Mercurial > hg > cc > cirrus_home
diff lib/python/lock.py @ 87:b6a5999d8e06
working with locking and copying
author | Henry S. Thompson <ht@inf.ed.ac.uk> |
---|---|
date | Tue, 16 Mar 2021 16:20:02 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lib/python/lock.py Tue Mar 16 16:20:02 2021 +0000 @@ -0,0 +1,34 @@ +# Courtesy of https://stackoverflow.com/a/46407326 +import fcntl, os +def lock_file(f): + if f.writable(): fcntl.lockf(f, fcntl.LOCK_EX) +def unlock_file(f): + if f.writable(): fcntl.lockf(f, fcntl.LOCK_UN) + +# Class for ensuring that all file operations are atomic, treat +# initialization like a standard call to 'open' that happens to be atomic. +# This file opener *must* be used in a "with" block. +class AtomicOpen: + # Open the file with arguments provided by user. Then acquire + # a lock on that file object (WARNING: Advisory locking). + def __init__(self, path, *args, **kwargs): + # Open the file and acquire a lock on the file before operating + self.file = open(path,*args, **kwargs) + # Lock the opened file + lock_file(self.file) + + # Return the opened file object (knowing a lock has been obtained). + def __enter__(self, *args, **kwargs): return self.file + + # Unlock the file and close the file object. + def __exit__(self, exc_type=None, exc_value=None, traceback=None): + # Flush to make sure all buffered contents are written to file. + self.file.flush() + os.fsync(self.file.fileno()) + # Release the lock on the file. + unlock_file(self.file) + self.file.close() + # Handle exceptions that may have come up during execution, by + # default any exceptions are raised to the user. + if (exc_type != None): return False + else: return True