[PATCH 3 of 3 V3] templater: introduce {latesttag()} function to match a pattern (issue4184)

Yuya Nishihara yuya at tcha.org
Mon Aug 24 08:18:12 CDT 2015


On Mon, 24 Aug 2015 00:54:20 -0400, Matt Harbison wrote:
> # HG changeset patch
> # User Matt Harbison <matt_harbison at yahoo.com>
> # Date 1440387898 14400
> #      Sun Aug 23 23:44:58 2015 -0400
> # Node ID 34d52e2098ee7f9a4e4402ebdd343525f0ed3e18
> # Parent  1a83ed3de651a4b5959f367d647ca5f693dbb234
> templater: introduce {latesttag()} function to match a pattern (issue4184)
> 
> This allows the latest class of tag to be found, such as a release candidate or
> final build, instead of just the absolute latest.
> 
> It doesn't appear that the existing keyword can be given an optional argument.
> There is a keyword, function and filter for 'date', so it doesn't seem harmful
> to introduce a new function with the same name as an existing keyword.  Most
> functions are pretty Mercurial agnostic, but there is {revset()} as precedent.
> 
> Even though templatekw.getlatesttags() returns a single tuple, one entry of
> which is a list, it is simplest to present this as a list of tags instead of a
> single item, with each tag having a distance and change count attribute.  It is
> also closer to how {latesttag} returns a list of tags, and how this function
> works when not given a '%' operator.
> 
> diff --git a/mercurial/help/templates.txt b/mercurial/help/templates.txt
> --- a/mercurial/help/templates.txt
> +++ b/mercurial/help/templates.txt
> @@ -98,6 +98,10 @@
>  
>     $ hg log --template "{bookmarks % '{bookmark}{ifeq(bookmark, active, '*')} '}\n"
>  
> +- Find the previous release candidate tag, the distance and changes since the tag::
> +
> +   $ hg log -r . --template "{latesttag('re:^.*-rc$') % '{tag}, {changes}, {distance}'}\n"

I think "{latesttag % '{tag}, {changes}...'}" should be possible as well.
Perhaps it will need a helper function like templatekw.shownames().

>     $ hg log --template "{ifcontains(rev, revset('.'), '@')}\n"
> diff --git a/mercurial/templater.py b/mercurial/templater.py
> --- a/mercurial/templater.py
> +++ b/mercurial/templater.py
> @@ -510,6 +510,44 @@
>      # ignore args[0] (the label string) since this is supposed to be a a no-op
>      yield args[1][0](context, mapping, args[1][1])
>  
> +def latesttag(context, mapping, args):
> +    """:latesttag([pattern]): The global tags matching the given pattern on the
> +    most recent globally tagged ancestor of this changeset."""
> +    if len(args) > 1:
> +        # i18n: "latesttag" is a keyword
> +        raise error.ParseError(_("latesttag expects at most one argument"))
> +
> +    pattern = None
> +    if len(args) == 1:
> +        pattern = stringify(args[0][0](context, mapping, args[0][1]))
> +
> +    repo, ctx = mapping['repo'], mapping['ctx']
> +    cache = mapping['cache']
> +    latesttags = templatekw.getlatesttags(repo, ctx, cache, pattern)
> +
> +    def changes(tag):
> +        offset = 0
> +        revs = [ctx.rev()]
> +
> +        # The only() revset doesn't currently support wdir()
> +        if ctx.rev() is None:
> +            offset = 1
> +            revs = [p.rev() for p in ctx.parents()]
> +
> +        return len(repo.revs('only(%ld, %s)', revs, tag)) + offset
> +
> +    makemap = lambda v: {
> +        'changes': changes(v),

Because changes() is slow, it should be delayed. makemap() can have a
callable that implements the same interface as templatekw.showxxx() functions.
See templater.runmap() and runsymbol().

> +        # Not the date the tag was applied, but not much we can do about that
> +        #'commitdate': util.makedate(latesttags[0]),
> +        'distance': latesttags[1],
> +        'tag': v
> +    }
> +
> +    tags = latesttags[2]
> +    f = templatekw._showlist('latesttag', tags, separator=':', **mapping)
> +    return templatekw._hybrid(f, tags, makemap, lambda x: x['latesttag'])

Typo of x['tag'] ?

  % hg log -T '{join(latesttag(), " ")}\n'
  abort: template: no key named 'latesttag'


More information about the Mercurial-devel mailing list