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
This commit is contained in:
Martin von Zweigbergk 2017-09-15 00:01:57 -07:00
parent 96bbe76280
commit cb781eb5fa
2 changed files with 39 additions and 35 deletions

View File

@ -1128,6 +1128,44 @@ class revlog(object):
raise LookupError(id, self.indexfile, _('no match found')) 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): def cmp(self, node, text):
"""compare text with a given file revision """compare text with a given file revision

View File

@ -1023,41 +1023,7 @@ def shortest(context, mapping, args):
# which would be unacceptably slow. so we look for hash collision in # which would be unacceptably slow. so we look for hash collision in
# unfiltered space, which means some hashes may be slightly longer. # unfiltered space, which means some hashes may be slightly longer.
cl = mapping['ctx']._repo.unfiltered().changelog cl = mapping['ctx']._repo.unfiltered().changelog
def isvalid(test): return cl.shortest(node, minlength)
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
@templatefunc('strip(text[, chars])') @templatefunc('strip(text[, chars])')
def strip(context, mapping, args): def strip(context, mapping, args):