Mercurial > hg
changeset 33379:7ddb2aa2b7af
match: express anypats(), not prefix(), in terms of the others
When I added prefix() in 9789b4a7c595 (match: introduce boolean
prefix() method, 2014-10-28), we already had always(), isexact(), and
anypats(), so it made sense to write it in terms of them (a prefix
matcher is one that isn't any of the other types). It's only now that
I realize that it's much more natural to define prefix() explicitly
(it's one that uses path: patterns, roughly speaking) and let
anypats() be defined in terms of the others. Remember that these
methods are all used for determining which fast paths are
possible. anypats() simply means that no fast paths are possible (it
could be called complex() instead). Further evidence is that
rootfilesin:some/dir does not have any patterns, but it's still
considered to be an anypats() matcher. That's because anypats() really
just means that it's not a prefix() matcher (and not always() and not
isexact()).
This patch thus changes prefix() to return False by default and
anypats() to return True only if the other three are False. Having
anypats() be True by default also seems like a good thing, because it
means forgetting to override it will lead only to performance bugs,
not correctness bugs.
Since the base class's implementation changes, we're also forced to
update the subclasses. That change exposed and fixed a bug in the
differencematcher: for example when both its two input matchers were
prefix matchers, we would say that the result was also a prefix
matcher, which is incorrect, because e.g "path:dir - path:dir/foo" no
longer matches everything under "dir" (which is what prefix() means).
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Sun, 09 Jul 2017 17:02:09 -0700 |
parents | adf95bfb423a |
children | 892d255ec2a1 |
files | mercurial/match.py |
diffstat | 1 files changed, 16 insertions(+), 35 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/match.py Sun Jul 09 15:19:27 2017 -0700 +++ b/mercurial/match.py Sun Jul 09 17:02:09 2017 -0700 @@ -307,20 +307,25 @@ ''' return False - def anypats(self): - '''Matcher uses patterns or include/exclude.''' - return False - def always(self): - '''Matcher will match everything and .files() will be empty - - optimization might be possible and necessary.''' + '''Matcher will match everything and .files() will be empty -- + optimization might be possible.''' return False def isexact(self): + '''Matcher will match exactly the list of files in .files() -- + optimization might be possible.''' return False def prefix(self): - return not self.always() and not self.isexact() and not self.anypats() + '''Matcher will match the paths in .files() recursively -- + optimization might be possible.''' + return False + + def anypats(self): + '''None of .always(), .isexact(), and .prefix() is true -- + optimizations will be difficult.''' + return not self.always() and not self.isexact() and not self.prefix() class alwaysmatcher(basematcher): '''Matches everything.''' @@ -385,8 +390,8 @@ any(parentdir in self._fileset for parentdir in util.finddirs(dir))) - def anypats(self): - return self._anypats + def prefix(self): + return not self._anypats def __repr__(self): return ('<patternmatcher patterns=%r>' % self._pats) @@ -416,9 +421,6 @@ any(parentdir in self._roots for parentdir in util.finddirs(dir))) - def anypats(self): - return True - def __repr__(self): return ('<includematcher includes=%r>' % self._pats) @@ -497,9 +499,6 @@ def isexact(self): return self._m1.isexact() - def anypats(self): - return self._m1.anypats() or self._m2.anypats() - def __repr__(self): return ('<differencematcher m1=%r, m2=%r>' % (self._m1, self._m2)) @@ -566,9 +565,6 @@ def isexact(self): return self._m1.isexact() or self._m2.isexact() - def anypats(self): - return self._m1.anypats() or self._m2.anypats() - def __repr__(self): return ('<intersectionmatcher m1=%r, m2=%r>' % (self._m1, self._m2)) @@ -645,8 +641,8 @@ def always(self): return self._always - def anypats(self): - return self._matcher.anypats() + def prefix(self): + return self._matcher.prefix() and not self._always def __repr__(self): return ('<subdirmatcher path=%r, matcher=%r>' % @@ -662,12 +658,6 @@ def __call__(self, value): return value in self._includes or self._matcher(value) - def anypats(self): - return True - - def prefix(self): - return False - def __repr__(self): return ('<forceincludematcher matcher=%r, includes=%r>' % (self._matcher, sorted(self._includes))) @@ -683,12 +673,6 @@ return True return False - def anypats(self): - return True - - def prefix(self): - return False - def __repr__(self): return ('<unionmatcher matchers=%r>' % self._matchers) @@ -699,9 +683,6 @@ def __call__(self, value): return not self._matcher(value) - def anypats(self): - return True - def __repr__(self): return ('<negatematcher matcher=%r>' % self._matcher)