From patchwork Tue Nov 15 04:59:09 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: match: adding support for repository-root-based globs From: via Mercurial-devel X-Patchwork-Id: 17583 Message-Id: <93434cce258a797fcc39.1479185949@rdamazio.mtv.corp.google.com> To: mercurial-devel@mercurial-scm.org Date: Mon, 14 Nov 2016 20:59:09 -0800 # HG changeset patch # User Rodrigo Damazio Bovendorp # Date 1475944120 25200 # Sat Oct 08 09:28:40 2016 -0700 # Node ID 93434cce258a797fcc3997c0af994a524695e273 # Parent b032a7b676c6637b2ac6f3ef29431013b15a08f9 match: adding support for repository-root-based globs The broader plan is to add explicit base directories for all patterns: ============ ======== ======= =========== pattern type root-ed cwd-ed any-of-path ============ ======== ======= =========== wildcard rootglob cwdglob anyglob regexp rootre cwdre anyre raw string rootpath cwdpath anypath ============ ======== ======= =========== (table by foozy) I'm starting by adding rootglob. One important characteristic and difference from the older glob types is that rootglob does a *full* match, meaning that a * at the end will never match recursively, even when the glob is used as an include pattern. diff -r b032a7b676c6 -r 93434cce258a mercurial/help/patterns.txt --- a/mercurial/help/patterns.txt Tue Nov 01 18:54:03 2016 -0700 +++ b/mercurial/help/patterns.txt Sat Oct 08 09:28:40 2016 -0700 @@ -40,6 +40,11 @@ ``-I`` or ``-X`` options), can match also against directories: files under matched directories are treated as matched. +For ``-I`` and ``-X`` options, ``glob:`` will match directories recursively. +``rootglob:``, on the other end, does a full match, meaning that all files, in +directories or subdirectories, will only match if the entire expression matches. +In that case, ``**`` can be used to obtain recursiveness. + Plain examples:: path:foo/bar a name bar in a directory named foo in the root @@ -48,13 +53,18 @@ Glob examples:: - glob:*.c any name ending in ".c" in the current directory - *.c any name ending in ".c" in the current directory - **.c any name ending in ".c" in any subdirectory of the - current directory including itself. - foo/*.c any name ending in ".c" in the directory foo - foo/**.c any name ending in ".c" in any subdirectory of foo - including itself. + glob:*.c any name ending in ".c" in the current directory + *.c any name ending in ".c" in the current directory + **.c any name ending in ".c" in any subdirectory of the + current directory including itself. + foo/* any file in directory foo plus all its subdirectories, + recursively + foo/*.c any name ending in ".c" in the directory foo + foo/**.c any name ending in ".c" in any subdirectory of foo + including itself. + rootglob:*.c any name ending in ".c" in the repository root + rootglob:foo/* all files inside foo but not its subdirectories + rootglob:foo/** all files inside foo and its subdirectories Regexp examples:: diff -r b032a7b676c6 -r 93434cce258a mercurial/match.py --- a/mercurial/match.py Tue Nov 01 18:54:03 2016 -0700 +++ b/mercurial/match.py Sat Oct 08 09:28:40 2016 -0700 @@ -105,6 +105,8 @@ 'glob:' - a glob relative to cwd 're:' - a regular expression 'path:' - a path relative to repository root + 'rootglob:' - a glob relative to repository root. Unlike glob, * + will never match subdirectories. 'relglob:' - an unrooted glob (*.c matches C files in all dirs) 'relpath:' - a path relative to cwd 'relre:' - a regexp that needn't match the start of a name @@ -286,7 +288,7 @@ for kind, pat in [_patsplit(p, default) for p in patterns]: if kind in ('glob', 'relpath'): pat = pathutil.canonpath(root, cwd, pat, auditor) - elif kind in ('relglob', 'path'): + elif kind in ('relglob', 'path', 'rootglob'): pat = util.normpath(pat) elif kind in ('listfile', 'listfile0'): try: @@ -447,7 +449,8 @@ if ':' in pattern: kind, pat = pattern.split(':', 1) if kind in ('re', 'glob', 'path', 'relglob', 'relpath', 'relre', - 'listfile', 'listfile0', 'set', 'include', 'subinclude'): + 'listfile', 'listfile0', 'set', 'include', 'subinclude', + 'rootglob'): return kind, pat return default, pattern @@ -540,6 +543,8 @@ if pat == '.': return '' return '^' + util.re.escape(pat) + '(?:/|$)' + if kind == 'rootglob': + return '^' + _globre(pat) + '$' if kind == 'relglob': return '(?:|.*/)' + _globre(pat) + globsuffix if kind == 'relpath': @@ -614,6 +619,8 @@ >>> _roots([('glob', 'g/*', ''), ('glob', 'g', ''), ('glob', 'g*', '')]) ['g', 'g', '.'] + >>> _roots([('rootglob', 'g/*', ''), ('rootglob', 'g', '')]) + ['g', 'g'] >>> _roots([('relpath', 'r', ''), ('path', 'p/p', ''), ('path', '', '')]) ['r', 'p/p', '.'] >>> _roots([('relglob', 'rg*', ''), ('re', 're/', ''), ('relre', 'rr', '')]) @@ -621,7 +628,7 @@ ''' r = [] for kind, pat, source in kindpats: - if kind == 'glob': # find the non-glob prefix + if kind == 'glob' or kind == 'rootglob': # find the non-glob prefix root = [] for p in pat.split('/'): if '[' in p or '{' in p or '*' in p or '?' in p: @@ -636,7 +643,7 @@ def _anypats(kindpats): for kind, pat, source in kindpats: - if kind in ('glob', 're', 'relglob', 'relre', 'set'): + if kind in ('glob', 're', 'relglob', 'relre', 'set', 'rootglob'): return True _commentre = None diff -r b032a7b676c6 -r 93434cce258a tests/test-walk.t --- a/tests/test-walk.t Tue Nov 01 18:54:03 2016 -0700 +++ b/tests/test-walk.t Sat Oct 08 09:28:40 2016 -0700 @@ -112,6 +112,69 @@ f beans/navy ../beans/navy f beans/pinto ../beans/pinto f beans/turtle ../beans/turtle + + $ hg debugwalk -I 'rootglob:*' + f fennel ../fennel + f fenugreek ../fenugreek + f fiddlehead ../fiddlehead + $ hg debugwalk -I 'rootglob:sk*nk' + $ hg debugwalk 'rootglob:sk*nk' + $ hg debugwalk -I 'rootglob:*k' + f fenugreek ../fenugreek + $ hg debugwalk -I 'rootglob:mammals/*' + f mammals/skunk skunk + $ hg debugwalk 'rootglob:mammals/*' + f mammals/skunk skunk + $ hg debugwalk -I 'rootglob:**/*u*' + f beans/turtle ../beans/turtle + f fenugreek ../fenugreek + f mammals/Procyonidae/coatimundi Procyonidae/coatimundi + f mammals/skunk skunk + $ hg debugwalk -I 'rootglob:mammals/**' + f mammals/Procyonidae/cacomistle Procyonidae/cacomistle + f mammals/Procyonidae/coatimundi Procyonidae/coatimundi + f mammals/Procyonidae/raccoon Procyonidae/raccoon + f mammals/skunk skunk + $ hg debugwalk -I 'rootglob:*a*/*u*' + f beans/turtle ../beans/turtle + f mammals/skunk skunk + $ hg debugwalk 'rootglob:*a*/*u*' + f beans/turtle ../beans/turtle + f mammals/skunk skunk + $ hg debugwalk -X 'rootglob:mammals/*' + f beans/black ../beans/black + f beans/borlotti ../beans/borlotti + f beans/kidney ../beans/kidney + f beans/navy ../beans/navy + f beans/pinto ../beans/pinto + f beans/turtle ../beans/turtle + f fennel ../fennel + f fenugreek ../fenugreek + f fiddlehead ../fiddlehead + f mammals/Procyonidae/cacomistle Procyonidae/cacomistle + f mammals/Procyonidae/coatimundi Procyonidae/coatimundi + f mammals/Procyonidae/raccoon Procyonidae/raccoon + $ hg debugwalk -X 'rootglob:mammals/**' + f beans/black ../beans/black + f beans/borlotti ../beans/borlotti + f beans/kidney ../beans/kidney + f beans/navy ../beans/navy + f beans/pinto ../beans/pinto + f beans/turtle ../beans/turtle + f fennel ../fennel + f fenugreek ../fenugreek + f fiddlehead ../fiddlehead + $ hg debugwalk -X 'rootglob:**/*u*' + f beans/black ../beans/black + f beans/borlotti ../beans/borlotti + f beans/kidney ../beans/kidney + f beans/navy ../beans/navy + f beans/pinto ../beans/pinto + f fennel ../fennel + f fiddlehead ../fiddlehead + f mammals/Procyonidae/cacomistle Procyonidae/cacomistle + f mammals/Procyonidae/raccoon Procyonidae/raccoon + $ hg debugwalk . f mammals/Procyonidae/cacomistle Procyonidae/cacomistle f mammals/Procyonidae/coatimundi Procyonidae/coatimundi