Mercurial > hg
comparison mercurial/match.py @ 25283:19d0e5efa6ca
match: enable 'subinclude:' syntax
This adds a new rule syntax that allows the user to include a pattern file, but
only have those patterns match against files underneath the subdirectory of the
pattern file.
This is useful when you have nested projects in a repository and the inner
projects wants to set up ignore rules that won't affect other projects in the
repository. It is also useful in high commit rate repositories for removing the
root .hgignore as a point of contention.
author | Durham Goode <durham@fb.com> |
---|---|
date | Sat, 16 May 2015 16:25:05 -0700 |
parents | f9a29dc964a3 |
children | caaf4045eca8 |
comparison
equal
deleted
inserted
replaced
25282:0f28815ef066 | 25283:19d0e5efa6ca |
---|---|
40 | 40 |
41 continue | 41 continue |
42 other.append((kind, pat, source)) | 42 other.append((kind, pat, source)) |
43 return fset, other | 43 return fset, other |
44 | 44 |
45 def _expandsubinclude(kindpats, root): | |
46 '''Returns the list of subinclude matchers and the kindpats without the | |
47 subincludes in it.''' | |
48 relmatchers = [] | |
49 other = [] | |
50 | |
51 for kind, pat, source in kindpats: | |
52 if kind == 'subinclude': | |
53 sourceroot = pathutil.dirname(source) | |
54 pat = util.pconvert(pat) | |
55 path = pathutil.join(sourceroot, pat) | |
56 | |
57 newroot = pathutil.dirname(path) | |
58 relmatcher = match(newroot, '', [], ['include:%s' % path]) | |
59 | |
60 prefix = pathutil.canonpath(root, root, newroot) | |
61 if prefix: | |
62 prefix += '/' | |
63 relmatchers.append((prefix, relmatcher)) | |
64 else: | |
65 other.append((kind, pat, source)) | |
66 | |
67 return relmatchers, other | |
68 | |
45 def _kindpatsalwaysmatch(kindpats): | 69 def _kindpatsalwaysmatch(kindpats): |
46 """"Checks whether the kindspats match everything, as e.g. | 70 """"Checks whether the kindspats match everything, as e.g. |
47 'relpath:.' does. | 71 'relpath:.' does. |
48 """ | 72 """ |
49 for kind, pat, source in kindpats: | 73 for kind, pat, source in kindpats: |
74 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs) | 98 'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs) |
75 'relpath:<path>' - a path relative to cwd | 99 'relpath:<path>' - a path relative to cwd |
76 'relre:<regexp>' - a regexp that needn't match the start of a name | 100 'relre:<regexp>' - a regexp that needn't match the start of a name |
77 'set:<fileset>' - a fileset expression | 101 'set:<fileset>' - a fileset expression |
78 'include:<path>' - a file of patterns to read and include | 102 'include:<path>' - a file of patterns to read and include |
103 'subinclude:<path>' - a file of patterns to match against files under | |
104 the same directory | |
79 '<something>' - a pattern of the specified default type | 105 '<something>' - a pattern of the specified default type |
80 """ | 106 """ |
81 | 107 |
82 self._root = root | 108 self._root = root |
83 self._cwd = cwd | 109 self._cwd = cwd |
373 """Split a string into the optional pattern kind prefix and the actual | 399 """Split a string into the optional pattern kind prefix and the actual |
374 pattern.""" | 400 pattern.""" |
375 if ':' in pattern: | 401 if ':' in pattern: |
376 kind, pat = pattern.split(':', 1) | 402 kind, pat = pattern.split(':', 1) |
377 if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre', | 403 if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre', |
378 'listfile', 'listfile0', 'set', 'include'): | 404 'listfile', 'listfile0', 'set', 'include', 'subinclude'): |
379 return kind, pat | 405 return kind, pat |
380 return default, pattern | 406 return default, pattern |
381 | 407 |
382 def _globre(pat): | 408 def _globre(pat): |
383 r'''Convert an extended glob string to a regexp string. | 409 r'''Convert an extended glob string to a regexp string. |
479 def _buildmatch(ctx, kindpats, globsuffix, listsubrepos, root): | 505 def _buildmatch(ctx, kindpats, globsuffix, listsubrepos, root): |
480 '''Return regexp string and a matcher function for kindpats. | 506 '''Return regexp string and a matcher function for kindpats. |
481 globsuffix is appended to the regexp of globs.''' | 507 globsuffix is appended to the regexp of globs.''' |
482 matchfuncs = [] | 508 matchfuncs = [] |
483 | 509 |
510 subincludes, kindpats = _expandsubinclude(kindpats, root) | |
511 if subincludes: | |
512 def matchsubinclude(f): | |
513 for prefix, mf in subincludes: | |
514 if f.startswith(prefix) and mf(f[len(prefix):]): | |
515 return True | |
516 return False | |
517 matchfuncs.append(matchsubinclude) | |
518 | |
484 fset, kindpats = _expandsets(kindpats, ctx, listsubrepos) | 519 fset, kindpats = _expandsets(kindpats, ctx, listsubrepos) |
485 if fset: | 520 if fset: |
486 matchfuncs.append(fset.__contains__) | 521 matchfuncs.append(fset.__contains__) |
487 | 522 |
488 regex = '' | 523 regex = '' |
575 re:pattern # non-rooted regular expression | 610 re:pattern # non-rooted regular expression |
576 glob:pattern # non-rooted glob | 611 glob:pattern # non-rooted glob |
577 pattern # pattern of the current default type''' | 612 pattern # pattern of the current default type''' |
578 | 613 |
579 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:', | 614 syntaxes = {'re': 'relre:', 'regexp': 'relre:', 'glob': 'relglob:', |
580 'include': 'include'} | 615 'include': 'include', 'subinclude': 'subinclude'} |
581 syntax = 'relre:' | 616 syntax = 'relre:' |
582 patterns = [] | 617 patterns = [] |
583 | 618 |
584 fp = open(filepath) | 619 fp = open(filepath) |
585 for line in fp: | 620 for line in fp: |