diff options
author | Marko Kreen | 2012-06-18 14:26:02 +0000 |
---|---|---|
committer | Marko Kreen | 2012-06-18 14:26:02 +0000 |
commit | 4f7724a83634c5346347bee6d652cbf14a3f2c87 (patch) | |
tree | b27a3e951115536d7b42e65d69b3b96b129be6ca | |
parent | 651dd5f4578bde761cf4164f752b25aad09419df (diff) |
fileutil: write_atomic() for win32
win32 does not support atomic rename
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | python/skytools/fileutil.py | 67 |
2 files changed, 66 insertions, 3 deletions
@@ -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() + |