# HG changeset patch # User Martin von Zweigbergk # Date 2018-04-14 07:13:08 # Node ID 7b29556247776a86ead7eb98fd3a20dafd0c08b4 # Parent 8e8541610d85c1e8b278785e2291de6ca2f81439 scmutil: make shortesthexnodeidprefix() take a full binary nodeid The shortest() template function depended on the behavior of revlog._partialmatch() for these types of inputs: * non-hex strings * ambiguous strings * too long strings revlog._partialmatch() seems to return the input unchanged in these cases, but we shouldn't depend on such a low-level function to match the behavior we want in the user-facing template function. Instead, let's handle these cases in the template function and always pass a binary nodeid to _partialmatch(). Differential Revision: https://phab.mercurial-scm.org/D3371 diff --git a/hgext/show.py b/hgext/show.py --- a/hgext/show.py +++ b/hgext/show.py @@ -29,7 +29,6 @@ from __future__ import absolute_import from mercurial.i18n import _ from mercurial.node import ( - hex, nullrev, ) from mercurial import ( @@ -448,8 +447,8 @@ def longestshortest(repo, revs, minlen=4 if not revs: return minlen cl = repo.changelog - return max(len(scmutil.shortesthexnodeidprefix(repo, hex(cl.node(r)), - minlen)) for r in revs) + return max(len(scmutil.shortesthexnodeidprefix(repo, cl.node(r), minlen)) + for r in revs) # Adjust the docstring of the show command so it shows all registered views. # This is a bit hacky because it runs at the end of module load. When moved diff --git a/mercurial/scmutil.py b/mercurial/scmutil.py --- a/mercurial/scmutil.py +++ b/mercurial/scmutil.py @@ -443,12 +443,12 @@ def resolvehexnodeidprefix(repo, prefix) repo.changelog.rev(node) # make sure node isn't filtered return node -def shortesthexnodeidprefix(repo, hexnode, minlength=1): +def shortesthexnodeidprefix(repo, node, minlength=1): """Find the shortest unambiguous prefix that matches hexnode.""" # _partialmatch() of filtered changelog could take O(len(repo)) time, # which would be unacceptably slow. so we look for hash collision in # unfiltered space, which means some hashes may be slightly longer. - return repo.unfiltered().changelog.shortest(hexnode, minlength) + return repo.unfiltered().changelog.shortest(hex(node), minlength) def isrevsymbol(repo, symbol): """Checks if a symbol exists in the repo. diff --git a/mercurial/templatefuncs.py b/mercurial/templatefuncs.py --- a/mercurial/templatefuncs.py +++ b/mercurial/templatefuncs.py @@ -10,6 +10,9 @@ from __future__ import absolute_import import re from .i18n import _ +from .node import ( + bin, +) from . import ( color, encoding, @@ -579,7 +582,7 @@ def shortest(context, mapping, args): # i18n: "shortest" is a keyword raise error.ParseError(_("shortest() expects one or two arguments")) - node = evalstring(context, mapping, args[0]) + hexnode = evalstring(context, mapping, args[0]) minlength = 4 if len(args) > 1: @@ -588,6 +591,20 @@ def shortest(context, mapping, args): _("shortest() expects an integer minlength")) repo = context.resource(mapping, 'ctx')._repo + if len(hexnode) > 40: + return hexnode + elif len(hexnode) == 40: + try: + node = bin(hexnode) + except TypeError: + return hexnode + else: + try: + node = scmutil.resolvehexnodeidprefix(repo, hexnode) + except (error.LookupError, error.WdirUnsupported): + return hexnode + if not node: + return hexnode return scmutil.shortesthexnodeidprefix(repo, node, minlength) @templatefunc('strip(text[, chars])') 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 @@ -3900,6 +3900,21 @@ Test shortest(node) function: $ hg log -r 'wdir()' -T '{node|shortest}\n' ffff + $ hg log --template '{shortest("f")}\n' -l1 + f + + $ hg log --template '{shortest("0123456789012345678901234567890123456789")}\n' -l1 + 0123456789012345678901234567890123456789 + + $ hg log --template '{shortest("01234567890123456789012345678901234567890123456789")}\n' -l1 + 01234567890123456789012345678901234567890123456789 + + $ hg log --template '{shortest("not a hex string")}\n' -l1 + not a hex string + + $ hg log --template '{shortest("not a hex string, but it'\''s 40 bytes long")}\n' -l1 + not a hex string, but it's 40 bytes long + $ cd .. Test shortest(node) with the repo having short hash collision: