[PATCH] templates: add {lasttag} and {lasttagdistance} keywords

Gilles Moris gilles.moris at free.fr
Tue Jul 21 16:53:19 CDT 2009


 mercurial/cmdutil.py            |  32 ++++++++++++++++
 mercurial/help.py               |   3 +
 tests/test-command-template     |  45 ++++++++++++++++++++++
 tests/test-command-template.out |  51 +++++++++++++++++++++++++
 4 files changed, 131 insertions(+), 0 deletions(-)


# HG changeset patch
# User Gilles Moris <gilles.moris at free.fr>
# Date 1247087563 -7200
# Node ID fd4f84152d1377dca859abf600aff978960991ff
# Parent  051a8528f56c3e7b6516ab3fa7d35b9b6602ed43
templates: add {lasttag} and {lasttagdistance} keywords.

Useful to build nightly version names and see on which tag a rev is based on.

Among tag ancestors, the one with the latest date, or with the longuest path if
there are multiple pathes to the same tag, is chosen.
This way, lasttag does not depend on the push/pull order and matches the
user's expectation, in particular in the case of a backout merge.
Only global tags are considered. The local tags (including 'tip' and automatic
MQ tags) are discarded.

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -744,6 +744,31 @@
                                          'manifest': '{rev}:{node|formatnode}',
                                          'filecopy': '{name} ({source})'})
 
+    @util.propertycache
+    def lasttagmap(self):
+        '''get an array[rev] of latest global tag tuple, each tuple being
+        (date of the latest tag, distance to that tag, the tag(s)).
+        '''
+        defvalue = 0, 0, 'null'
+        ltmap = [defvalue] * len(self.repo)
+
+        for r in range(len(self.repo)):
+            ctx = self.repo[r]
+
+            tags = [t for t in ctx.tags() if self.repo.tagtype(t) == 'global']
+            if tags:
+                ltmap[r] = ctx.date(), 0, '='.join(sorted(tags))
+            else:
+                # the last tag of this rev comes from the ancestor with the
+                # latest tag (secondarily the longest distance to the tag),
+                # achieved by comparing the tuples.
+                ldate, ldist, ltag = max(
+                    p.rev() >= 0 and ltmap[p.rev()] or defvalue
+                    for p in ctx.parents())
+                ltmap[r] = ldate, ldist + 1, ltag
+
+        return ltmap
+
     def use_template(self, t):
         '''set template string to use'''
         self.t.cache['changeset'] = t
@@ -877,6 +902,11 @@
                 removes += i[2]
             return '%s: +%s/-%s' % (files, adds, removes)
 
+        def showlasttag(**args):
+            return self.lasttagmap[ctx.rev()][2]
+        def showlasttagdistance(**args):
+            return self.lasttagmap[ctx.rev()][1]
+
         defprops = {
             'author': ctx.user(),
             'branches': showbranches,
@@ -894,6 +924,8 @@
             'tags': showtags,
             'extras': showextras,
             'diffstat': showdiffstat,
+            'lasttag': showlasttag,
+            'lasttagdistance': showlasttagdistance,
             }
         props = props.copy()
         props.update(defprops)
diff --git a/mercurial/help.py b/mercurial/help.py
--- a/mercurial/help.py
+++ b/mercurial/help.py
@@ -372,6 +372,9 @@
     - file_adds: List of strings. Files added by this changeset.
     - file_mods: List of strings. Files modified by this changeset.
     - file_dels: List of strings. Files removed by this changeset.
+    - lasttag: String. Most recent global tag in the ancestors of this
+          changeset.
+    - lasttagdistance: Integer. Longest path to the last tag.
     - node: String. The changeset identification hash, as a 40-character
       hexadecimal string.
     - parents: List of strings. The parents of the changeset.
diff --git a/tests/test-command-template b/tests/test-command-template
--- a/tests/test-command-template
+++ b/tests/test-command-template
@@ -127,4 +127,49 @@
 echo 'x = "f' >> t
 hg log
 
+cd ..
+
+echo '# lasttag'
+hg init lasttag
+cd lasttag
+
+echo a > file
+hg ci -Am a -d '0 0'
+
+echo b >> file
+hg ci -m b -d '1 0'
+
+echo c >> head1
+hg ci -Am h1c -d '2 0'
+
+hg update -q 1
+echo d >> head2
+hg ci -Am h2d -d '3 0'
+
+echo e >> head2
+hg ci -m h2e -d '4 0'
+
+hg merge -q
+hg ci -m merge -d '5 0'
+
+echo '# No tag set'
+hg log --template '{rev}: {lasttag}+{lasttagdistance}\n'
+
+echo '# one common tag: longuest path wins'
+hg tag -r 1 -m t1 -d '6 0' t1
+hg log --template '{rev}: {lasttag}+{lasttagdistance}\n'
+
+echo '# one ancestor tag: more recent wins'
+hg tag -r 2 -m t2 -d '7 0' t2
+hg log --template '{rev}: {lasttag}+{lasttagdistance}\n'
+
+echo '# two branch tags: more recent wins'
+hg tag -r 3 -m t3 -d '8 0' t3
+hg log --template '{rev}: {lasttag}+{lasttagdistance}\n'
+
+echo '# merged tag overrides'
+hg tag -r 5 -m t5 -d '9 0' t5
+hg tag -r 3 -m at3 -d '10 0' at3
+hg log --template '{rev}: {lasttag}+{lasttagdistance}\n'
+
 echo '# done'
diff --git a/tests/test-command-template.out b/tests/test-command-template.out
--- a/tests/test-command-template.out
+++ b/tests/test-command-template.out
@@ -672,4 +672,55 @@
 1e4e1b8f71e05681d422154f5421e385fec3454f
 # error on syntax
 abort: t:3: unmatched quotes
+# lasttag
+adding file
+adding head1
+adding head2
+created new head
+# No tag set
+5: null+5
+4: null+4
+3: null+3
+2: null+3
+1: null+2
+0: null+1
+# one common tag: longuest path wins
+6: t1+4
+5: t1+3
+4: t1+2
+3: t1+1
+2: t1+1
+1: t1+0
+0: null+1
+# one ancestor tag: more recent wins
+7: t2+3
+6: t2+2
+5: t2+1
+4: t1+2
+3: t1+1
+2: t2+0
+1: t1+0
+0: null+1
+# two branch tags: more recent wins
+8: t3+5
+7: t3+4
+6: t3+3
+5: t3+2
+4: t3+1
+3: t3+0
+2: t2+0
+1: t1+0
+0: null+1
+# merged tag overrides
+10: t5+5
+9: t5+4
+8: t5+3
+7: t5+2
+6: t5+1
+5: t5+0
+4: at3=t3+1
+3: at3=t3+0
+2: t2+0
+1: t1+0
+0: null+1
 # done


More information about the Mercurial-devel mailing list