diff --git a/mercurial/util.py b/mercurial/util.py --- a/mercurial/util.py +++ b/mercurial/util.py @@ -726,31 +726,31 @@ class atomictempfile(object): name, making the changes visible. """ def __init__(self, name, mode='w+b', createmode=None): - self.__name = name - self._fp = None - self.temp = mktempcopy(name, emptyok=('w' in mode), - createmode=createmode) - self._fp = posixfile(self.temp, mode) + self.__name = name # permanent name + self._tempname = mktempcopy(name, emptyok=('w' in mode), + createmode=createmode) + self._fp = posixfile(self._tempname, mode) - def __getattr__(self, name): - return getattr(self._fp, name) + # delegated methods + self.write = self._fp.write + self.fileno = self._fp.fileno def rename(self): if not self._fp.closed: self._fp.close() - rename(self.temp, localpath(self.__name)) + rename(self._tempname, localpath(self.__name)) def close(self): - if not self._fp: - return if not self._fp.closed: try: - os.unlink(self.temp) - except: pass + os.unlink(self._tempname) + except OSError: + pass self._fp.close() def __del__(self): - self.close() + if hasattr(self, '_fp'): # constructor actually did something + self.close() def makedirs(name, mode=None): """recursive directory creation with parent mode inheritance""" diff --git a/tests/test-atomictempfile.py b/tests/test-atomictempfile.py new file mode 100644 --- /dev/null +++ b/tests/test-atomictempfile.py @@ -0,0 +1,49 @@ +import os +import glob +from mercurial.util import atomictempfile + +# basic usage +def test1_simple(): + if os.path.exists('foo'): + os.remove('foo') + file = atomictempfile('foo') + (dir, basename) = os.path.split(file._tempname) + assert not os.path.isfile('foo') + assert basename in glob.glob('.foo-*') + + file.write('argh\n') + file.rename() + + assert os.path.isfile('foo') + assert basename not in glob.glob('.foo-*') + print 'OK' + +# close() removes the temp file but does not make the write +# permanent -- essentially discards your work (WTF?!) +def test2_close(): + if os.path.exists('foo'): + os.remove('foo') + file = atomictempfile('foo') + (dir, basename) = os.path.split(file._tempname) + + file.write('yo\n') + file.close() + + assert not os.path.isfile('foo') + assert basename not in os.listdir('.') + print 'OK' + +# if a programmer screws up and passes bad args to atomictempfile, they +# get a plain ordinary TypeError, not infinite recursion +def test3_oops(): + try: + file = atomictempfile() + except TypeError: + print "OK" + else: + print "expected TypeError" + +if __name__ == '__main__': + test1_simple() + test2_close() + test3_oops() diff --git a/tests/test-atomictempfile.py.out b/tests/test-atomictempfile.py.out new file mode 100644 --- /dev/null +++ b/tests/test-atomictempfile.py.out @@ -0,0 +1,3 @@ +OK +OK +OK