comparison mercurial/match.py @ 25213:08a8e9da0ae7

match: add source to kindpats list Future patches will be adding the ability to recursively include pattern files in a match rule expression. Part of that behavior will require tracking which file each pattern came from so we can report errors correctly. Let's add a 'source' arg to the kindpats list to track this. Initially it will only be populated by listfile rules.
author Durham Goode <durham@fb.com>
date Sat, 16 May 2015 15:51:03 -0700
parents 472a685a4961
children 08703b10c3ae
comparison
equal deleted inserted replaced
25212:a39c35e8e559 25213:08a8e9da0ae7
24 def _expandsets(kindpats, ctx, listsubrepos): 24 def _expandsets(kindpats, ctx, listsubrepos):
25 '''Returns the kindpats list with the 'set' patterns expanded.''' 25 '''Returns the kindpats list with the 'set' patterns expanded.'''
26 fset = set() 26 fset = set()
27 other = [] 27 other = []
28 28
29 for kind, pat in kindpats: 29 for kind, pat, source in kindpats:
30 if kind == 'set': 30 if kind == 'set':
31 if not ctx: 31 if not ctx:
32 raise util.Abort("fileset expression with no context") 32 raise util.Abort("fileset expression with no context")
33 s = ctx.getfileset(pat) 33 s = ctx.getfileset(pat)
34 fset.update(s) 34 fset.update(s)
37 for subpath in ctx.substate: 37 for subpath in ctx.substate:
38 s = ctx.sub(subpath).getfileset(pat) 38 s = ctx.sub(subpath).getfileset(pat)
39 fset.update(subpath + '/' + f for f in s) 39 fset.update(subpath + '/' + f for f in s)
40 40
41 continue 41 continue
42 other.append((kind, pat)) 42 other.append((kind, pat, source))
43 return fset, other 43 return fset, other
44 44
45 def _kindpatsalwaysmatch(kindpats): 45 def _kindpatsalwaysmatch(kindpats):
46 """"Checks whether the kindspats match everything, as e.g. 46 """"Checks whether the kindspats match everything, as e.g.
47 'relpath:.' does. 47 'relpath:.' does.
48 """ 48 """
49 for kind, pat in kindpats: 49 for kind, pat, source in kindpats:
50 if pat != '' or kind not in ['relpath', 'glob']: 50 if pat != '' or kind not in ['relpath', 'glob']:
51 return False 51 return False
52 return True 52 return True
53 53
54 class match(object): 54 class match(object):
220 else: 220 else:
221 files = files.splitlines() 221 files = files.splitlines()
222 files = [f for f in files if f] 222 files = [f for f in files if f]
223 except EnvironmentError: 223 except EnvironmentError:
224 raise util.Abort(_("unable to read file list (%s)") % pat) 224 raise util.Abort(_("unable to read file list (%s)") % pat)
225 kindpats += self._normalize(files, default, root, cwd, auditor) 225 for k, p, source in self._normalize(files, default, root, cwd,
226 auditor):
227 kindpats.append((k, p, pat))
226 continue 228 continue
227 # else: re or relre - which cannot be normalized 229 # else: re or relre - which cannot be normalized
228 kindpats.append((kind, pat)) 230 kindpats.append((kind, pat, ''))
229 return kindpats 231 return kindpats
230 232
231 def exact(root, cwd, files): 233 def exact(root, cwd, files):
232 return match(root, cwd, files, exact=True) 234 return match(root, cwd, files, exact=True)
233 235
313 315
314 def _normalize(self, patterns, default, root, cwd, auditor): 316 def _normalize(self, patterns, default, root, cwd, auditor):
315 self._kp = super(icasefsmatcher, self)._normalize(patterns, default, 317 self._kp = super(icasefsmatcher, self)._normalize(patterns, default,
316 root, cwd, auditor) 318 root, cwd, auditor)
317 kindpats = [] 319 kindpats = []
318 for kind, pats in self._kp: 320 for kind, pats, source in self._kp:
319 if kind not in ('re', 'relre'): # regex can't be normalized 321 if kind not in ('re', 'relre'): # regex can't be normalized
320 pats = self._dsnormalize(pats) 322 pats = self._dsnormalize(pats)
321 kindpats.append((kind, pats)) 323 kindpats.append((kind, pats, source))
322 return kindpats 324 return kindpats
323 325
324 def patkind(pattern, default=None): 326 def patkind(pattern, default=None):
325 '''If pattern is 'kind:pat' with a known kind, return kind.''' 327 '''If pattern is 'kind:pat' with a known kind, return kind.'''
326 return _patsplit(pattern, default)[0] 328 return _patsplit(pattern, default)[0]
447 def _buildregexmatch(kindpats, globsuffix): 449 def _buildregexmatch(kindpats, globsuffix):
448 """Build a match function from a list of kinds and kindpats, 450 """Build a match function from a list of kinds and kindpats,
449 return regexp string and a matcher function.""" 451 return regexp string and a matcher function."""
450 try: 452 try:
451 regex = '(?:%s)' % '|'.join([_regex(k, p, globsuffix) 453 regex = '(?:%s)' % '|'.join([_regex(k, p, globsuffix)
452 for (k, p) in kindpats]) 454 for (k, p, s) in kindpats])
453 if len(regex) > 20000: 455 if len(regex) > 20000:
454 raise OverflowError 456 raise OverflowError
455 return regex, _rematcher(regex) 457 return regex, _rematcher(regex)
456 except OverflowError: 458 except OverflowError:
457 # We're using a Python with a tiny regex engine and we 459 # We're using a Python with a tiny regex engine and we
462 raise 464 raise
463 regexa, a = _buildregexmatch(kindpats[:l//2], globsuffix) 465 regexa, a = _buildregexmatch(kindpats[:l//2], globsuffix)
464 regexb, b = _buildregexmatch(kindpats[l//2:], globsuffix) 466 regexb, b = _buildregexmatch(kindpats[l//2:], globsuffix)
465 return regex, lambda s: a(s) or b(s) 467 return regex, lambda s: a(s) or b(s)
466 except re.error: 468 except re.error:
467 for k, p in kindpats: 469 for k, p, s in kindpats:
468 try: 470 try:
469 _rematcher('(?:%s)' % _regex(k, p, globsuffix)) 471 _rematcher('(?:%s)' % _regex(k, p, globsuffix))
470 except re.error: 472 except re.error:
471 raise util.Abort(_("invalid pattern (%s): %s") % (k, p)) 473 if s:
474 raise util.Abort(_("%s: invalid pattern (%s): %s") %
475 (s, k, p))
476 else:
477 raise util.Abort(_("invalid pattern (%s): %s") % (k, p))
472 raise util.Abort(_("invalid pattern")) 478 raise util.Abort(_("invalid pattern"))
473 479
474 def _roots(kindpats): 480 def _roots(kindpats):
475 '''return roots and exact explicitly listed files from patterns 481 '''return roots and exact explicitly listed files from patterns
476 482
477 >>> _roots([('glob', 'g/*'), ('glob', 'g'), ('glob', 'g*')]) 483 >>> _roots([('glob', 'g/*', ''), ('glob', 'g', ''), ('glob', 'g*', '')])
478 ['g', 'g', '.'] 484 ['g', 'g', '.']
479 >>> _roots([('relpath', 'r'), ('path', 'p/p'), ('path', '')]) 485 >>> _roots([('relpath', 'r', ''), ('path', 'p/p', ''), ('path', '', '')])
480 ['r', 'p/p', '.'] 486 ['r', 'p/p', '.']
481 >>> _roots([('relglob', 'rg*'), ('re', 're/'), ('relre', 'rr')]) 487 >>> _roots([('relglob', 'rg*', ''), ('re', 're/', ''), ('relre', 'rr', '')])
482 ['.', '.', '.'] 488 ['.', '.', '.']
483 ''' 489 '''
484 r = [] 490 r = []
485 for kind, pat in kindpats: 491 for kind, pat, source in kindpats:
486 if kind == 'glob': # find the non-glob prefix 492 if kind == 'glob': # find the non-glob prefix
487 root = [] 493 root = []
488 for p in pat.split('/'): 494 for p in pat.split('/'):
489 if '[' in p or '{' in p or '*' in p or '?' in p: 495 if '[' in p or '{' in p or '*' in p or '?' in p:
490 break 496 break
495 else: # relglob, re, relre 501 else: # relglob, re, relre
496 r.append('.') 502 r.append('.')
497 return r 503 return r
498 504
499 def _anypats(kindpats): 505 def _anypats(kindpats):
500 for kind, pat in kindpats: 506 for kind, pat, source in kindpats:
501 if kind in ('glob', 're', 'relglob', 'relre', 'set'): 507 if kind in ('glob', 're', 'relglob', 'relre', 'set'):
502 return True 508 return True
503 509
504 _commentre = None 510 _commentre = None
505 511