Mercurial > hg
view tests/test-fncache.t @ 29021:92d37fb3f1aa stable
verify: don't init subrepo when missing one is referenced (issue5128) (API)
Initializing a subrepo when one doesn't exist is the right thing to do when the
parent is being updated, but in few other cases. Unfortunately, there isn't
enough context in the subrepo module to distinguish this case. This same issue
can be caused with other subrepo aware commands, so there is a general issue
here beyond the scope of this fix.
A simpler attempt I tried was to add an '_updating' boolean to localrepo, and
set/clear it around the call to mergemod.update() in hg.updaterepo(). That
mostly worked, but doesn't handle the case where archive will clone the subrepo
if it is missing. (I vaguely recall that there may be other commands that will
clone if needed like this, but certainly not all do. It seems both handy, and a
bit surprising for what should be a read only operation. It might be nice if
all commands did this consistently, but we probably need Angel's subrepo caching
first, to not make a mess of the working directory.)
I originally handled 'Exception' in order to pick up the Aborts raised in
subrepo.state(), but this turns out to be unnecessary because that is called
once and cached by ctx.sub() when iterating the subrepos.
It was suggested in the bug discussion to skip looking at the subrepo links
unless -S is specified. I don't really like that idea because missing a subrepo
or (less likely, but worse) a corrupt .hgsubstate is a problem of the parent
repo when checking out a revision. The -S option seems like a better fit for
functionality that would recurse into each subrepo and do a full verification.
Ultimately, the default value for 'allowcreate' should probably be flipped, but
since the default behavior was to allow creation, this is less risky for now.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Wed, 27 Apr 2016 22:45:52 -0400 |
parents | a01d3d32b53a |
children | 1bdafe1111ce |
line wrap: on
line source
Init repo1: $ hg init repo1 $ cd repo1 $ echo "some text" > a $ hg add adding a $ hg ci -m first $ cat .hg/store/fncache | sort data/a.i Testing a.i/b: $ mkdir a.i $ echo "some other text" > a.i/b $ hg add adding a.i/b (glob) $ hg ci -m second $ cat .hg/store/fncache | sort data/a.i data/a.i.hg/b.i Testing a.i.hg/c: $ mkdir a.i.hg $ echo "yet another text" > a.i.hg/c $ hg add adding a.i.hg/c (glob) $ hg ci -m third $ cat .hg/store/fncache | sort data/a.i data/a.i.hg.hg/c.i data/a.i.hg/b.i Testing verify: $ hg verify checking changesets checking manifests crosschecking files in changesets and manifests checking files 3 files, 3 changesets, 3 total revisions $ rm .hg/store/fncache $ hg verify checking changesets checking manifests crosschecking files in changesets and manifests checking files warning: revlog 'data/a.i' not in fncache! warning: revlog 'data/a.i.hg/c.i' not in fncache! warning: revlog 'data/a.i/b.i' not in fncache! 3 files, 3 changesets, 3 total revisions 3 warnings encountered! hint: run "hg debugrebuildfncache" to recover from corrupt fncache Follow the hint to make sure it works $ hg debugrebuildfncache adding data/a.i adding data/a.i.hg/c.i adding data/a.i/b.i 3 items added, 0 removed from fncache $ hg verify checking changesets checking manifests crosschecking files in changesets and manifests checking files 3 files, 3 changesets, 3 total revisions $ cd .. Non store repo: $ hg --config format.usestore=False init foo $ cd foo $ mkdir tst.d $ echo foo > tst.d/foo $ hg ci -Amfoo adding tst.d/foo $ find .hg | sort .hg .hg/00changelog.i .hg/00manifest.i .hg/cache .hg/cache/branch2-served .hg/cache/rbc-names-v1 .hg/cache/rbc-revs-v1 .hg/data .hg/data/tst.d.hg .hg/data/tst.d.hg/foo.i .hg/dirstate .hg/last-message.txt .hg/phaseroots .hg/requires .hg/undo .hg/undo.backup.dirstate .hg/undo.backupfiles .hg/undo.bookmarks .hg/undo.branch .hg/undo.desc .hg/undo.dirstate .hg/undo.phaseroots $ cd .. Non fncache repo: $ hg --config format.usefncache=False init bar $ cd bar $ mkdir tst.d $ echo foo > tst.d/Foo $ hg ci -Amfoo adding tst.d/Foo $ find .hg | sort .hg .hg/00changelog.i .hg/cache .hg/cache/branch2-served .hg/cache/rbc-names-v1 .hg/cache/rbc-revs-v1 .hg/dirstate .hg/last-message.txt .hg/requires .hg/store .hg/store/00changelog.i .hg/store/00manifest.i .hg/store/data .hg/store/data/tst.d.hg .hg/store/data/tst.d.hg/_foo.i .hg/store/phaseroots .hg/store/undo .hg/store/undo.backupfiles .hg/store/undo.phaseroots .hg/undo.backup.dirstate .hg/undo.bookmarks .hg/undo.branch .hg/undo.desc .hg/undo.dirstate $ cd .. Encoding of reserved / long paths in the store $ hg init r2 $ cd r2 $ cat <<EOF > .hg/hgrc > [ui] > portablefilenames = ignore > EOF $ hg import -q --bypass - <<EOF > # HG changeset patch > # User test > # Date 0 0 > # Node ID 1c7a2f7cb77be1a0def34e4c7cabc562ad98fbd7 > # Parent 0000000000000000000000000000000000000000 > 1 > > diff --git a/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz > new file mode 100644 > --- /dev/null > +++ b/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxxxxx-xxxxxxxxx-xxxxxxxxx-123456789-12.3456789-12345-ABCDEFGHIJKLMNOPRSTUVWXYZ-abcdefghjiklmnopqrstuvwxyz > @@ -0,0 +1,1 @@ > +foo > diff --git a/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT > new file mode 100644 > --- /dev/null > +++ b/AUX/SECOND/X.PRN/FOURTH/FI:FTH/SIXTH/SEVENTH/EIGHTH/NINETH/TENTH/ELEVENTH/LOREMIPSUM.TXT > @@ -0,0 +1,1 @@ > +foo > diff --git a/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt > new file mode 100644 > --- /dev/null > +++ b/Project Planning/Resources/AnotherLongDirectoryName/Followedbyanother/AndAnother/AndThenAnExtremelyLongFileName.txt > @@ -0,0 +1,1 @@ > +foo > diff --git a/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c > new file mode 100644 > --- /dev/null > +++ b/bla.aux/prn/PRN/lpt/com3/nul/coma/foo.NUL/normal.c > @@ -0,0 +1,1 @@ > +foo > diff --git a/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider > new file mode 100644 > --- /dev/null > +++ b/enterprise/openesbaddons/contrib-imola/corba-bc/netbeansplugin/wsdlExtension/src/main/java/META-INF/services/org.netbeans.modules.xml.wsdl.bindingsupport.spi.ExtensibilityElementTemplateProvider > @@ -0,0 +1,1 @@ > +foo > EOF $ find .hg/store -name *.i | sort .hg/store/00changelog.i .hg/store/00manifest.i .hg/store/data/bla.aux/pr~6e/_p_r_n/lpt/co~6d3/nu~6c/coma/foo._n_u_l/normal.c.i .hg/store/dh/12345678/12345678/12345678/12345678/12345678/12345678/12345678/12345/xxxxxx168e07b38e65eff86ab579afaaa8e30bfbe0f35f.i .hg/store/dh/au~78/second/x.prn/fourth/fi~3afth/sixth/seventh/eighth/nineth/tenth/loremia20419e358ddff1bf8751e38288aff1d7c32ec05.i .hg/store/dh/enterpri/openesba/contrib-/corba-bc/netbeans/wsdlexte/src/main/java/org.net7018f27961fdf338a598a40c4683429e7ffb9743.i .hg/store/dh/project_/resource/anotherl/followed/andanoth/andthenanextremelylongfilename0d8e1f4187c650e2f1fdca9fd90f786bc0976b6b.i $ cd .. Aborting lock does not prevent fncache writes $ cat > exceptionext.py <<EOF > import os > from mercurial import commands, error > from mercurial.extensions import wrapcommand, wrapfunction > > def lockexception(orig, vfs, lockname, wait, releasefn, *args, **kwargs): > def releasewrap(): > l.held = False # ensure __del__ is a noop > raise error.Abort("forced lock failure") > l = orig(vfs, lockname, wait, releasewrap, *args, **kwargs) > return l > > def reposetup(ui, repo): > wrapfunction(repo, '_lock', lockexception) > > cmdtable = {} > > # wrap "commit" command to prevent wlock from being '__del__()'-ed > # at the end of dispatching (for intentional "forced lcok failure") > def commitwrap(orig, ui, repo, *pats, **opts): > repo = repo.unfiltered() # to use replaced repo._lock certainly > wlock = repo.wlock() > try: > return orig(ui, repo, *pats, **opts) > finally: > # multiple 'relase()' is needed for complete releasing wlock, > # because "forced" abort at last releasing store lock > # prevents wlock from being released at same 'lockmod.release()' > for i in range(wlock.held): > wlock.release() > > def extsetup(ui): > wrapcommand(commands.table, "commit", commitwrap) > EOF $ extpath=`pwd`/exceptionext.py $ hg init fncachetxn $ cd fncachetxn $ printf "[extensions]\nexceptionext=$extpath\n" >> .hg/hgrc $ touch y $ hg ci -qAm y abort: forced lock failure [255] $ cat .hg/store/fncache data/y.i Aborting transaction prevents fncache change $ cat > ../exceptionext.py <<EOF > import os > from mercurial import commands, error, localrepo > from mercurial.extensions import wrapfunction > > def wrapper(orig, self, *args, **kwargs): > tr = orig(self, *args, **kwargs) > def fail(tr): > raise error.Abort("forced transaction failure") > # zzz prefix to ensure it sorted after store.write > tr.addfinalize('zzz-forcefails', fail) > return tr > > def uisetup(ui): > wrapfunction(localrepo.localrepository, 'transaction', wrapper) > > cmdtable = {} > > EOF $ rm -f "${extpath}c" $ touch z $ hg ci -qAm z transaction abort! rollback completed abort: forced transaction failure [255] $ cat .hg/store/fncache data/y.i Aborted transactions can be recovered later $ cat > ../exceptionext.py <<EOF > import os > from mercurial import commands, error, transaction, localrepo > from mercurial.extensions import wrapfunction > > def trwrapper(orig, self, *args, **kwargs): > tr = orig(self, *args, **kwargs) > def fail(tr): > raise error.Abort("forced transaction failure") > # zzz prefix to ensure it sorted after store.write > tr.addfinalize('zzz-forcefails', fail) > return tr > > def abortwrapper(orig, self, *args, **kwargs): > raise error.Abort("forced transaction failure") > > def uisetup(ui): > wrapfunction(localrepo.localrepository, 'transaction', trwrapper) > 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 $ cd .. debugrebuildfncache does nothing unless repo has fncache requirement $ hg --config format.usefncache=false init nofncache $ cd nofncache $ hg debugrebuildfncache (not rebuilding fncache because repository does not support fncache) $ cd .. debugrebuildfncache works on empty repository $ hg init empty $ cd empty $ hg debugrebuildfncache fncache already up to date $ cd .. debugrebuildfncache on an up to date repository no-ops $ hg init repo $ cd repo $ echo initial > foo $ echo initial > .bar $ hg commit -A -m initial adding .bar adding foo $ cat .hg/store/fncache | sort data/.bar.i data/foo.i $ hg debugrebuildfncache fncache already up to date debugrebuildfncache restores deleted fncache file $ rm -f .hg/store/fncache $ hg debugrebuildfncache adding data/.bar.i adding data/foo.i 2 items added, 0 removed from fncache $ cat .hg/store/fncache | sort data/.bar.i data/foo.i Rebuild after rebuild should no-op $ hg debugrebuildfncache fncache already up to date A single missing file should get restored, an extra file should be removed $ cat > .hg/store/fncache << EOF > data/foo.i > data/bad-entry.i > EOF $ hg debugrebuildfncache removing data/bad-entry.i adding data/.bar.i 1 items added, 1 removed from fncache $ cat .hg/store/fncache | sort data/.bar.i data/foo.i $ cd .. Try a simple variation without dotencode to ensure fncache is ignorant of encoding $ hg --config format.dotencode=false init nodotencode $ cd nodotencode $ echo initial > foo $ echo initial > .bar $ hg commit -A -m initial adding .bar adding foo $ cat .hg/store/fncache | sort data/.bar.i data/foo.i $ rm .hg/store/fncache $ hg debugrebuildfncache adding data/.bar.i adding data/foo.i 2 items added, 0 removed from fncache $ cat .hg/store/fncache | sort data/.bar.i data/foo.i