changeset 34250:448725a2ef73

templater: extract shortest() logic from template function It can be useful for extensions to be able to produce the shortest unambiguous hash (including the in-tree "show" extension). That logic is currently inside the shortest() template function. Let's move it out of the templater. I've put it on revlog since it's closely related to revlog._partialmatch. We may also want a convenience method on context, but I'll leave that for a later patch. Differential Revision: https://phab.mercurial-scm.org/D724
author Martin von Zweigbergk <martinvonz@google.com>
date Fri, 15 Sep 2017 00:01:57 -0700
parents ab379eed2e31
children 61714510220d
files mercurial/revlog.py mercurial/templater.py
diffstat 2 files changed, 39 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/revlog.py	Fri Sep 15 18:37:29 2017 -0400
+++ b/mercurial/revlog.py	Fri Sep 15 00:01:57 2017 -0700
@@ -1128,6 +1128,44 @@
 
         raise LookupError(id, self.indexfile, _('no match found'))
 
+    def shortest(self, hexnode, minlength=1):
+        """Find the shortest unambiguous prefix that matches hexnode."""
+        def isvalid(test):
+            try:
+                if self._partialmatch(test) is None:
+                    return False
+
+                try:
+                    i = int(test)
+                    # if we are a pure int, then starting with zero will not be
+                    # confused as a rev; or, obviously, if the int is larger
+                    # than the value of the tip rev
+                    if test[0] == '0' or i > len(self):
+                        return True
+                    return False
+                except ValueError:
+                    return True
+            except error.RevlogError:
+                return False
+            except error.WdirUnsupported:
+                # single 'ff...' match
+                return True
+
+        shortest = hexnode
+        startlength = max(6, minlength)
+        length = startlength
+        while True:
+            test = hexnode[: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 cmp(self, node, text):
         """compare text with a given file revision
 
--- a/mercurial/templater.py	Fri Sep 15 18:37:29 2017 -0400
+++ b/mercurial/templater.py	Fri Sep 15 00:01:57 2017 -0700
@@ -1023,41 +1023,7 @@
     # which would be unacceptably slow. so we look for hash collision in
     # unfiltered space, which means some hashes may be slightly longer.
     cl = mapping['ctx']._repo.unfiltered().changelog
-    def isvalid(test):
-        try:
-            if cl._partialmatch(test) is None:
-                return False
-
-            try:
-                i = int(test)
-                # if we are a pure int, then starting with zero will not be
-                # confused as a rev; or, obviously, if the int is larger than
-                # the value of the tip rev
-                if test[0] == '0' or i > len(cl):
-                    return True
-                return False
-            except ValueError:
-                return True
-        except error.RevlogError:
-            return False
-        except error.WdirUnsupported:
-            # single 'ff...' match
-            return True
-
-    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
+    return cl.shortest(node, minlength)
 
 @templatefunc('strip(text[, chars])')
 def strip(context, mapping, args):