24 Utilities for safe file IO
26 from contextlib
import contextmanager
40 """Make a directory in a manner avoiding race conditions"""
41 if directory !=
"" and not os.path.exists(directory):
43 os.makedirs(directory)
46 if e.errno != errno.EEXIST:
51 """Set a file mode according to the user's umask"""
53 umask = os.umask(0o077)
57 os.chmod(filename, (~umask & 0o666))
66 """Context manager to get a file that can be written only once and all other writes will succeed only if
67 they match the initial write.
69 The context manager provides a temporary file object. After the user is done, the temporary file becomes
70 the permanent file if the file at name does not already exist. If the file at name does exist the
71 temporary file is compared to the file at name. If they are the same then this is good and the temp file
72 is silently thrown away. If they are not the same then a runtime error is raised.
74 outDir, outName = os.path.split(name)
76 temp = tempfile.NamedTemporaryFile(mode=
"w", dir=outDir, prefix=outName, delete=
False)
84 os.symlink(temp.name, name)
87 os.rename(temp.name, name)
92 if e.errno != errno.EEXIST:
94 filesMatch = filecmp.cmp(temp.name, name, shallow=
False)
107 """Context manager to create a file in a manner avoiding race conditions
109 The context manager provides a temporary file object. After the user is done,
110 we move that file into the desired place and close the fd to avoid resource
113 outDir, outName = os.path.split(name)
116 with tempfile.NamedTemporaryFile(mode=
"w", dir=outDir, prefix=outName, delete=
False)
as temp:
123 os.rename(temp.name, name)
129 """Context manager for creating a file in a manner avoiding race conditions
131 The context manager provides a temporary filename with no open file descriptors
132 (as this can cause trouble on some systems). After the user is done, we move the
133 file into the desired place.
135 outDir, outName = os.path.split(name)
137 temp = tempfile.NamedTemporaryFile(mode=
"w", dir=outDir, prefix=outName, delete=
False)
143 os.rename(tempName, name)
149 """Context manager for reading a file that may be locked with an exclusive lock via
150 SafeLockedFileForWrite. This will first acquire a shared lock before returning the file. When the file is
151 closed the shared lock will be unlocked.
156 The file name to be opened, may include path.
161 The file to be read from.
163 log = Log.getLogger(
"daf.persistence.butler")
165 with open(name,
'r')
as f:
166 log.debug(
"Acquiring shared lock on {}".
format(name))
167 fcntl.flock(f, fcntl.LOCK_SH)
168 log.debug(
"Acquired shared lock on {}".
format(name))
171 log.debug(
"Releasing shared lock on {}".
format(name))
175 """File-like object that is used to create a file if needed, lock it with an exclusive lock, and contain
176 file descriptors to readable and writable versions of the file.
178 This will only open a file descriptor in 'write' mode if a write operation is performed. If no write
179 operation is performed, the existing file (if there is one) will not be overwritten.
181 Contains __enter__ and __exit__ functions so this can be used by a context manager.
184 self.
log = Log.getLogger(
"daf.persistence.butler")