summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWill McGugan <will@willmcgugan.com>2015-04-19 12:46:53 +0100
committerWill McGugan <will@willmcgugan.com>2015-04-19 12:46:53 +0100
commit7731df71a7b68c7a8ff181326bf84dd71b7c8a14 (patch)
tree8440fb2ee22f62627083163d29198368f77c5823
parent29b519fb3ebead760cedb784e244d3fbaf6981ff (diff)
downloadpyfilesystem-git-7731df71a7b68c7a8ff181326bf84dd71b7c8a14.tar.gz
added open_atomic_write
-rw-r--r--fs/utils.py44
1 files changed, 43 insertions, 1 deletions
diff --git a/fs/utils.py b/fs/utils.py
index 8fd6254..208fc61 100644
--- a/fs/utils.py
+++ b/fs/utils.py
@@ -16,8 +16,10 @@ __all__ = ['copyfile',
'isfile',
'isdir',
'find_duplicates',
- 'print_fs']
+ 'print_fs',
+ 'open_atomic_write']
+import os
import sys
import stat
import six
@@ -628,6 +630,46 @@ def print_fs(fs,
return dircount[0], filecount[0]
+class AtomicWriter(object):
+ """Context manager to perform atomic writes"""
+
+ def __init__(self, fs, path, mode='w'):
+ self.fs = fs
+ self.path = path
+ self.mode = mode
+ self.tmp_path = path + '~'
+ self._f = None
+
+ def __enter__(self):
+ self._f = self.fs.open(self.tmp_path, self.mode)
+ return self._f
+
+ def __exit__(self, exc_type, exc_value, traceback):
+ if exc_type is None:
+ if self._f is not None:
+ if hasattr('_f', 'flush'):
+ self._f.flush()
+ if hasattr(self._f, 'fileno'):
+ os.fsync(self._f.fileno())
+ self._f.close()
+ self._f = None
+ self.fs.rename(self.tmp_path, self.path)
+ else:
+ if self._f is not None:
+ self._f.close()
+
+
+def open_atomic_write(fs, path, mode='w'):
+ """Open a file for 'atomic' writing
+
+ This returns a context manager which ensures that a file is written in its entirety or not at all.
+
+ """
+ return AtomicWriter(fs, path, mode=mode)
+
+
+
+
if __name__ == "__main__":
from fs.tempfs import TempFS
from six import b