import signal
import httplib
import urllib
+import time
+import logging
import wizard
"""
Context for locking a directory.
"""
- def __init__(self, lockfile):
+ def __init__(self, lockfile, expiry = 3600):
self.lockfile = lockfile
+ self.expiry = expiry # by default an hour
def __enter__(self):
- try:
- os.open(self.lockfile, os.O_CREAT | os.O_EXCL)
- except OSError as e:
- if e.errno == errno.EEXIST:
- raise DirectoryLockedError(os.getcwd())
- elif e.errno == errno.EACCES:
- raise PermissionsError(os.getcwd())
- raise
+ # It's A WAVY
+ for i in range(0, 3):
+ try:
+ os.open(self.lockfile, os.O_CREAT | os.O_EXCL)
+ open(self.lockfile, "w").write("%d" % os.getpid())
+ except OSError as e:
+ if e.errno == errno.EEXIST:
+ # There is a possibility of infinite recursion, but we
+ # expect it to be unlikely, and not harmful if it does happen
+ with LockDirectory(self.lockfile + "_"):
+ # See if we can break the lock
+ try:
+ pid = open(self.lockfile, "r").read().strip()
+ if not os.path.exists("/proc/%s" % pid):
+ # break the lock, try again
+ logging.warning("Breaking orphaned lock at %s", self.lockfile)
+ os.unlink(self.lockfile)
+ continue
+ try:
+ # check if the file is expiry old, if so, break the lock, try again
+ if time.time() - os.stat(self.lockfile).st_mtime > self.expiry:
+ logging.warning("Breaking stale lock at %s", self.lockfile)
+ os.unlink(self.lockfile)
+ continue
+ except OSError as e:
+ if e.errno == errno.ENOENT:
+ continue
+ raise
+ except IOError:
+ # oh hey, it went away; try again
+ continue
+ raise DirectoryLockedError(os.getcwd())
+ elif e.errno == errno.EACCES:
+ raise PermissionsError(os.getcwd())
+ raise
+ return
+ raise DirectoryLockedError(os.getcwd())
def __exit__(self, *args):
try:
os.unlink(self.lockfile)