Patchwork match: adding support for repository-root-based globs

login
register
mail settings
Submitter via Mercurial-devel
Date Nov. 15, 2016, 4:59 a.m.
Message ID <93434cce258a797fcc39.1479185949@rdamazio.mtv.corp.google.com>
Download mbox | patch
Permalink /patch/17583/
State Changes Requested
Headers show

Comments

via Mercurial-devel - Nov. 15, 2016, 4:59 a.m.
# HG changeset patch
# User Rodrigo Damazio Bovendorp <rdamazio@google.com>
# 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:
Pierre-Yves David - Nov. 15, 2016, 2:21 p.m.
On 11/15/2016 04:59 AM, Rodrigo Damazio Bovendorp via Mercurial-devel wrote:
> # HG changeset patch
> # User Rodrigo Damazio Bovendorp <rdamazio@google.com>
> # Date 1475944120 25200
> #      Sat Oct 08 09:28:40 2016 -0700
> # Node ID 93434cce258a797fcc3997c0af994a524695e273
> # Parent  b032a7b676c6637b2ac6f3ef29431013b15a08f9
> match: adding support for repository-root-based globs

I saw that Foozy created a plan page about this, it seem to have good 
summary of the current matcher we have but from my reading it is a bit 
fuzzy about the current variation we have in behavior from one command 
to another and from flag usage. I think it is important to have a global 
view of the situation here to be able to efficiently tackle the issues 
at hand.

I'm traveling in Marocco with poor internet connectivity until the end 
of the week. I would prefer if we could not take a final discussion 
until I've time to discuss it more at the beginning of next week. Sorry 
for the extra delay.

> 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:<glob>' - a glob relative to cwd
>          're:<regexp>' - a regular expression
>          'path:<path>' - a path relative to repository root
> +        'rootglob:<path>' - a glob relative to repository root. Unlike glob, *
> +                            will never match subdirectories.
>          'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
>          'relpath:<path>' - a path relative to cwd
>          'relre:<regexp>' - 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
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@mercurial-scm.org
> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>
via Mercurial-devel - Nov. 24, 2016, 3:54 a.m.
Pierre-Yves, hope you had a great time in Morocco :) Any other comments
here?


On Tue, Nov 15, 2016 at 6:21 AM, Pierre-Yves David <
pierre-yves.david@ens-lyon.org> wrote:

>
>
> On 11/15/2016 04:59 AM, Rodrigo Damazio Bovendorp via Mercurial-devel
> wrote:
>
>> # HG changeset patch
>> # User Rodrigo Damazio Bovendorp <rdamazio@google.com>
>> # Date 1475944120 25200
>> #      Sat Oct 08 09:28:40 2016 -0700
>> # Node ID 93434cce258a797fcc3997c0af994a524695e273
>> # Parent  b032a7b676c6637b2ac6f3ef29431013b15a08f9
>> match: adding support for repository-root-based globs
>>
>
> I saw that Foozy created a plan page about this, it seem to have good
> summary of the current matcher we have but from my reading it is a bit
> fuzzy about the current variation we have in behavior from one command to
> another and from flag usage. I think it is important to have a global view
> of the situation here to be able to efficiently tackle the issues at hand.
>
> I'm traveling in Marocco with poor internet connectivity until the end of
> the week. I would prefer if we could not take a final discussion until I've
> time to discuss it more at the beginning of next week. Sorry for the extra
> delay.
>
> 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:<glob>' - a glob relative to cwd
>>          're:<regexp>' - a regular expression
>>          'path:<path>' - a path relative to repository root
>> +        'rootglob:<path>' - a glob relative to repository root. Unlike
>> glob, *
>> +                            will never match subdirectories.
>>          'relglob:<glob>' - an unrooted glob (*.c matches C files in all
>> dirs)
>>          'relpath:<path>' - a path relative to cwd
>>          'relre:<regexp>' - 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
>> _______________________________________________
>> Mercurial-devel mailing list
>> Mercurial-devel@mercurial-scm.org
>> https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>>
>>
> --
> Pierre-Yves David
>
Pierre-Yves David - Nov. 24, 2016, 10:05 a.m.
On 11/24/2016 04:54 AM, Rodrigo Damazio wrote:
> Pierre-Yves, hope you had a great time in Morocco :)

I had,

> Any other comments here?

Yep, I'll start a thread about the Plan page soon, this topic is now on 
the tip of my "complex discussion" stack and unless Denmark is hit by an 
asteroid I should post something later today.

> On Tue, Nov 15, 2016 at 6:21 AM, Pierre-Yves David
> <pierre-yves.david@ens-lyon.org <mailto:pierre-yves.david@ens-lyon.org>>
> wrote:
>
>
>
>     On 11/15/2016 04:59 AM, Rodrigo Damazio Bovendorp via
>     Mercurial-devel wrote:
>
>         # HG changeset patch
>         # User Rodrigo Damazio Bovendorp <rdamazio@google.com
>         <mailto:rdamazio@google.com>>
>         # Date 1475944120 <tel:1475944120> 25200
>         #      Sat Oct 08 09:28:40 2016 -0700
>         # Node ID 93434cce258a797fcc3997c0af994a524695e273
>         # Parent  b032a7b676c6637b2ac6f3ef29431013b15a08f9
>         match: adding support for repository-root-based globs
>
>
>     I saw that Foozy created a plan page about this, it seem to have
>     good summary of the current matcher we have but from my reading it
>     is a bit fuzzy about the current variation we have in behavior from
>     one command to another and from flag usage. I think it is important
>     to have a global view of the situation here to be able to
>     efficiently tackle the issues at hand.
>
>     I'm traveling in Marocco with poor internet connectivity until the
>     end of the week. I would prefer if we could not take a final
>     discussion until I've time to discuss it more at the beginning of
>     next week. Sorry for the extra delay.
>
>         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:<glob>' - a glob relative to cwd
>                  're:<regexp>' - a regular expression
>                  'path:<path>' - a path relative to repository root
>         +        'rootglob:<path>' - a glob relative to repository root.
>         Unlike glob, *
>         +                            will never match subdirectories.
>                  'relglob:<glob>' - an unrooted glob (*.c matches C
>         files in all dirs)
>                  'relpath:<path>' - a path relative to cwd
>                  'relre:<regexp>' - 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
>         _______________________________________________
>         Mercurial-devel mailing list
>         Mercurial-devel@mercurial-scm.org
>         <mailto:Mercurial-devel@mercurial-scm.org>
>         https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel
>         <https://www.mercurial-scm.org/mailman/listinfo/mercurial-devel>
>
>
>     --
>     Pierre-Yves David
>
>

Patch

============ ======== ======= ===========
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:<glob>' - a glob relative to cwd
         're:<regexp>' - a regular expression
         'path:<path>' - a path relative to repository root
+        'rootglob:<path>' - a glob relative to repository root. Unlike glob, *
+                            will never match subdirectories.
         'relglob:<glob>' - an unrooted glob (*.c matches C files in all dirs)
         'relpath:<path>' - a path relative to cwd
         'relre:<regexp>' - 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