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):