cmdutil: templating keywords latesttag and latesttagdistance
This can be used for referring to revisions in a reasonable
meaningful, stable and monotonically increasing way, suitable for
releases or builds directly from a repository.
The latest tag is found by searching through untagged ancestors and
finding the latest tagged ancestor based on tag date. The distance is
found from the length of the longest path to the tagged revision.
For example:
hg log -l1 --template '{latesttag}+{latesttagdistance}\n'
can return
1.3.1+197
This is mostly work by Gilles Moris <gilles.moris@free.fr>
--- a/mercurial/cmdutil.py Sat Oct 03 23:38:10 2009 +0200
+++ b/mercurial/cmdutil.py Sat Oct 03 18:31:20 2009 +0200
@@ -745,6 +745,9 @@
'parent': '{rev}:{node|formatnode} ',
'manifest': '{rev}:{node|formatnode}',
'filecopy': '{name} ({source})'})
+ # Cache mapping from rev to a tuple with tag date, tag
+ # distance and tag name
+ self._latesttagcache = {-1: (0, 0, 'null')}
def use_template(self, t):
'''set template string to use'''
@@ -762,6 +765,30 @@
return []
return parents
+ def _latesttaginfo(self, rev):
+ '''return date, distance and name for the latest tag of rev'''
+ todo = [rev]
+ while todo:
+ rev = todo.pop()
+ if rev in self._latesttagcache:
+ continue
+ ctx = self.repo[rev]
+ tags = [t for t in ctx.tags() if self.repo.tagtype(t) == 'global']
+ if tags:
+ self._latesttagcache[rev] = ctx.date()[0], 0, ':'.join(sorted(tags))
+ continue
+ try:
+ # The tuples are laid out so the right one can be found by comparison.
+ pdate, pdist, ptag = max(
+ self._latesttagcache[p.rev()] for p in ctx.parents())
+ except KeyError:
+ # Cache miss - recurse
+ todo.append(rev)
+ todo.extend(p.rev() for p in ctx.parents())
+ continue
+ self._latesttagcache[rev] = pdate, pdist + 1, ptag
+ return self._latesttagcache[rev]
+
def _show(self, ctx, copies, props):
'''show a single changeset or file revision'''
@@ -879,6 +906,11 @@
removes += i[2]
return '%s: +%s/-%s' % (files, adds, removes)
+ def showlatesttag(**args):
+ return self._latesttaginfo(ctx.rev())[2]
+ def showlatesttagdistance(**args):
+ return self._latesttaginfo(ctx.rev())[1]
+
defprops = {
'author': ctx.user(),
'branches': showbranches,
@@ -896,6 +928,8 @@
'tags': showtags,
'extras': showextras,
'diffstat': showdiffstat,
+ 'latesttag': showlatesttag,
+ 'latesttagdistance': showlatesttagdistance,
}
props = props.copy()
props.update(defprops)
--- a/mercurial/help.py Sat Oct 03 23:38:10 2009 +0200
+++ b/mercurial/help.py Sat Oct 03 18:31:20 2009 +0200
@@ -393,6 +393,9 @@
number.
:tags: List of strings. Any tags associated with the
changeset.
+ :latesttag: String. Most recent global tag in the ancestors of this
+ changeset.
+ :latesttagdistance: Integer. Longest path to the latest 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
--- a/tests/test-command-template Sat Oct 03 23:38:10 2009 +0200
+++ b/tests/test-command-template Sat Oct 03 18:31:20 2009 +0200
@@ -127,4 +127,49 @@
echo 'x = "f' >> t
hg log
+cd ..
+
+echo '# latesttag'
+hg init latesttag
+cd latesttag
+
+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}: {latesttag}+{latesttagdistance}\n'
+
+echo '# one common tag: longuest path wins'
+hg tag -r 1 -m t1 -d '6 0' t1
+hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+
+echo '# one ancestor tag: more recent wins'
+hg tag -r 2 -m t2 -d '7 0' t2
+hg log --template '{rev}: {latesttag}+{latesttagdistance}\n'
+
+echo '# two branch tags: more recent wins'
+hg tag -r 3 -m t3 -d '8 0' t3
+hg log --template '{rev}: {latesttag}+{latesttagdistance}\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}: {latesttag}+{latesttagdistance}\n'
+
echo '# done'
--- a/tests/test-command-template.out Sat Oct 03 23:38:10 2009 +0200
+++ b/tests/test-command-template.out Sat Oct 03 18:31:20 2009 +0200
@@ -672,4 +672,55 @@
1e4e1b8f71e05681d422154f5421e385fec3454f
# error on syntax
abort: t:3: unmatched quotes
+# latesttag
+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