view rhodecode/lib/vcs/utils/lockfiles.py @ 2007:324ac367a4da beta

Added VCS into rhodecode core for faster and easier deployments of new versions
author Marcin Kuzminski <marcin@python-works.com>
date Mon, 20 Feb 2012 23:00:54 +0200
parents
children 95a226b35b91
line wrap: on
line source

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