# HG changeset patch # User Henrik Stuart # Date 1241443917 -7200 # Node ID 48a382c23226736ee2023a23ff17fe8a51b500fa # Parent f00573bc93f88543ece887981b9a40fc846b0d41 transaction: refactor transaction.abort and rollback to use the same code This adds a change to the way that abort is processed, as it will not continue truncating files beyond the first failure, otherwise the respective functionality is maintained, i.e. abort will not unlink files, but rollback will. Co-contributor: Sune Foldager diff -r f00573bc93f8 -r 48a382c23226 mercurial/localrepo.py --- a/mercurial/localrepo.py Mon May 04 13:47:12 2009 +0200 +++ b/mercurial/localrepo.py Mon May 04 15:31:57 2009 +0200 @@ -624,7 +624,7 @@ try: if os.path.exists(self.sjoin("journal")): self.ui.status(_("rolling back interrupted transaction\n")) - transaction.rollback(self.sopener, self.sjoin("journal")) + transaction.rollback(self.sopener, self.sjoin("journal"), self.ui.warn) self.invalidate() return True else: @@ -640,7 +640,7 @@ lock = self.lock() if os.path.exists(self.sjoin("undo")): self.ui.status(_("rolling back last transaction\n")) - transaction.rollback(self.sopener, self.sjoin("undo")) + transaction.rollback(self.sopener, self.sjoin("undo"), self.ui.warn) util.rename(self.join("undo.dirstate"), self.join("dirstate")) try: branch = self.opener("undo.branch").read() diff -r f00573bc93f8 -r 48a382c23226 mercurial/transaction.py --- a/mercurial/transaction.py Mon May 04 13:47:12 2009 +0200 +++ b/mercurial/transaction.py Mon May 04 15:31:57 2009 +0200 @@ -23,6 +23,23 @@ return func(self, *args, **kwds) return _active +def _playback(journal, report, opener, entries, unlink=True): + for f, o, ignore in entries: + if o or not unlink: + try: + opener(f, 'a').truncate(o) + except: + report(_("failed to truncate %s\n") % f) + raise + else: + try: + fn = opener(f).name + os.unlink(fn) + except OSError, inst: + if inst.errno != errno.ENOENT: + raise + os.unlink(journal) + class transaction(object): def __init__(self, report, opener, journal, after=None, createmode=None): self.journal = None @@ -101,40 +118,21 @@ self.report(_("transaction abort!\n")) - failed = False - for f, o, ignore in self.entries: + try: try: - self.opener(f, "a").truncate(o) + _playback(self.journal, self.report, self.opener, self.entries, False) + self.report(_("rollback completed\n")) except: - failed = True - self.report(_("failed to truncate %s\n") % f) - - self.entries = [] - - if not failed: - os.unlink(self.journal) - self.report(_("rollback completed\n")) - else: - self.report(_("rollback failed - please run hg recover\n")) - - self.journal = None + self.report(_("rollback failed - please run hg recover\n")) + finally: + self.journal = None -def rollback(opener, file): - files = {} +def rollback(opener, file, report): + entries = [] + for l in open(file).readlines(): f, o = l.split('\0') - files[f] = int(o) - for f in files: - o = files[f] - if o: - opener(f, "a").truncate(int(o)) - else: - try: - fn = opener(f).name - os.unlink(fn) - except OSError, inst: - if inst.errno != errno.ENOENT: - raise - os.unlink(file) + entries.append((f, int(o), None)) + _playback(file, report, opener, entries) diff -r f00573bc93f8 -r 48a382c23226 tests/test-repair-strip.out --- a/tests/test-repair-strip.out Mon May 04 13:47:12 2009 +0200 +++ b/tests/test-repair-strip.out Mon May 04 15:31:57 2009 +0200 @@ -17,8 +17,9 @@ b@?: rev 1 points to nonexistent changeset 2 (expected 1) b@?: 736c29771fba not in manifests +warning: orphan revlog 'data/c.i' 2 files, 2 changesets, 3 total revisions -1 warnings encountered! +2 warnings encountered! 2 integrity errors encountered! % journal contents 00changelog.i @@ -63,15 +64,15 @@ manifest@?: rev 2 points to nonexistent changeset 2 manifest@?: rev 3 points to nonexistent changeset 3 crosschecking files in changesets and manifests - c@?: in manifest but not in changeset + c@3: in manifest but not in changeset checking files - b@2: 736c29771fba in manifests not found - data/c.i@?: missing revlog! - ?: empty or missing c - c@3: 149da44f2a4e in manifests not found -3 files, 2 changesets, 2 total revisions -7 integrity errors encountered! -(first damaged changeset appears to be 2) + b@?: rev 1 points to nonexistent changeset 2 + (expected 1) + c@?: rev 0 points to nonexistent changeset 3 +3 files, 2 changesets, 4 total revisions +1 warnings encountered! +5 integrity errors encountered! +(first damaged changeset appears to be 3) % journal contents 00changelog.i 00manifest.i