Mercurial > hg
comparison mercurial/minifileset.py @ 35741:73432eee0ac4
fileset: add kind:pat operator
":" isn't taken as a symbol character but an infix operator so we can write
e.g. "path:'foo bar'" as well as "'path:foo bar'". An invalid pattern kind
is rejected in the former form as we know a kind is specified explicitly.
The binding strength is copied from "x:y" range operator of revset. Perhaps
it can be adjusted later if we want to parse "foo:bar()" as "(foo:bar)()",
not "foo:(bar())". We can also add "kind:" postfix operator if we want.
One possible confusion is that the scope of the leading "set:" vs "kind:pat"
operator. The former is consumed by a matcher so applies to the whole fileset
expression:
$ hg files 'set:foo() or kind:bar or baz'
^^^^^^^^^^^^^^^^^^^^^^^^
Whereas the scope of kind:pat operator is narrow:
$ hg files 'set:foo() or kind:bar or baz'
^^^
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 14 Jan 2018 13:29:15 +0900 |
parents | 06a757b9e334 |
children | d5288b966e2f |
comparison
equal
deleted
inserted
replaced
35740:06a757b9e334 | 35741:73432eee0ac4 |
---|---|
15 | 15 |
16 def _compile(tree): | 16 def _compile(tree): |
17 if not tree: | 17 if not tree: |
18 raise error.ParseError(_("missing argument")) | 18 raise error.ParseError(_("missing argument")) |
19 op = tree[0] | 19 op = tree[0] |
20 if op in {'symbol', 'string'}: | 20 if op in {'symbol', 'string', 'kindpat'}: |
21 name = fileset.getstring(tree, _('invalid file pattern')) | 21 name = fileset.getpattern(tree, {'path'}, _('invalid file pattern')) |
22 if name.startswith('**'): # file extension test, ex. "**.tar.gz" | 22 if name.startswith('**'): # file extension test, ex. "**.tar.gz" |
23 ext = name[2:] | 23 ext = name[2:] |
24 for c in ext: | 24 for c in ext: |
25 if c in '*{}[]?/\\': | 25 if c in '*{}[]?/\\': |
26 raise error.ParseError(_('reserved character: %s') % c) | 26 raise error.ParseError(_('reserved character: %s') % c) |
27 return lambda n, s: n.endswith(ext) | 27 return lambda n, s: n.endswith(ext) |
28 # TODO: teach fileset about 'path:', so that this can be a symbol and | |
29 # not require quoting. | |
30 elif name.startswith('path:'): # directory or full path test | 28 elif name.startswith('path:'): # directory or full path test |
31 p = name[5:] # prefix | 29 p = name[5:] # prefix |
32 pl = len(p) | 30 pl = len(p) |
33 f = lambda n, s: n.startswith(p) and (len(n) == pl or n[pl] == '/') | 31 f = lambda n, s: n.startswith(p) and (len(n) == pl or n[pl] == '/') |
34 return f | 32 return f |
76 common logic operations, and parenthesis for grouping. The supported path | 74 common logic operations, and parenthesis for grouping. The supported path |
77 tests are '**.extname' for file extension test, and '"path:dir/subdir"' | 75 tests are '**.extname' for file extension test, and '"path:dir/subdir"' |
78 for prefix test. The ``size()`` predicate is borrowed from filesets to test | 76 for prefix test. The ``size()`` predicate is borrowed from filesets to test |
79 file size. The predicates ``all()`` and ``none()`` are also supported. | 77 file size. The predicates ``all()`` and ``none()`` are also supported. |
80 | 78 |
81 '(**.php & size(">10MB")) | **.zip | ("path:bin" & !"path:bin/README")' for | 79 '(**.php & size(">10MB")) | **.zip | (path:bin & !path:bin/README)' for |
82 example, will catch all php files whose size is greater than 10 MB, all | 80 example, will catch all php files whose size is greater than 10 MB, all |
83 files whose name ends with ".zip", and all files under "bin" in the repo | 81 files whose name ends with ".zip", and all files under "bin" in the repo |
84 root except for "bin/README". | 82 root except for "bin/README". |
85 """ | 83 """ |
86 tree = fileset.parse(text) | 84 tree = fileset.parse(text) |