Patchwork [1,of,3,STABLE,V2] templater: do not use index.partialmatch() directly to calculate shortest()

login
register
mail settings
Submitter Yuya Nishihara
Date Oct. 25, 2016, 2:17 p.m.
Message ID <869574e70105ec60b88b.1477405032@mimosa>
Download mbox | patch
Permalink /patch/17191/
State Accepted
Headers show

Comments

Yuya Nishihara - Oct. 25, 2016, 2:17 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1477199123 -32400
#      Sun Oct 23 14:05:23 2016 +0900
# Branch stable
# Node ID 869574e70105ec60b88b1bb85a12369e5e560279
# Parent  76c57e1fe79b0980b377b4f305635dea393d6315
templater: do not use index.partialmatch() directly to calculate shortest()

cl.index.partialmatch() isn't a drop-in replacement for cl._partialmatch().
It has no knowledge about hidden revisions, and it raises ValueError if a node
shorter than 4 chars is given. Instead, use index.partialmatch() through
cl._partialmatch(), which has no such problems and gives the identical result
with/without --pure.

The test output was sampled with --pure without this patch, which shows the
most correct result. However, we'll need to switch to using an unfiltered
changelog because _partialmatch() of a filtered changelog can be an order of
magnitude slower.

  (with hidden revisions)
  % hg log -R hg-committed -r0:20000 -T '{node|shortest}\n' --time > /dev/null
  (.^)  time: real 1.530 secs (user 1.480+0.000 sys 0.040+0.000)
  (.)   time: real 43.080 secs (user 43.060+0.000 sys 0.030+0.000)

Patch

diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -840,13 +840,8 @@  def shortest(context, mapping, args):
     cl = mapping['ctx']._repo.changelog
     def isvalid(test):
         try:
-            try:
-                cl.index.partialmatch(test)
-            except AttributeError:
-                # Pure mercurial doesn't support partialmatch on the index.
-                # Fallback to the slow way.
-                if cl._partialmatch(test) is None:
-                    return False
+            if cl._partialmatch(test) is None:
+                return False
 
             try:
                 i = int(test)
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
@@ -3413,8 +3413,76 @@  Test shortest(node) function:
   hg: parse error: shortest() expects an integer minlength
   [255]
 
+  $ cd ..
+
+Test shortest(node) with the repo having short hash collision:
+
+  $ hg init hashcollision
+  $ cd hashcollision
+  $ cat <<EOF >> .hg/hgrc
+  > [experimental]
+  > evolution = createmarkers
+  > EOF
+  $ echo 0 > a
+  $ hg ci -qAm 0
+  $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
+  >   hg up -q 0
+  >   echo $i > a
+  >   hg ci -qm $i
+  > done
+  $ hg up -q null
+  $ hg log -r0: -T '{rev}:{node}\n'
+  0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
+  1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
+  2:11407b3f1b9c3e76a79c1ec5373924df096f0499
+  3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
+  4:10776689e627b465361ad5c296a20a487e153ca4
+  5:a00be79088084cb3aff086ab799f8790e01a976b
+  6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
+  7:a0457b3450b8e1b778f1163b31a435802987fe5d
+  8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
+  9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
+  10:c562ddd9c94164376c20b86b0b4991636a3bf84f
+  $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
+  $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
+  $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
+
+ nodes starting with '11' (we don't have the revision number '11' though)
+
+  $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
+  1:1142
+  2:1140
+  3:11d
+
+ '5:a00' is hidden, but still we have two nodes starting with 'a0'
+
+  $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
+  6:a0b
+  7:a04
+
+ node '10' conflicts with the revision number '10' even if it is hidden
+ (we could exclude hidden revision numbers, but currently we don't)
+
+  $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
+  4:107
+  $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
+  4:107
+
+ node 'c562' should be unique if the other 'c562' nodes are hidden
+
+  $ hg log -r 8 -T '{rev}:{node|shortest}\n'
+  8:c562
+  $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
+  8:c5625
+  9:c5623
+  10:c562d
+
+  $ cd ..
+
 Test pad function
 
+  $ cd r
+
   $ hg log --template '{pad(rev, 20)} {author|user}\n'
   2                    test
   1                    {node|short}