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

Gilles Moris gilles.moris at free.fr
Tue Aug 11 03:08:11 CDT 2009


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


# HG changeset patch
# User Gilles Moris <gilles.moris at free.fr>
# Date 1247087563 -7200
# Node ID aa102afa2e7b61a2d09b71ff8916397b1de8456a
# Parent  5873efc191a3a0a66be55c94224d669153f65228
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
@@ -731,6 +731,29 @@
                 parents = [parents[0]]
         return parents
 
+def computelasttagmap(repo):
+    '''compute 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(repo)
+
+    for r in range(len(repo)):
+        ctx = repo[r]
+
+        tags = [t for t in ctx.tags() if 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
 
 class changeset_templater(changeset_printer):
     '''format changeset information.'''
@@ -744,6 +767,10 @@
                                          'manifest': '{rev}:{node|formatnode}',
                                          'filecopy': '{name} ({source})'})
 
+    @util.propertycache
+    def lasttagmap(self):
+        return computelasttagmap(self.repo)
+
     def use_template(self, t):
         '''set template string to use'''
         self.t.cache['changeset'] = t
@@ -877,6 +904,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 +926,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
@@ -393,6 +393,9 @@
                 number.
     :tags:      List of strings. Any tags associated with the
                 changeset.
+    :lasttag:   String. Most recent global tag in the ancestors of this
+                changeset.
+    :lasttagdistance: Integer. Longest path to the last tag.
 
     The "date" keyword does not produce human-readable output. If you
     want to use a date in your output, you can use a filter to process
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