# HG changeset patch # User Martin von Zweigbergk # Date 1499795195 25200 # Node ID 258298f4712b603e7bf3ff7517132ab8a3cabada # Parent d78b7d734b63bd5490b4aa80169270e0a3a043ca sparse: override dirstate.walk() instead of dirstate._ignore Instead of treating files that are outside the sparse config as ignored, this makes it so we list only those that are within the sparse config by passing the sparse matcher to dirstate.walk(). Once we add support for narrow (sparseness applied to history, not just working copy), we will need to do a similar restriction of the walk over manifests, so this will be more consistent then. It also simplifies the code a bit. Note that a side-effect of this change is that files outside the sparse config used to be listed as ignored, but they will now not be listed at all. This can be seen in the test case where "hg purge" no longer has any effect because it doesn't see that the files outside the space config exist. To fix that, I think we should add an option to dirstate.walk() to walk outside the sparse config. We might expose that to the user as --no-sparse flag to e.g. "hg status" and "hg purge", but that's work for another day. Differential Revision: https://phab.mercurial-scm.org/D59 diff -r d78b7d734b63 -r 258298f4712b hgext/sparse.py --- a/hgext/sparse.py Wed Jul 12 15:24:47 2017 -0700 +++ b/hgext/sparse.py Tue Jul 11 10:46:35 2017 -0700 @@ -192,36 +192,11 @@ and to prevent modifications to files outside the checkout. """ - # The atrocity below is needed to wrap dirstate._ignore. It is a cached - # property, which means normal function wrapping doesn't work. - class ignorewrapper(object): - def __init__(self, orig): - self.orig = orig - self.origignore = None - self.func = None - self.sparsematch = None - - def __get__(self, obj, type=None): - origignore = self.orig.__get__(obj) + def walk(orig, self, match, subrepos, unknown, ignored, full=True): + match = matchmod.intersectmatchers(match, self._sparsematcher) + return orig(self, match, subrepos, unknown, ignored, full) - sparsematch = obj._sparsematcher - if sparsematch.always(): - return origignore - - if self.sparsematch != sparsematch or self.origignore != origignore: - self.func = matchmod.unionmatcher([ - origignore, matchmod.negatematcher(sparsematch)]) - self.sparsematch = sparsematch - self.origignore = origignore - return self.func - - def __set__(self, obj, value): - return self.orig.__set__(obj, value) - - def __delete__(self, obj): - return self.orig.__delete__(obj) - - replacefilecache(dirstate.dirstate, '_ignore', ignorewrapper) + extensions.wrapfunction(dirstate.dirstate, 'walk', walk) # dirstate.rebuild should not add non-matching files def _rebuild(orig, self, parent, allfiles, changedfiles=None): diff -r d78b7d734b63 -r 258298f4712b tests/test-sparse.t --- a/tests/test-sparse.t Wed Jul 12 15:24:47 2017 -0700 +++ b/tests/test-sparse.t Tue Jul 11 10:46:35 2017 -0700 @@ -144,10 +144,15 @@ M show $ hg up -qC . +TODO: add an option to purge to also purge files outside the sparse config? $ hg purge --all --config extensions.purge= $ ls + hide + hide3 show show2 +For now, manually remove the files + $ rm hide hide3 Verify rebase temporarily includes excluded files