[PATCH 1 of 2] Add {basetag} {basedistance} and {nancestors} template keywords

Gilles Moris gilles.moris at free.fr
Tue Feb 10 15:52:16 CST 2009


1 file changed, 96 insertions(+), 1 deletion(-)
mercurial/cmdutil.py |   97 +++++++++++++++++++++++++++++++++++++++++++++++++-


# HG changeset patch
# User Gilles Moris <gilles.moris at free.fr>
# Date 1234301937 -3600
# Node ID 7ac8dcbc6eeffa86e944ec41a00f8e8fb789e08e
# Parent  16e74cc6ec63a180649b3a1e3a02eb8686b16321
Add {basetag} {basedistance} and {nancestors} template keywords.

This enables to display nearest tag on which a changeset is based on.

diff --git a/mercurial/cmdutil.py b/mercurial/cmdutil.py
--- a/mercurial/cmdutil.py
+++ b/mercurial/cmdutil.py
@@ -7,7 +7,7 @@
 
 from node import hex, nullid, nullrev, short
 from i18n import _
-import os, sys, bisect, stat
+import os, sys, bisect, stat, heapq
 import mdiff, bdiff, util, templater, templatefilters, patch, errno, error
 import match as _match
 
@@ -822,6 +822,27 @@
                              node=hex(changes[0])))
             return self.t('manifest', **args)
 
+        def shownancestors(**args):
+            na = 0
+            for c in ctx.ancestors():
+                na += 1
+            yield na
+
+        def getbasetag():
+            if not hasattr(self, 'basetagdistance'):
+                self.basetagdistance = -1
+                for c, d in nearesttagsdateh(self.repo, ctx, fwd=False):
+                    self.basetagctx = c
+                    self.basetagdistance = d
+                    break
+            return self.basetagdistance
+        def showbasetag(**args):
+            if getbasetag() >= 0:
+                yield self.basetagctx.tags()[0]
+        def showbasedistance(**args):
+            if getbasetag() >= 0:
+                yield self.basetagdistance
+
         defprops = {
             'author': changes[1],
             'branches': showbranches,
@@ -838,6 +859,9 @@
             'rev': rev,
             'tags': showtags,
             'extras': showextras,
+            'nancestors': shownancestors,
+            'basetag': showbasetag,
+            'basedistance': showbasedistance,
             }
         props = props.copy()
         props.update(defprops)
@@ -1184,3 +1208,74 @@
         return commitfunc(ui, repo, message, m, opts)
     except ValueError, inst:
         raise util.Abort(str(inst))
+
+def nearesttagsdateh(repo, ctx, fwd):
+    """search for cset with tags trying to return csets ordered by date
+    this is a generator function that returns a tuple
+    (changectx, distancefromnode)
+    it searches like a breadth first search algorithm except that an
+    heuristic is set on date to give them priority over number of hops
+    """
+    # initialize the search algorithm depending on the search direction
+    if fwd:
+        excltags = []
+        heuristic = lambda c: c.date()[0]
+        chldcache = [[]] * len(repo.changelog)
+        for r in xrange(ctx.rev(), len(ctx._repo)):
+            for p in repo[r].parents():
+                pr = p.rev()
+                if not chldcache[pr]:
+                    chldcache[pr] = [r]
+                else:
+                    chldcache[pr].append(r)
+        infants = lambda r: chldcache[r]
+    else:
+        try:
+            qparent = repo['qparent']
+            qtip = repo['qtip']
+            if qparent.rev() < ctx.rev() and ctx.rev() <= qtip.rev():
+                ctx = qparent
+                excltags = ['qparent']
+            else:
+                excltags = ['tip']
+        except error.RepoError:
+            excltags = ['tip']
+        heuristic = lambda c: - c.date()[0]
+        infants = lambda r: [ p.rev() for p in repo[r].parents() ]
+
+    # use a distance map and a pseudo sorted list by date
+    # this is a generalised breadth first search with the date as heuristic
+    dmap = [0] * (len(repo))
+    heap = []
+    heapq.heappush(heap, (heuristic(ctx), ctx))
+
+    while heap:
+        # get the highest (resp lowest) date with heappop
+        date, ctx = heapq.heappop(heap)
+        rev = ctx.rev()
+        d = dmap[rev]
+        if d < 0:
+            continue
+        tags = [ t for t in ctx.tags() if t not in excltags ]
+        if tags:
+            yield ctx, d
+            # cut branch once a tag is found
+            if fwd:
+                for c in ctx.descendants():
+                    dmap[c.rev()] = -1
+            else:
+                for c in ctx.ancestors():
+                    dmap[c.rev()] = -1
+            continue
+        # queue neighbours to propagate search
+        for nr in infants(rev):
+            if dmap[nr] > 0:
+                # if a node was already queued, retains the longest path
+                # this also avoid revisiting an already visited node
+                dmap[nr] = max(dmap[nr], d+1)
+            elif dmap[nr] == 0:
+                n = repo[nr]
+                # queue another node keeping the pseudo sorted assertion
+                heapq.heappush(heap, (heuristic(n), n))
+                dmap[nr] = d + 1
+


More information about the Mercurial-devel mailing list