Patchwork [1,of,2,V2] template: add shortest(node) template function

login
register
mail settings
Submitter Durham Goode
Date Feb. 5, 2014, 3:56 a.m.
Message ID <bc85372a73c4f09e12d7.1391572598@dev010.prn1.facebook.com>
Download mbox | patch
Permalink /patch/3484/
State Accepted
Commit 9c6b86dd2ed20c105c9aa8fcf3a415f670402378
Headers show

Comments

Durham Goode - Feb. 5, 2014, 3:56 a.m.
# HG changeset patch
# User Durham Goode <durham@fb.com>
# Date 1389946237 28800
#      Fri Jan 17 00:10:37 2014 -0800
# Node ID bc85372a73c4f09e12d7ef8b7ac1f7dfcb1a5108
# Parent  ec5d4287a4269bc939e203c975af8585570404c6
template: add shortest(node) template function

Adds a '{shortest(node)}' template function that results in the shortest hex node
that uniquely identifies the changeset at that time. The minimum length can be
specified as an optional second argument and defaults to 4.

This is useful for producing prettier log output, like so:

@  durham  shortestnode
|  77cf    template: add pad function for padding output
|
o  durham
|  b183    template: add shortestnode keyword
|
o  pierre-yves @
|  6545    backout: add a message after backout that need manual commit
|
| o  durham   manifestcache
|/   93f0    manifest cache
|
| o  durham   catperf
| |  c765    cat: increase perf when catting single files
| |
| o  durham
|/   9c53    changectx: increase perf of walk function
|

Patch

diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -328,6 +328,45 @@ 
 
     return minirst.format(text, style=style, keep=['verbose'])
 
+def shortest(context, mapping, args):
+    """usage: shortest(node, minlength=4)
+    """
+    if not (1 <= len(args) <= 2):
+        raise error.ParseError(_("shortest() expects one or two arguments"))
+
+    node = stringify(args[0][0](context, mapping, args[0][1]))
+
+    minlength = 4
+    if len(args) > 1:
+        minlength = int(args[1][1])
+
+    cl = mapping['ctx']._repo.changelog
+    def isvalid(test):
+        try:
+            cl.index.partialmatch(test)
+            try:
+                int(test)
+                return False
+            except ValueError:
+                return True
+        except error.RevlogError:
+            return False
+
+    shortest = node
+    startlength = max(6, minlength)
+    length = startlength
+    while True:
+        test = node[:length]
+        if isvalid(test):
+            shortest = test
+            if length == minlength or length > startlength:
+                return shortest
+            length -= 1
+        else:
+            length += 1
+            if len(shortest) <= length:
+                return shortest
+
 def strip(context, mapping, args):
     if not (1 <= len(args) <= 2):
         raise error.ParseError(_("strip expects one or two arguments"))
@@ -369,6 +408,7 @@ 
     "join": join,
     "label": label,
     "rstdoc": rstdoc,
+    "shortest": shortest,
     "strip": strip,
     "sub": sub,
 }
diff --git a/tests/test-command-template.t b/tests/test-command-template.t
--- a/tests/test-command-template.t
+++ b/tests/test-command-template.t
@@ -1626,3 +1626,14 @@ 
 
   $ hg log -r 0 --template '{if(branches, "yes", "no")}\n'
   no
+
+Test shortest(node) function:
+
+  $ echo b > b
+  $ hg ci -qAm b
+  $ hg log --template '{shortest(node)}\n'
+  d97c
+  f776
+  $ hg log --template '{shortest(node, 10)}\n'
+  d97c383ae3
+  f7769ec2ab