Mercurial > public > mercurial-scm > hg-stable
diff mercurial/match.py @ 32534:7095dbc266e3
match: split up main matcher into patternmatcher and includematcher
At this point the includematcher is an exact copy of the main matcher
class. We will specialize and simplify both classes in the following
patches. This initial unmodified copy is just to make the differences
clearer. We also rename the main matcher to "patternmatcher" for
consistency.
I may eventually merge this new includematcher back into the main
matcher, but I think doing it this way makes the intermediate steps
clearer regardless.
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Fri, 19 May 2017 22:36:14 -0700 |
parents | 369c2d5eeea3 |
children | 3026f19b4b01 |
line wrap: on
line diff
--- a/mercurial/match.py Thu May 18 23:39:39 2017 -0700 +++ b/mercurial/match.py Fri May 19 22:36:14 2017 -0700 @@ -145,18 +145,18 @@ if exact: m = exactmatcher(root, cwd, patterns, badfn) else: - m = matcher(root, cwd, normalize, patterns, include=None, - default=default, auditor=auditor, ctx=ctx, - listsubrepos=listsubrepos, warn=warn, badfn=badfn) + m = patternmatcher(root, cwd, normalize, patterns, include=None, + default=default, auditor=auditor, ctx=ctx, + listsubrepos=listsubrepos, warn=warn, badfn=badfn) if include: - im = matcher(root, cwd, normalize, [], include=include, default=default, - auditor=auditor, ctx=ctx, listsubrepos=listsubrepos, - warn=warn, badfn=None) + im = includematcher(root, cwd, normalize, [], include=include, + default=default, auditor=auditor, ctx=ctx, + listsubrepos=listsubrepos, warn=warn, badfn=None) m = intersectmatchers(m, im) if exclude: - em = matcher(root, cwd, normalize, [], include=exclude, default=default, - auditor=auditor, ctx=ctx, listsubrepos=listsubrepos, - warn=warn, badfn=None) + em = includematcher(root, cwd, normalize, [], include=exclude, + default=default, auditor=auditor, ctx=ctx, + listsubrepos=listsubrepos, warn=warn, badfn=None) m = differencematcher(m, em) return m @@ -311,13 +311,14 @@ def prefix(self): return not self.always() and not self.isexact() and not self.anypats() -class matcher(basematcher): +class patternmatcher(basematcher): def __init__(self, root, cwd, normalize, patterns, include=None, default='glob', auditor=None, ctx=None, listsubrepos=False, warn=None, badfn=None): - super(matcher, self).__init__(root, cwd, badfn, - relativeuipath=bool(include or patterns)) + super(patternmatcher, self).__init__(root, cwd, badfn, + relativeuipath=bool(include or + patterns)) if include is None: include = [] @@ -397,7 +398,97 @@ return self._always def __repr__(self): - return ('<matcher patterns=%r, includes=%r>' % + return ('<patternmatcher patterns=%r, includes=%r>' % + (self.patternspat, self.includepat)) + +class includematcher(basematcher): + + def __init__(self, root, cwd, normalize, patterns, include=None, + default='glob', auditor=None, ctx=None, + listsubrepos=False, warn=None, badfn=None): + super(includematcher, self).__init__(root, cwd, badfn, + relativeuipath=bool(include or + patterns)) + if include is None: + include = [] + + self._anypats = bool(include) + self._anyincludepats = False + self._always = False + self.patternspat = None + self.includepat = None + + # roots are directories which are recursively included. + self._includeroots = set() + # dirs are directories which are non-recursively included. + self._includedirs = set() + + matchfns = [] + if include: + kindpats = normalize(include, 'glob', root, cwd, auditor, warn) + self.includepat, im = _buildmatch(ctx, kindpats, '(?:/|$)', + listsubrepos, root) + self._anyincludepats = _anypats(kindpats) + roots, dirs = _rootsanddirs(kindpats) + self._includeroots.update(roots) + self._includedirs.update(dirs) + matchfns.append(im) + if patterns: + kindpats = normalize(patterns, default, root, cwd, auditor, warn) + if not _kindpatsalwaysmatch(kindpats): + self._files = _explicitfiles(kindpats) + self._anypats = self._anypats or _anypats(kindpats) + self.patternspat, pm = _buildmatch(ctx, kindpats, '$', + listsubrepos, root) + matchfns.append(pm) + + if not matchfns: + m = util.always + self._always = True + elif len(matchfns) == 1: + m = matchfns[0] + else: + def m(f): + for matchfn in matchfns: + if not matchfn(f): + return False + return True + + self.matchfn = m + + @propertycache + def _dirs(self): + return set(util.dirs(self._fileset)) | {'.'} + + def visitdir(self, dir): + if self.prefix() and dir in self._fileset: + return 'all' + if self._includeroots or self._includedirs: + if (not self._anyincludepats and + dir in self._includeroots): + # The condition above is essentially self.prefix() for includes + return 'all' + if ('.' not in self._includeroots and + dir not in self._includeroots and + dir not in self._includedirs and + not any(parent in self._includeroots + for parent in util.finddirs(dir))): + return False + return (not self._fileset or + '.' in self._fileset or + dir in self._fileset or + dir in self._dirs or + any(parentdir in self._fileset + for parentdir in util.finddirs(dir))) + + def anypats(self): + return self._anypats + + def always(self): + return self._always + + def __repr__(self): + return ('<includematcher patterns=%r, includes=%r>' % (self.patternspat, self.includepat)) class exactmatcher(basematcher):