Mercurial > hg
comparison mercurial/match.py @ 41675:ddbebce94665
match: delete unused root and cwd arguments to constructors (API)
Most matchers no longer need the root and cwd
arguments. patternmatcher and includematcher still need the root
argument for subincludes.
Differential Revision: https://phab.mercurial-scm.org/D5929
author | Martin von Zweigbergk <martinvonz@google.com> |
---|---|
date | Sun, 10 Feb 2019 14:35:36 -0800 |
parents | c302218a2528 |
children | 0531dff73d0b |
comparison
equal
deleted
inserted
replaced
41674:e178b131906a | 41675:ddbebce94665 |
---|---|
40 # slightly faster, provided by facebook's re2 bindings | 40 # slightly faster, provided by facebook's re2 bindings |
41 return m.test_match | 41 return m.test_match |
42 except AttributeError: | 42 except AttributeError: |
43 return m.match | 43 return m.match |
44 | 44 |
45 def _expandsets(root, cwd, kindpats, ctx, listsubrepos, badfn): | 45 def _expandsets(kindpats, ctx, listsubrepos, badfn): |
46 '''Returns the kindpats list with the 'set' patterns expanded to matchers''' | 46 '''Returns the kindpats list with the 'set' patterns expanded to matchers''' |
47 matchers = [] | 47 matchers = [] |
48 other = [] | 48 other = [] |
49 | 49 |
50 for kind, pat, source in kindpats: | 50 for kind, pat, source in kindpats: |
55 matchers.append(ctx.matchfileset(pat, badfn=badfn)) | 55 matchers.append(ctx.matchfileset(pat, badfn=badfn)) |
56 | 56 |
57 if listsubrepos: | 57 if listsubrepos: |
58 for subpath in ctx.substate: | 58 for subpath in ctx.substate: |
59 sm = ctx.sub(subpath).matchfileset(pat, badfn=badfn) | 59 sm = ctx.sub(subpath).matchfileset(pat, badfn=badfn) |
60 pm = prefixdirmatcher(root, cwd, subpath, sm, badfn=badfn) | 60 pm = prefixdirmatcher(subpath, sm, badfn=badfn) |
61 matchers.append(pm) | 61 matchers.append(pm) |
62 | 62 |
63 continue | 63 continue |
64 other.append((kind, pat, source)) | 64 other.append((kind, pat, source)) |
65 return matchers, other | 65 return matchers, other |
95 for kind, pat, source in kindpats: | 95 for kind, pat, source in kindpats: |
96 if pat != '' or kind not in ['relpath', 'glob']: | 96 if pat != '' or kind not in ['relpath', 'glob']: |
97 return False | 97 return False |
98 return True | 98 return True |
99 | 99 |
100 def _buildkindpatsmatcher(matchercls, root, cwd, kindpats, ctx=None, | 100 def _buildkindpatsmatcher(matchercls, root, kindpats, ctx=None, |
101 listsubrepos=False, badfn=None): | 101 listsubrepos=False, badfn=None): |
102 matchers = [] | 102 matchers = [] |
103 fms, kindpats = _expandsets(root, cwd, kindpats, ctx=ctx, | 103 fms, kindpats = _expandsets(kindpats, ctx=ctx, |
104 listsubrepos=listsubrepos, badfn=badfn) | 104 listsubrepos=listsubrepos, badfn=badfn) |
105 if kindpats: | 105 if kindpats: |
106 m = matchercls(root, cwd, kindpats, badfn=badfn) | 106 m = matchercls(root, kindpats, badfn=badfn) |
107 matchers.append(m) | 107 matchers.append(m) |
108 if fms: | 108 if fms: |
109 matchers.extend(fms) | 109 matchers.extend(fms) |
110 if not matchers: | 110 if not matchers: |
111 return nevermatcher(root, cwd, badfn=badfn) | 111 return nevermatcher(badfn=badfn) |
112 if len(matchers) == 1: | 112 if len(matchers) == 1: |
113 return matchers[0] | 113 return matchers[0] |
114 return unionmatcher(matchers) | 114 return unionmatcher(matchers) |
115 | 115 |
116 def match(root, cwd, patterns=None, include=None, exclude=None, default='glob', | 116 def match(root, cwd, patterns=None, include=None, exclude=None, default='glob', |
167 return kindpats | 167 return kindpats |
168 | 168 |
169 if patterns: | 169 if patterns: |
170 kindpats = normalize(patterns, default, root, cwd, auditor, warn) | 170 kindpats = normalize(patterns, default, root, cwd, auditor, warn) |
171 if _kindpatsalwaysmatch(kindpats): | 171 if _kindpatsalwaysmatch(kindpats): |
172 m = alwaysmatcher(root, cwd, badfn) | 172 m = alwaysmatcher(badfn) |
173 else: | 173 else: |
174 m = _buildkindpatsmatcher(patternmatcher, root, cwd, kindpats, | 174 m = _buildkindpatsmatcher(patternmatcher, root, kindpats, ctx=ctx, |
175 ctx=ctx, listsubrepos=listsubrepos, | 175 listsubrepos=listsubrepos, badfn=badfn) |
176 badfn=badfn) | |
177 else: | 176 else: |
178 # It's a little strange that no patterns means to match everything. | 177 # It's a little strange that no patterns means to match everything. |
179 # Consider changing this to match nothing (probably using nevermatcher). | 178 # Consider changing this to match nothing (probably using nevermatcher). |
180 m = alwaysmatcher(root, cwd, badfn) | 179 m = alwaysmatcher(badfn) |
181 | 180 |
182 if include: | 181 if include: |
183 kindpats = normalize(include, 'glob', root, cwd, auditor, warn) | 182 kindpats = normalize(include, 'glob', root, cwd, auditor, warn) |
184 im = _buildkindpatsmatcher(includematcher, root, cwd, kindpats, ctx=ctx, | 183 im = _buildkindpatsmatcher(includematcher, root, kindpats, ctx=ctx, |
185 listsubrepos=listsubrepos, badfn=None) | 184 listsubrepos=listsubrepos, badfn=None) |
186 m = intersectmatchers(m, im) | 185 m = intersectmatchers(m, im) |
187 if exclude: | 186 if exclude: |
188 kindpats = normalize(exclude, 'glob', root, cwd, auditor, warn) | 187 kindpats = normalize(exclude, 'glob', root, cwd, auditor, warn) |
189 em = _buildkindpatsmatcher(includematcher, root, cwd, kindpats, ctx=ctx, | 188 em = _buildkindpatsmatcher(includematcher, root, kindpats, ctx=ctx, |
190 listsubrepos=listsubrepos, badfn=None) | 189 listsubrepos=listsubrepos, badfn=None) |
191 m = differencematcher(m, em) | 190 m = differencematcher(m, em) |
192 return m | 191 return m |
193 | 192 |
194 def exact(root, cwd, files, badfn=None): | 193 def exact(root, cwd, files, badfn=None): |
195 return exactmatcher(root, cwd, files, badfn=badfn) | 194 return exactmatcher(files, badfn=badfn) |
196 | 195 |
197 def always(root, cwd, badfn=None): | 196 def always(root, cwd, badfn=None): |
198 return alwaysmatcher(root, cwd, badfn=badfn) | 197 return alwaysmatcher(badfn=badfn) |
199 | 198 |
200 def never(root, cwd, badfn=None): | 199 def never(root, cwd, badfn=None): |
201 return nevermatcher(root, cwd, badfn=badfn) | 200 return nevermatcher(badfn=badfn) |
202 | 201 |
203 def badmatch(match, badfn): | 202 def badmatch(match, badfn): |
204 """Make a copy of the given matcher, replacing its bad method with the given | 203 """Make a copy of the given matcher, replacing its bad method with the given |
205 one. | 204 one. |
206 """ | 205 """ |
249 kindpats.append((kind, pat, '')) | 248 kindpats.append((kind, pat, '')) |
250 return kindpats | 249 return kindpats |
251 | 250 |
252 class basematcher(object): | 251 class basematcher(object): |
253 | 252 |
254 def __init__(self, root, cwd, badfn=None): | 253 def __init__(self, badfn=None): |
255 self._root = root | |
256 self._cwd = cwd | |
257 if badfn is not None: | 254 if badfn is not None: |
258 self.bad = badfn | 255 self.bad = badfn |
259 | 256 |
260 def __call__(self, fn): | 257 def __call__(self, fn): |
261 return self.matchfn(fn) | 258 return self.matchfn(fn) |
374 return not self.always() and not self.isexact() and not self.prefix() | 371 return not self.always() and not self.isexact() and not self.prefix() |
375 | 372 |
376 class alwaysmatcher(basematcher): | 373 class alwaysmatcher(basematcher): |
377 '''Matches everything.''' | 374 '''Matches everything.''' |
378 | 375 |
379 def __init__(self, root, cwd, badfn=None): | 376 def __init__(self, badfn=None): |
380 super(alwaysmatcher, self).__init__(root, cwd, badfn) | 377 super(alwaysmatcher, self).__init__(badfn) |
381 | 378 |
382 def always(self): | 379 def always(self): |
383 return True | 380 return True |
384 | 381 |
385 def matchfn(self, f): | 382 def matchfn(self, f): |
395 return r'<alwaysmatcher>' | 392 return r'<alwaysmatcher>' |
396 | 393 |
397 class nevermatcher(basematcher): | 394 class nevermatcher(basematcher): |
398 '''Matches nothing.''' | 395 '''Matches nothing.''' |
399 | 396 |
400 def __init__(self, root, cwd, badfn=None): | 397 def __init__(self, badfn=None): |
401 super(nevermatcher, self).__init__(root, cwd, badfn) | 398 super(nevermatcher, self).__init__(badfn) |
402 | 399 |
403 # It's a little weird to say that the nevermatcher is an exact matcher | 400 # It's a little weird to say that the nevermatcher is an exact matcher |
404 # or a prefix matcher, but it seems to make sense to let callers take | 401 # or a prefix matcher, but it seems to make sense to let callers take |
405 # fast paths based on either. There will be no exact matches, nor any | 402 # fast paths based on either. There will be no exact matches, nor any |
406 # prefixes (files() returns []), so fast paths iterating over them should | 403 # prefixes (files() returns []), so fast paths iterating over them should |
421 return r'<nevermatcher>' | 418 return r'<nevermatcher>' |
422 | 419 |
423 class predicatematcher(basematcher): | 420 class predicatematcher(basematcher): |
424 """A matcher adapter for a simple boolean function""" | 421 """A matcher adapter for a simple boolean function""" |
425 | 422 |
426 def __init__(self, root, cwd, predfn, predrepr=None, badfn=None): | 423 def __init__(self, predfn, predrepr=None, badfn=None): |
427 super(predicatematcher, self).__init__(root, cwd, badfn) | 424 super(predicatematcher, self).__init__(badfn) |
428 self.matchfn = predfn | 425 self.matchfn = predfn |
429 self._predrepr = predrepr | 426 self._predrepr = predrepr |
430 | 427 |
431 @encoding.strmethod | 428 @encoding.strmethod |
432 def __repr__(self): | 429 def __repr__(self): |
434 or pycompat.byterepr(self.matchfn)) | 431 or pycompat.byterepr(self.matchfn)) |
435 return '<predicatenmatcher pred=%s>' % s | 432 return '<predicatenmatcher pred=%s>' % s |
436 | 433 |
437 class patternmatcher(basematcher): | 434 class patternmatcher(basematcher): |
438 | 435 |
439 def __init__(self, root, cwd, kindpats, badfn=None): | 436 def __init__(self, root, kindpats, badfn=None): |
440 super(patternmatcher, self).__init__(root, cwd, badfn) | 437 super(patternmatcher, self).__init__(badfn) |
441 | 438 |
442 self._files = _explicitfiles(kindpats) | 439 self._files = _explicitfiles(kindpats) |
443 self._prefix = _prefix(kindpats) | 440 self._prefix = _prefix(kindpats) |
444 self._pats, self.matchfn = _buildmatch(kindpats, '$', root) | 441 self._pats, self.matchfn = _buildmatch(kindpats, '$', root) |
445 | 442 |
512 def get(self, path): | 509 def get(self, path): |
513 return self._dirs.get(path, set()) | 510 return self._dirs.get(path, set()) |
514 | 511 |
515 class includematcher(basematcher): | 512 class includematcher(basematcher): |
516 | 513 |
517 def __init__(self, root, cwd, kindpats, badfn=None): | 514 def __init__(self, root, kindpats, badfn=None): |
518 super(includematcher, self).__init__(root, cwd, badfn) | 515 super(includematcher, self).__init__(badfn) |
519 | 516 |
520 self._pats, self.matchfn = _buildmatch(kindpats, '(?:/|$)', root) | 517 self._pats, self.matchfn = _buildmatch(kindpats, '(?:/|$)', root) |
521 self._prefix = _prefix(kindpats) | 518 self._prefix = _prefix(kindpats) |
522 roots, dirs, parents = _rootsdirsandparents(kindpats) | 519 roots, dirs, parents = _rootsdirsandparents(kindpats) |
523 # roots are directories which are recursively included. | 520 # roots are directories which are recursively included. |
573 class exactmatcher(basematcher): | 570 class exactmatcher(basematcher): |
574 '''Matches the input files exactly. They are interpreted as paths, not | 571 '''Matches the input files exactly. They are interpreted as paths, not |
575 patterns (so no kind-prefixes). | 572 patterns (so no kind-prefixes). |
576 ''' | 573 ''' |
577 | 574 |
578 def __init__(self, root, cwd, files, badfn=None): | 575 def __init__(self, files, badfn=None): |
579 super(exactmatcher, self).__init__(root, cwd, badfn) | 576 super(exactmatcher, self).__init__(badfn) |
580 | 577 |
581 if isinstance(files, list): | 578 if isinstance(files, list): |
582 self._files = files | 579 self._files = files |
583 else: | 580 else: |
584 self._files = list(files) | 581 self._files = list(files) |
621 | 618 |
622 class differencematcher(basematcher): | 619 class differencematcher(basematcher): |
623 '''Composes two matchers by matching if the first matches and the second | 620 '''Composes two matchers by matching if the first matches and the second |
624 does not. | 621 does not. |
625 | 622 |
626 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir, | 623 The second matcher's non-matching-attributes (bad, explicitdir, |
627 traversedir) are ignored. | 624 traversedir) are ignored. |
628 ''' | 625 ''' |
629 def __init__(self, m1, m2): | 626 def __init__(self, m1, m2): |
630 super(differencematcher, self).__init__(m1._root, m1._cwd) | 627 super(differencematcher, self).__init__() |
631 self._m1 = m1 | 628 self._m1 = m1 |
632 self._m2 = m2 | 629 self._m2 = m2 |
633 self.bad = m1.bad | 630 self.bad = m1.bad |
634 self.explicitdir = m1.explicitdir | 631 self.explicitdir = m1.explicitdir |
635 self.traversedir = m1.traversedir | 632 self.traversedir = m1.traversedir |
689 return ('<differencematcher m1=%r, m2=%r>' % (self._m1, self._m2)) | 686 return ('<differencematcher m1=%r, m2=%r>' % (self._m1, self._m2)) |
690 | 687 |
691 def intersectmatchers(m1, m2): | 688 def intersectmatchers(m1, m2): |
692 '''Composes two matchers by matching if both of them match. | 689 '''Composes two matchers by matching if both of them match. |
693 | 690 |
694 The second matcher's non-matching-attributes (root, cwd, bad, explicitdir, | 691 The second matcher's non-matching-attributes (bad, explicitdir, |
695 traversedir) are ignored. | 692 traversedir) are ignored. |
696 ''' | 693 ''' |
697 if m1 is None or m2 is None: | 694 if m1 is None or m2 is None: |
698 return m1 or m2 | 695 return m1 or m2 |
699 if m1.always(): | 696 if m1.always(): |
709 return m | 706 return m |
710 return intersectionmatcher(m1, m2) | 707 return intersectionmatcher(m1, m2) |
711 | 708 |
712 class intersectionmatcher(basematcher): | 709 class intersectionmatcher(basematcher): |
713 def __init__(self, m1, m2): | 710 def __init__(self, m1, m2): |
714 super(intersectionmatcher, self).__init__(m1._root, m1._cwd) | 711 super(intersectionmatcher, self).__init__() |
715 self._m1 = m1 | 712 self._m1 = m1 |
716 self._m2 = m2 | 713 self._m2 = m2 |
717 self.bad = m1.bad | 714 self.bad = m1.bad |
718 self.explicitdir = m1.explicitdir | 715 self.explicitdir = m1.explicitdir |
719 self.traversedir = m1.traversedir | 716 self.traversedir = m1.traversedir |
796 >>> m2.bad(b'x.txt', b'No such file') | 793 >>> m2.bad(b'x.txt', b'No such file') |
797 sub/x.txt: No such file | 794 sub/x.txt: No such file |
798 """ | 795 """ |
799 | 796 |
800 def __init__(self, path, matcher): | 797 def __init__(self, path, matcher): |
801 super(subdirmatcher, self).__init__(matcher._root, matcher._cwd) | 798 super(subdirmatcher, self).__init__() |
802 self._path = path | 799 self._path = path |
803 self._matcher = matcher | 800 self._matcher = matcher |
804 self._always = matcher.always() | 801 self._always = matcher.always() |
805 | 802 |
806 self._files = [f[len(path) + 1:] for f in matcher._files | 803 self._files = [f[len(path) + 1:] for f in matcher._files |
847 (self._path, self._matcher)) | 844 (self._path, self._matcher)) |
848 | 845 |
849 class prefixdirmatcher(basematcher): | 846 class prefixdirmatcher(basematcher): |
850 """Adapt a matcher to work on a parent directory. | 847 """Adapt a matcher to work on a parent directory. |
851 | 848 |
852 The matcher's non-matching-attributes (root, cwd, bad, explicitdir, | 849 The matcher's non-matching-attributes (bad, explicitdir, traversedir) are |
853 traversedir) are ignored. | 850 ignored. |
854 | 851 |
855 The prefix path should usually be the relative path from the root of | 852 The prefix path should usually be the relative path from the root of |
856 this matcher to the root of the wrapped matcher. | 853 this matcher to the root of the wrapped matcher. |
857 | 854 |
858 >>> m1 = match(util.localpath(b'root/d/e'), b'f', [b'../a.txt', b'b.txt']) | 855 >>> m1 = match(util.localpath(b'root/d/e'), b'f', [b'../a.txt', b'b.txt']) |
859 >>> m2 = prefixdirmatcher(b'root', b'd/e/f', b'd/e', m1) | 856 >>> m2 = prefixdirmatcher(b'd/e', m1) |
860 >>> bool(m2(b'a.txt'),) | 857 >>> bool(m2(b'a.txt'),) |
861 False | 858 False |
862 >>> bool(m2(b'd/e/a.txt')) | 859 >>> bool(m2(b'd/e/a.txt')) |
863 True | 860 True |
864 >>> bool(m2(b'd/e/b.txt')) | 861 >>> bool(m2(b'd/e/b.txt')) |
877 False | 874 False |
878 >>> m2.visitdir(b'd/ef') | 875 >>> m2.visitdir(b'd/ef') |
879 False | 876 False |
880 """ | 877 """ |
881 | 878 |
882 def __init__(self, root, cwd, path, matcher, badfn=None): | 879 def __init__(self, path, matcher, badfn=None): |
883 super(prefixdirmatcher, self).__init__(root, cwd, badfn) | 880 super(prefixdirmatcher, self).__init__(badfn) |
884 if not path: | 881 if not path: |
885 raise error.ProgrammingError('prefix path must not be empty') | 882 raise error.ProgrammingError('prefix path must not be empty') |
886 self._path = path | 883 self._path = path |
887 self._pathprefix = path + '/' | 884 self._pathprefix = path + '/' |
888 self._matcher = matcher | 885 self._matcher = matcher |
928 % (pycompat.bytestr(self._path), self._matcher)) | 925 % (pycompat.bytestr(self._path), self._matcher)) |
929 | 926 |
930 class unionmatcher(basematcher): | 927 class unionmatcher(basematcher): |
931 """A matcher that is the union of several matchers. | 928 """A matcher that is the union of several matchers. |
932 | 929 |
933 The non-matching-attributes (root, cwd, bad, explicitdir, traversedir) are | 930 The non-matching-attributes (bad, explicitdir, traversedir) are taken from |
934 taken from the first matcher. | 931 the first matcher. |
935 """ | 932 """ |
936 | 933 |
937 def __init__(self, matchers): | 934 def __init__(self, matchers): |
938 m1 = matchers[0] | 935 m1 = matchers[0] |
939 super(unionmatcher, self).__init__(m1._root, m1._cwd) | 936 super(unionmatcher, self).__init__() |
940 self.explicitdir = m1.explicitdir | 937 self.explicitdir = m1.explicitdir |
941 self.traversedir = m1.traversedir | 938 self.traversedir = m1.traversedir |
942 self._matchers = matchers | 939 self._matchers = matchers |
943 | 940 |
944 def matchfn(self, f): | 941 def matchfn(self, f): |