]> scripts.mit.edu Git - wizard.git/blobdiff - wizard/util.py
Update TODO.
[wizard.git] / wizard / util.py
index 174c13f161ed7524c4299fa7c5c0a59cb32eb240..a6e8f243dabf48a8792b442f51e75183ef4698c9 100644 (file)
@@ -17,6 +17,8 @@ import itertools
 import signal
 import httplib
 import urllib
+import time
+import logging
 
 import wizard
 
@@ -96,17 +98,47 @@ class LockDirectory(object):
     """
     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)