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