comparison mercurial/localrepo.py @ 14266:89e7d35e0ef0 stable

fix bookmarks rollback behavior Before this patch undo.bookmarks was created on bookmarks write and not with other transaction-related files. There were two issues: first is that if you have changed bookmarks few times after a transaction happened, rollback will give you a state which can point to non-existing revision. Second is that if you have not changed bookmarks after a transaction, rollback will touch your state anyway. This change also adds `localrepo._writejournal` method, which can be used by other extensions to save their transaction-related backup in right time.
author Alexander Solovyov <alexander@solovyov.net>
date Sun, 01 May 2011 13:07:00 +0200
parents 044e1356327d
children a55a0045704c 4d958d1bb072
comparison
equal deleted inserted replaced
14211:b00ab6890fe9 14266:89e7d35e0ef0
667 # abort here if the journal already exists 667 # abort here if the journal already exists
668 if os.path.exists(self.sjoin("journal")): 668 if os.path.exists(self.sjoin("journal")):
669 raise error.RepoError( 669 raise error.RepoError(
670 _("abandoned transaction found - run hg recover")) 670 _("abandoned transaction found - run hg recover"))
671 671
672 journalfiles = self._writejournal(desc)
673 renames = [(x, undoname(x)) for x in journalfiles]
674
675 tr = transaction.transaction(self.ui.warn, self.sopener,
676 self.sjoin("journal"),
677 aftertrans(renames),
678 self.store.createmode)
679 self._transref = weakref.ref(tr)
680 return tr
681
682 def _writejournal(self, desc):
672 # save dirstate for rollback 683 # save dirstate for rollback
673 try: 684 try:
674 ds = self.opener("dirstate").read() 685 ds = self.opener("dirstate").read()
675 except IOError: 686 except IOError:
676 ds = "" 687 ds = ""
677 self.opener("journal.dirstate", "w").write(ds) 688 self.opener("journal.dirstate", "w").write(ds)
678 self.opener("journal.branch", "w").write( 689 self.opener("journal.branch", "w").write(
679 encoding.fromlocal(self.dirstate.branch())) 690 encoding.fromlocal(self.dirstate.branch()))
680 self.opener("journal.desc", "w").write("%d\n%s\n" % (len(self), desc)) 691 self.opener("journal.desc", "w").write("%d\n%s\n" % (len(self), desc))
681 692
682 renames = [(self.sjoin("journal"), self.sjoin("undo")), 693 bkname = self.join('bookmarks')
683 (self.join("journal.dirstate"), self.join("undo.dirstate")), 694 if os.path.exists(bkname):
684 (self.join("journal.branch"), self.join("undo.branch")), 695 util.copyfile(bkname, self.join('journal.bookmarks'))
685 (self.join("journal.desc"), self.join("undo.desc"))] 696 else:
686 tr = transaction.transaction(self.ui.warn, self.sopener, 697 self.opener('journal.bookmarks', 'w').write('')
687 self.sjoin("journal"), 698
688 aftertrans(renames), 699 return (self.sjoin('journal'), self.join('journal.dirstate'),
689 self.store.createmode) 700 self.join('journal.branch'), self.join('journal.desc'),
690 self._transref = weakref.ref(tr) 701 self.join('journal.bookmarks'))
691 return tr
692 702
693 def recover(self): 703 def recover(self):
694 lock = self.lock() 704 lock = self.lock()
695 try: 705 try:
696 if os.path.exists(self.sjoin("journal")): 706 if os.path.exists(self.sjoin("journal")):
2025 def a(): 2035 def a():
2026 for src, dest in renamefiles: 2036 for src, dest in renamefiles:
2027 util.rename(src, dest) 2037 util.rename(src, dest)
2028 return a 2038 return a
2029 2039
2040 def undoname(fn):
2041 base, name = os.path.split(fn)
2042 assert name.startswith('journal')
2043 return os.path.join(base, name.replace('journal', 'undo', 1))
2044
2030 def instance(ui, path, create): 2045 def instance(ui, path, create):
2031 return localrepository(ui, util.drop_scheme('file', path), create) 2046 return localrepository(ui, util.drop_scheme('file', path), create)
2032 2047
2033 def islocal(path): 2048 def islocal(path):
2034 return True 2049 return True