Files @ 6d9b3ade3051
Branch filter:

Location: kallithea/rhodecode/lib/vcs/utils/lockfiles.py - annotation

Zachary Auclair
Allowing multiple issue servers to be autolinked in the changeset view;
linking is now contingent on issue_server_link, issue_pat and issue_prefix
being defined; multiple servers can be used by specifying a common suffix on all
the above variables, ie ..

issue_server_link_1
issue_pat_1
issue_prefix_1

.. and ..

issue_server_link_other
issue_pat_other
issue_prefix_other

.. would be treated as two distinct servers, but ..

issue_pat_thing

.. would be ignored (since the other two requisite vars aren't present).

This patch is backwards compatible with existing variables (as a suffix
isn't needed).
import os


class LockFile(object):
	"""Provides methods to obtain, check for, and release a file based lock which
	should be used to handle concurrent access to the same file.

	As we are a utility class to be derived from, we only use protected methods.

	Locks will automatically be released on destruction"""
	__slots__ = ("_file_path", "_owns_lock")

	def __init__(self, file_path):
		self._file_path = file_path
		self._owns_lock = False

	def __del__(self):
		self._release_lock()

	def _lock_file_path(self):
		""":return: Path to lockfile"""
		return "%s.lock" % (self._file_path)

	def _has_lock(self):
		""":return: True if we have a lock and if the lockfile still exists
		:raise AssertionError: if our lock-file does not exist"""
		if not self._owns_lock:
			return False

		return True

	def _obtain_lock_or_raise(self):
		"""Create a lock file as flag for other instances, mark our instance as lock-holder

		:raise IOError: if a lock was already present or a lock file could not be written"""
		if self._has_lock():
			return
		lock_file = self._lock_file_path()
		if os.path.isfile(lock_file):
			raise IOError("Lock for file %r did already exist, delete %r in case the lock is illegal" % (self._file_path, lock_file))

		try:
			fd = os.open(lock_file, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0)
			os.close(fd)
		except OSError,e:
			raise IOError(str(e))

		self._owns_lock = True

	def _obtain_lock(self):
		"""The default implementation will raise if a lock cannot be obtained.
		Subclasses may override this method to provide a different implementation"""
		return self._obtain_lock_or_raise()

	def _release_lock(self):
		"""Release our lock if we have one"""
		if not self._has_lock():
			return

		# if someone removed our file beforhand, lets just flag this issue
		# instead of failing, to make it more usable.
		lfp = self._lock_file_path()
		try:
			# on bloody windows, the file needs write permissions to be removable.
			# Why ...
			if os.name == 'nt':
				os.chmod(lfp, 0777)
			# END handle win32
			os.remove(lfp)
		except OSError:
			pass
		self._owns_lock = False