diff mercurial/cmdutil.py @ 9536:f04d17912441

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>
author Mads Kiilerich <mads@kiilerich.com>
date Sat, 03 Oct 2009 18:31:20 +0200
parents ae88c721f916
children f57640bf10d4
line wrap: on
line diff
--- 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)