Patchwork [RFC,V2] templater: introduce latesttag() function to match a pattern (issue4184)

login
register
mail settings
Submitter Matt Harbison
Date Aug. 23, 2015, 8:50 p.m.
Message ID <7635dd2e59810eaf75ef.1440363049@Envy>
Download mbox | patch
Permalink /patch/10265/
State Superseded
Headers show

Comments

Matt Harbison - Aug. 23, 2015, 8:50 p.m.
# HG changeset patch
# User Matt Harbison <matt_harbison@yahoo.com>
# Date 1440360913 14400
#      Sun Aug 23 16:15:13 2015 -0400
# Node ID 7635dd2e59810eaf75efdd5ba095b2c74f1e36f2
# Parent  d315fc51e187c70ee75964f7503b8780f1c95884
templater: introduce latesttag() function to match a pattern (issue4184)

This still requires the first patch from the previous version of this series.
Unlike the last series, this allows the tags, changessincelasttag and
latesttagdistance to be handled by this one function.

A couple of issues I've noticed, and can't figure out.

1) "{latesttag('re:^t[13]$')}" crashes.  It would be nice if there was a way to
   get it to show a list of tags in the same way {latesttags} does, as that's
   probably what most people would expect.

  File "c:\Users\Matt\Projects\hg\mercurial\commands.py", line 4652, in log
    displayer.show(ctx, copies=copies, matchfn=revmatchfn)
  File "c:\Users\Matt\Projects\hg\mercurial\cmdutil.py", line 1148, in show
    self._show(ctx, copies, matchfn, props)
  File "c:\Users\Matt\Projects\hg\mercurial\cmdutil.py", line 1473, in _show
    self.ui.write(templater.stringify(self.t(key, **props)))
  File "c:\Users\Matt\Projects\hg\mercurial\templatefilters.py", line 346, in stringify
    return "".join([stringify(t) for t in thing if t is not None])
  File "c:\Users\Matt\Projects\hg\mercurial\util.py", line 613, in increasingchunks
    for chunk in source:
  File "c:\Users\Matt\Projects\hg\mercurial\templater.py", line 762, in _flatten
    for j in _flatten(i):
  File "c:\Users\Matt\Projects\hg\mercurial\templater.py", line 755, in _flatten
    for i in thing:
  File "c:\Users\Matt\Projects\hg\mercurial\templatekw.py", line 91, in _showlist
    yield dict(v, **args)
TypeError: cannot convert dictionary update sequence element #0 to a sequence


2) It doesn't appear that lists on the RHS of % work.  I applied a bogus '3.4.5'
   tag to '3.4.2' in the hg repo.  This is the result:

   $ ../hg log -r tip  \
     -T "{latesttag('re:^\d\.\d\.\d$') % '{tags % \"{tag}, \"}, {distance}, {changes}\n'}"
   3.4.23.4.5, 336, 1105

   However, if 'tags' in makemap is replaced with the commented out code instead
   of just 'v[2]', it crashes:

  File "c:\Users\Matt\Projects\hg\mercurial\commands.py", line 4652, in log
    displayer.show(ctx, copies=copies, matchfn=revmatchfn)
  File "c:\Users\Matt\Projects\hg\mercurial\cmdutil.py", line 1148, in show
    self._show(ctx, copies, matchfn, props)
  File "c:\Users\Matt\Projects\hg\mercurial\cmdutil.py", line 1473, in _show
    self.ui.write(templater.stringify(self.t(key, **props)))
  File "c:\Users\Matt\Projects\hg\mercurial\templatefilters.py", line 346, in stringify
    return "".join([stringify(t) for t in thing if t is not None])
  File "c:\Users\Matt\Projects\hg\mercurial\util.py", line 613, in increasingchunks
    for chunk in source:
  File "c:\Users\Matt\Projects\hg\mercurial\templater.py", line 762, in _flatten
    for j in _flatten(i):
  File "c:\Users\Matt\Projects\hg\mercurial\templater.py", line 762, in _flatten
    for j in _flatten(i):
  File "c:\Users\Matt\Projects\hg\mercurial\templater.py", line 762, in _flatten
    for j in _flatten(i):
  File "c:\Users\Matt\Projects\hg\mercurial\templater.py", line 755, in _flatten
    for i in thing:
  File "c:\Users\Matt\Projects\hg\mercurial\templater.py", line 284, in runmap
    d = func(context, mapping, data)
  File "c:\Users\Matt\Projects\hg\mercurial\templater.py", line 240, in runsymbol
    return v(**mapping)
TypeError: __call__() got an unexpected keyword argument 'node'

3) The date is not the date the tag was applied, but the date of the commit that
   is tagged.  I'm not sure that the date is particularly useful, so I have no
   problem leaving it out.

Patch

diff --git a/mercurial/templatekw.py b/mercurial/templatekw.py
--- a/mercurial/templatekw.py
+++ b/mercurial/templatekw.py
@@ -122,14 +122,21 @@ 
         revcache['files'] = repo.status(ctx.p1(), ctx)[:3]
     return revcache['files']
 
-def getlatesttags(repo, ctx, cache):
+def getlatesttags(repo, ctx, cache, pattern=None):
     '''return date, distance and name for the latest tag of rev'''
 
-    if 'latesttags' not in cache:
+    cachename = 'latesttags'
+    if pattern is not None:
+        cachename += '-' + pattern
+        match = util.stringmatcher(pattern)[2]
+    else:
+        match = util.always
+
+    if cachename not in cache:
         # Cache mapping from rev to a tuple with tag date, tag
         # distance and tag name
-        cache['latesttags'] = {-1: (0, 0, ['null'])}
-    latesttags = cache['latesttags']
+        cache[cachename] = {-1: (0, 0, ['null'])}
+    latesttags = cache[cachename]
 
     rev = ctx.rev()
     todo = [rev]
@@ -139,7 +146,8 @@ 
             continue
         ctx = repo[rev]
         tags = [t for t in ctx.tags()
-                if (repo.tagtype(t) and repo.tagtype(t) != 'local')]
+                if (repo.tagtype(t) and repo.tagtype(t) != 'local'
+                    and match(t))]
         if tags:
             latesttags[rev] = ctx.date()[0], 0, [t for t in sorted(tags)]
             continue
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -551,6 +551,42 @@ 
 
     return minirst.format(text, style=style, keep=['verbose'])
 
+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 one argument"))
+
+    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[2][0]),
+        'distance': v[1],
+        # Not the date the tag was applied, but not much we can do about that
+        #'tagdate': util.makedate(v[0]),
+        'tags': v[2]#templatekw.showlist('tag', v[2], separator=':', **mapping),
+    }
+
+    latesttags = [latesttags]
+    f = templatekw._showlist('latesttag', latesttags, **mapping)
+    return templatekw._hybrid(f, latesttags, makemap, lambda x: x['latesttag'])
+
 def shortest(context, mapping, args):
     """:shortest(node, minlength=4): Obtain the shortest representation of
     a node."""
@@ -693,6 +729,7 @@ 
     "indent": indent,
     "join": join,
     "label": label,
+    "latesttag": latesttag,
     "pad": pad,
     "revset": revset,
     "rstdoc": rstdoc,
diff --git a/tests/test-command-template.t b/tests/test-command-template.t
--- a/tests/test-command-template.t
+++ b/tests/test-command-template.t
@@ -2681,6 +2681,19 @@ 
   1: t1+0
   0: null+1
 
+  $ hg log --template "{rev}: {latesttag('re:^t[13]$') % '{tags}, C: {changes}, D: {distance}'}\n"
+  10: t3, C: 8, D: 7
+  9: t3, C: 7, D: 6
+  8: t3, C: 6, D: 5
+  7: t3, C: 5, D: 4
+  6: t3, C: 4, D: 3
+  5: t3, C: 3, D: 2
+  4: t3, C: 1, D: 1
+  3: t3, C: 0, D: 0
+  2: t1, C: 1, D: 1
+  1: t1, C: 0, D: 0
+  0: null, C: 1, D: 1
+
   $ cd ..