from ctypes import sizeof, c_void_p
from os import environ
+from contextlib import contextmanager
import sys, os, pwd, subprocess, errno, socket, select, mmap, stat, re, struct
-import hashlib, heapq, operator, time, grp
+import hashlib, heapq, operator, time, grp, tempfile
from bup import _helpers
import bup._helpers as _helpers
try:
os.unlink(f)
except OSError, e:
- if e.errno == errno.ENOENT:
- pass # it doesn't exist, that's what you asked for
+ if e.errno != errno.ENOENT:
+ raise
def readpipe(argv, preexec_fn=None):
yield b
+@contextmanager
+def atomically_replaced_file(name, mode='w', buffering=-1):
+ """Yield a file that will be atomically renamed name when leaving the block.
+
+ This contextmanager yields an open file object that is backed by a
+ temporary file which will be renamed (atomically) to the target
+ name if everything succeeds.
+
+ The mode and buffering arguments are handled exactly as with open,
+ and the yielded file will have very restrictive permissions, as
+ per mkstemp.
+
+ E.g.::
+
+ with atomically_replaced_file('foo.txt', 'w') as f:
+ f.write('hello jack.')
+
+ """
+
+ (ffd, tempname) = tempfile.mkstemp(dir=os.path.dirname(name),
+ text=('b' not in mode))
+ try:
+ try:
+ f = os.fdopen(ffd, mode, buffering)
+ except:
+ os.close(ffd)
+ raise
+ try:
+ yield f
+ finally:
+ f.close()
+ os.rename(tempname, name)
+ finally:
+ unlink(tempname) # nonexistant file is ignored
+
+
def slashappend(s):
"""Append "/" to 's' if it doesn't aleady end in "/"."""
if s and not s.endswith('/'):
except IOError, e:
raise fatal("couldn't read %s" % parameter)
for exclude_path in f.readlines():
- excluded_paths.append(realpath(exclude_path.strip()))
+ # FIXME: perhaps this should be rstrip('\n')
+ exclude_path = realpath(exclude_path.strip())
+ if exclude_path:
+ excluded_paths.append(exclude_path)
return sorted(frozenset(excluded_paths))
raise fatal("couldn't read %s" % parameter)
for pattern in f.readlines():
spattern = pattern.rstrip('\n')
+ if not spattern:
+ continue
try:
excluded_patterns.append(re.compile(spattern))
except re.error, ex: