# HG changeset patch # User Henrik Stuart # Date 2009-05-04 13:31:57 # 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 --git a/mercurial/localrepo.py b/mercurial/localrepo.py --- a/mercurial/localrepo.py +++ b/mercurial/localrepo.py @@ -624,7 +624,7 @@ class localrepository(repo.repository): 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 @@ class localrepository(repo.repository): 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 --git a/mercurial/transaction.py b/mercurial/transaction.py --- a/mercurial/transaction.py +++ b/mercurial/transaction.py @@ -23,6 +23,23 @@ def active(func): 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 @@ class transaction(object): 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 --git a/tests/test-repair-strip.out b/tests/test-repair-strip.out --- a/tests/test-repair-strip.out +++ b/tests/test-repair-strip.out @@ -17,8 +17,9 @@ checking files 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 @@ checking manifests 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