X-Git-Url: https://git.kaliko.me/?a=blobdiff_plain;f=sima%2Flib%2Fhttpcli%2Ffilelock.py;fp=sima%2Flib%2Fhttpcli%2Ffilelock.py;h=6dc331be75a3828d080bf1a543ce230c15d202d5;hb=bed2018b162e3493dd5a5a7fe5433af2005a7d0a;hp=0000000000000000000000000000000000000000;hpb=3ee55407f08ca20a37ca008822283682d2ba58f9;p=mpd-sima.git diff --git a/sima/lib/httpcli/filelock.py b/sima/lib/httpcli/filelock.py new file mode 100644 index 0000000..6dc331b --- /dev/null +++ b/sima/lib/httpcli/filelock.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +# https://github.com/dmfrey/FileLock + +import os +import time +import errno + +class FileLockException(Exception): + pass + +class FileLock: + """ A file locking mechanism that has context-manager support so + you can use it in a with statement. This should be relatively cross + compatible as it doesn't rely on msvcrt or fcntl for the locking. + """ + + def __init__(self, file_name, timeout=10, delay=.05): + """ Prepare the file locker. Specify the file to lock and optionally + the maximum timeout and the delay between each attempt to lock. + """ + self.is_locked = False + self.lockfile = os.path.join(os.getcwd(), "%s.lock" % file_name) + self.file_name = file_name + self.timeout = timeout + self.delay = delay + + + def acquire(self): + """ Acquire the lock, if possible. If the lock is in use, it check again + every `wait` seconds. It does this until it either gets the lock or + exceeds `timeout` number of seconds, in which case it throws + an exception. + """ + start_time = time.time() + while True: + try: + self.fd = os.open(self.lockfile, os.O_CREAT|os.O_EXCL|os.O_RDWR) + break; + except OSError as e: + if e.errno != errno.EEXIST: + raise + if (time.time() - start_time) >= self.timeout: + raise FileLockException("Timeout occured.") + time.sleep(self.delay) + self.is_locked = True + + + def release(self): + """ Get rid of the lock by deleting the lockfile. + When working in a `with` statement, this gets automatically + called at the end. + """ + if self.is_locked: + os.close(self.fd) + os.unlink(self.lockfile) + self.is_locked = False + + + def __enter__(self): + """ Activated when used in the with statement. + Should automatically acquire a lock to be used in the with block. + """ + if not self.is_locked: + self.acquire() + return self + + + def __exit__(self, type, value, traceback): + """ Activated at the end of the with statement. + It automatically releases the lock if it isn't locked. + """ + if self.is_locked: + self.release() + + + def __del__(self): + """ Make sure that the FileLock instance doesn't leave a lockfile + lying around. + """ + self.release()