transactions: fix hg recover with fncache backups
The transaction backupfiles logic was broken for 'hg recover'. The file format
is XXX\0XXX\0YYY\0YYY\0 but the parser did a couple things wrong. 1) It went one
step beyond the final \0 and tried to read past the end of the array. 2)
array[i:i+1] returns a single item, instead of two items as intended.
Added a test to catch it, which turns out to be the first actual 'hg recover'
test.
--- a/mercurial/transaction.py Sun Oct 19 16:48:33 2014 +0900
+++ b/mercurial/transaction.py Mon Oct 20 16:53:56 2014 -0700
@@ -349,8 +349,9 @@
data = fp.read()
if len(data) > 0:
parts = data.split('\0')
- for i in xrange(0, len(parts), 2):
- f, b = parts[i:i + 1]
+ # Skip the final part, since it's just a trailing empty space
+ for i in xrange(0, len(parts) - 1, 2):
+ f, b = parts[i:i + 2]
backupentries.append((f, b, None))
_playback(file, report, opener, entries, backupentries)
--- a/tests/test-fncache.t Sun Oct 19 16:48:33 2014 +0900
+++ b/tests/test-fncache.t Mon Oct 20 16:53:56 2014 -0700
@@ -236,3 +236,46 @@
[255]
$ cat .hg/store/fncache
data/y.i
+
+Aborted transactions can be recovered later
+
+ $ cat > ../exceptionext.py <<EOF
+ > import os
+ > from mercurial import commands, util, transaction
+ > from mercurial.extensions import wrapfunction
+ >
+ > def closewrapper(orig, self, *args, **kwargs):
+ > origonclose = self.onclose
+ > def onclose():
+ > origonclose()
+ > raise util.Abort("forced transaction failure")
+ > self.onclose = onclose
+ > return orig(self, *args, **kwargs)
+ >
+ > def abortwrapper(orig, self, *args, **kwargs):
+ > raise util.Abort("forced transaction failure")
+ >
+ > def uisetup(ui):
+ > wrapfunction(transaction.transaction, 'close', closewrapper)
+ > wrapfunction(transaction.transaction, '_abort', abortwrapper)
+ >
+ > cmdtable = {}
+ >
+ > EOF
+ $ rm -f "${extpath}c"
+ $ hg up -q 1
+ $ touch z
+ $ hg ci -qAm z 2>/dev/null
+ [255]
+ $ cat .hg/store/fncache | sort
+ data/y.i
+ data/z.i
+ $ hg recover
+ rolling back interrupted transaction
+ checking changesets
+ checking manifests
+ crosschecking files in changesets and manifests
+ checking files
+ 1 files, 1 changesets, 1 total revisions
+ $ cat .hg/store/fncache
+ data/y.i