summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Kreen2012-06-18 14:26:02 +0000
committerMarko Kreen2012-06-18 14:26:02 +0000
commit4f7724a83634c5346347bee6d652cbf14a3f2c87 (patch)
treeb27a3e951115536d7b42e65d69b3b96b129be6ca
parent651dd5f4578bde761cf4164f752b25aad09419df (diff)
fileutil: write_atomic() for win32
win32 does not support atomic rename
-rw-r--r--Makefile2
-rw-r--r--python/skytools/fileutil.py67
2 files changed, 66 insertions, 3 deletions
diff --git a/Makefile b/Makefile
index 911b926f..01fa7242 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ SUBDIRS = sql doc
# modules that use doctest for regtests
DOCTESTMODS = skytools.quoting skytools.parsing skytools.timeutil \
skytools.sqltools skytools.querybuilder skytools.natsort \
- skytools.utf8 skytools.sockutil
+ skytools.utf8 skytools.sockutil skytools.fileutil
all: python-all sub-all config.mak
diff --git a/python/skytools/fileutil.py b/python/skytools/fileutil.py
index c6fcefdd..a88ce88d 100644
--- a/python/skytools/fileutil.py
+++ b/python/skytools/fileutil.py
@@ -1,9 +1,22 @@
-"""File utilities"""
-
+"""File utilities
+
+>>> import tempfile, os
+>>> pidfn = tempfile.mktemp('.pid')
+>>> write_atomic(pidfn, "1")
+>>> write_atomic(pidfn, "2")
+>>> os.remove(pidfn)
+>>> write_atomic(pidfn, "1", '.bak')
+>>> write_atomic(pidfn, "2", '.bak')
+>>> os.remove(pidfn)
+"""
+
+import sys
import os
+import errno
__all__ = ['write_atomic', 'signal_pidfile']
+# non-win32
def write_atomic(fn, data, bakext=None, mode='b'):
"""Write file with rename."""
@@ -32,6 +45,13 @@ def write_atomic(fn, data, bakext=None, mode='b'):
if e.errno != errno.ENOENT:
raise
+ # win32 does not like replace
+ if sys.platform == 'win32':
+ try:
+ os.remove(fn)
+ except:
+ pass
+
# atomically replace file
os.rename(fn2, fn)
@@ -100,3 +120,46 @@ def win32_detect_pid(pid):
k.CloseHandle(h)
return code.value == STILL_ACTIVE
+def win32_write_atomic(fn, data, bakext=None, mode='b'):
+ """Write file with rename for win32."""
+
+ if mode not in ['', 'b', 't']:
+ raise ValueError("unsupported fopen mode")
+
+ # write new data to tmp file
+ fn2 = fn + '.new'
+ f = open(fn2, 'w' + mode)
+ f.write(data)
+ f.close()
+
+ # move old data to bak file
+ if bakext:
+ if bakext.find('/') >= 0:
+ raise ValueError("invalid bakext")
+ fnb = fn + bakext
+ try:
+ os.remove(fnb)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ try:
+ os.rename(fn, fnb)
+ except OSError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ else:
+ try:
+ os.remove(fn)
+ except:
+ pass
+
+ # replace file
+ os.rename(fn2, fn)
+
+if sys.platform == 'win32':
+ write_atomic = win32_write_atomic
+
+if __name__ == '__main__':
+ import doctest
+ doctest.testmod()
+