Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/util.py @ 15057:774da7121fc9
atomictempfile: make close() consistent with other file-like objects.
The usual contract is that close() makes your writes permanent, so
atomictempfile's use of close() to *discard* writes (and rename() to
keep them) is rather unexpected. Thus, change it so close() makes
things permanent and add a new discard() method to throw them away.
discard() is only used internally, in __del__(), to ensure that writes
are discarded when an atomictempfile object goes out of scope.
I audited mercurial.*, hgext.*, and ~80 third-party extensions, and
found no one using the existing semantics of close() to discard
writes, so this should be safe.
author | Greg Ward <greg@gerg.ca> |
---|---|
date | Thu, 25 Aug 2011 20:21:04 -0400 |
parents | ff3e93686306 |
children | 81f33be0ea79 |
comparison
equal
deleted
inserted
replaced
15056:8413916df816 | 15057:774da7121fc9 |
---|---|
743 | 743 |
744 class atomictempfile(object): | 744 class atomictempfile(object): |
745 '''writeable file object that atomically updates a file | 745 '''writeable file object that atomically updates a file |
746 | 746 |
747 All writes will go to a temporary copy of the original file. Call | 747 All writes will go to a temporary copy of the original file. Call |
748 rename() when you are done writing, and atomictempfile will rename | 748 close() when you are done writing, and atomictempfile will rename |
749 the temporary copy to the original name, making the changes visible. | 749 the temporary copy to the original name, making the changes |
750 | 750 visible. If the object is destroyed without being closed, all your |
751 Unlike other file-like objects, close() discards your writes by | 751 writes are discarded. |
752 simply deleting the temporary file. | |
753 ''' | 752 ''' |
754 def __init__(self, name, mode='w+b', createmode=None): | 753 def __init__(self, name, mode='w+b', createmode=None): |
755 self.__name = name # permanent name | 754 self.__name = name # permanent name |
756 self._tempname = mktempcopy(name, emptyok=('w' in mode), | 755 self._tempname = mktempcopy(name, emptyok=('w' in mode), |
757 createmode=createmode) | 756 createmode=createmode) |
759 | 758 |
760 # delegated methods | 759 # delegated methods |
761 self.write = self._fp.write | 760 self.write = self._fp.write |
762 self.fileno = self._fp.fileno | 761 self.fileno = self._fp.fileno |
763 | 762 |
764 def rename(self): | 763 def close(self): |
765 if not self._fp.closed: | 764 if not self._fp.closed: |
766 self._fp.close() | 765 self._fp.close() |
767 rename(self._tempname, localpath(self.__name)) | 766 rename(self._tempname, localpath(self.__name)) |
768 | 767 |
769 def close(self): | 768 def discard(self): |
770 if not self._fp.closed: | 769 if not self._fp.closed: |
771 try: | 770 try: |
772 os.unlink(self._tempname) | 771 os.unlink(self._tempname) |
773 except OSError: | 772 except OSError: |
774 pass | 773 pass |
775 self._fp.close() | 774 self._fp.close() |
776 | 775 |
777 def __del__(self): | 776 def __del__(self): |
778 if safehasattr(self, '_fp'): # constructor actually did something | 777 if safehasattr(self, '_fp'): # constructor actually did something |
779 self.close() | 778 self.discard() |
780 | 779 |
781 def makedirs(name, mode=None): | 780 def makedirs(name, mode=None): |
782 """recursive directory creation with parent mode inheritance""" | 781 """recursive directory creation with parent mode inheritance""" |
783 parent = os.path.abspath(os.path.dirname(name)) | 782 parent = os.path.abspath(os.path.dirname(name)) |
784 try: | 783 try: |