# HG changeset patch # User Durham Goode # Date 2014-10-20 23:53:56 # Node ID cd86a6707159367e84373e6e901ba2409d8e5cf7 # Parent ba89f7b542c90b79bc677650df461b2f1fa675a8 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. diff --git a/mercurial/transaction.py b/mercurial/transaction.py --- a/mercurial/transaction.py +++ b/mercurial/transaction.py @@ -349,8 +349,9 @@ def rollback(opener, file, report): 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) diff --git a/tests/test-fncache.t b/tests/test-fncache.t --- a/tests/test-fncache.t +++ b/tests/test-fncache.t @@ -236,3 +236,46 @@ Aborting transaction prevents fncache ch [255] $ cat .hg/store/fncache data/y.i + +Aborted transactions can be recovered later + + $ cat > ../exceptionext.py < 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