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 <cryo@cyanite.org>
--- 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()
--- 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)
--- 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