[PATCH STABLE] revset: evaluate filesets against each revision for 'file()' (issue5778)

Yuya Nishihara yuya at tcha.org
Wed Jan 31 06:36:54 EST 2018


On Wed, 31 Jan 2018 00:14:27 -0500, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_harbison at yahoo.com>
> # Date 1517166539 18000
> #      Sun Jan 28 14:08:59 2018 -0500
> # Branch stable
> # Node ID 105a48b751a294a386c46d13041160f29e627aee
> # Parent  4ac443b8390179d22010fe49ea57e18ae44e48d4
> revset: evaluate filesets against each revision for 'file()' (issue5778)
> 
> After f2aeff8a87b6, the fileset was evaluated to a set of files against the
> working directory, and then those files were applied against each revision.  The
> result was nonsense.  For example, `hg log -r 'file("set:exec()")'` on the
> Mercurial repo listed revision 0 because it has the `hg` script, which is
> currently +x.  But that bit wasn't applied until revision 280 (which
> 'contains()' properly indicates).
> 
> This technique was borrowed from checkstatus(), which services adds(),
> modifies(), and removes(), so it seems safe enough.  The 'r=all()' is kind of a
> hack, but necessary because keying off 'r=None' changes the behavior of
> `hg log set:...` (test-largefiles-misc.t and test-fileset-generated.t drop
> current log output when keying off of 'r=None').  I'm not sure what the right
> behavior for that is (1fd352aa08fc explicitly enabled this behavior for
> graphlog), but the day before the release isn't the time to experiment.
> 
> diff --git a/mercurial/revset.py b/mercurial/revset.py
> --- a/mercurial/revset.py
> +++ b/mercurial/revset.py
> @@ -1051,6 +1051,7 @@
>  
>      l = getargs(x, 1, -1, "_matchfiles requires at least one argument")
>      pats, inc, exc = [], [], []
> +    hasset = False
>      rev, default = None, None
>      for arg in l:
>          s = getstring(arg, "_matchfiles requires string arguments")
> @@ -1074,11 +1075,12 @@
>              default = value
>          else:
>              raise error.ParseError('invalid _matchfiles prefix: %s' % prefix)
> +        if not hasset and matchmod.patkind(value) == 'set':
> +            hasset = True

'r:'/'d:' values shouldn't be tested. I think it can be simply written as
any(patkind(p) == 'set' for p in pats + inc + exc).

>      if not default:
>          default = 'glob'
>  
> -    m = matchmod.match(repo.root, repo.getcwd(), pats, include=inc,
> -                       exclude=exc, ctx=repo[rev], default=default)
> +    mcache = [None]
>  
>      # This directly read the changelog data as creating changectx for all
>      # revisions is quite expensive.
> @@ -1089,6 +1091,16 @@
>              files = repo[x].files()
>          else:
>              files = getfiles(x)
> +
> +        if not mcache[0] or (hasset and rev == 'all()'):
> +            r = rev
> +            if rev == 'all()':
> +                r = x
> +            mcache[0] = matchmod.match(repo.root, repo.getcwd(), pats,
> +                                       include=inc, exclude=exc, ctx=repo[r],
> +                                       default=default)
> +        m = mcache[0]
> +
>          for f in files:
>              if m(f):
>                  return True
> @@ -1110,7 +1122,8 @@
>      """
>      # i18n: "file" is a keyword
>      pat = getstring(x, _("file requires a pattern"))
> -    return _matchfiles(repo, subset, ('string', 'p:' + pat))
> +    return _matchfiles(repo, subset, ('list', ('string', 'p:' + pat),
> +                                              ('string', 'r:all()')))

"all()" can be a valid revision label. Instead, maybe we can take rev=None
as an unspecified value, and parse 'r:' into rev=wdirrev.


More information about the Mercurial-devel mailing list