Patchwork [2,of,2] revlog: add support for partial matching of wdir node id

login
register
mail settings
Submitter Yuya Nishihara
Date June 4, 2017, 2:50 p.m.
Message ID <62080cf2737f5945d6b7.1496587853@mimosa>
Download mbox | patch
Permalink /patch/21175/
State Accepted
Headers show

Comments

Yuya Nishihara - June 4, 2017, 2:50 p.m.
# HG changeset patch
# User Yuya Nishihara <yuya@tcha.org>
# Date 1471598764 -32400
#      Fri Aug 19 18:26:04 2016 +0900
# Node ID 62080cf2737f5945d6b72fcb476ee32762a1f129
# Parent  8a92c8414acdf0b72195ed393cc22717e0e80acf
revlog: add support for partial matching of wdir node id

The idea is simple. If the given node id prefix is 'ff...f', add +1 to the
number of matches (e.g. ambiguous if partial + maybewdir > 1).

This patch also fixes id() revset and shortest() template since _partialmatch()
can raise WdirUnsupported exception.
Augie Fackler - June 5, 2017, 2:15 p.m.
On Sun, Jun 04, 2017 at 11:50:53PM +0900, Yuya Nishihara wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya@tcha.org>
> # Date 1471598764 -32400
> #      Fri Aug 19 18:26:04 2016 +0900
> # Node ID 62080cf2737f5945d6b72fcb476ee32762a1f129
> # Parent  8a92c8414acdf0b72195ed393cc22717e0e80acf
> revlog: add support for partial matching of wdir node id

queued, thanks

Patch

diff --git a/mercurial/node.py b/mercurial/node.py
--- a/mercurial/node.py
+++ b/mercurial/node.py
@@ -29,6 +29,7 @@  wdirnodes = {newnodeid, addednodeid, mod
 # (they are experimental, so don't add too many dependencies on them)
 wdirrev = 0x7fffffff
 wdirid = b"\xff" * 20
+wdirhex = hex(wdirid)
 
 def short(node):
     return hex(node[:6])
diff --git a/mercurial/revlog.py b/mercurial/revlog.py
--- a/mercurial/revlog.py
+++ b/mercurial/revlog.py
@@ -26,6 +26,7 @@  from .node import (
     hex,
     nullid,
     nullrev,
+    wdirhex,
     wdirid,
     wdirrev,
 )
@@ -1038,10 +1039,17 @@  class revlog(object):
                 pass
 
     def _partialmatch(self, id):
+        maybewdir = wdirhex.startswith(id)
         try:
             partial = self.index.partialmatch(id)
             if partial and self.hasnode(partial):
+                if maybewdir:
+                    # single 'ff...' match in radix tree, ambiguous with wdir
+                    raise RevlogError
                 return partial
+            if maybewdir:
+                # no 'ff...' match in radix tree, wdir identified
+                raise error.WdirUnsupported
             return None
         except RevlogError:
             # parsers.c radix tree lookup gave multiple matches
@@ -1066,11 +1074,13 @@  class revlog(object):
                 nl = [n for n in nl if hex(n).startswith(id) and
                       self.hasnode(n)]
                 if len(nl) > 0:
-                    if len(nl) == 1:
+                    if len(nl) == 1 and not maybewdir:
                         self._pcache[id] = nl[0]
                         return nl[0]
                     raise LookupError(id, self.indexfile,
                                       _('ambiguous identifier'))
+                if maybewdir:
+                    raise error.WdirUnsupported
                 return None
             except TypeError:
                 pass
diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
@@ -1309,12 +1309,12 @@  def node_(repo, subset, x):
             rn = None
     else:
         rn = None
-        pm = repo.changelog._partialmatch(n)
-        if pm is not None:
-            try:
+        try:
+            pm = repo.changelog._partialmatch(n)
+            if pm is not None:
                 rn = repo.changelog.rev(pm)
-            except error.WdirUnsupported:
-                rn = node.wdirrev
+        except error.WdirUnsupported:
+            rn = node.wdirrev
 
     if rn is None:
         return baseset()
diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -960,6 +960,9 @@  def shortest(context, mapping, args):
                 return True
         except error.RevlogError:
             return False
+        except error.WdirUnsupported:
+            # single 'ff...' match
+            return True
 
     shortest = node
     startlength = max(6, minlength)
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
@@ -3503,6 +3503,9 @@  Test shortest(node) function:
   hg: parse error: shortest() expects an integer minlength
   [255]
 
+  $ hg log -r 'wdir()' -T '{node|shortest}\n'
+  ffff
+
   $ cd ..
 
 Test shortest(node) with the repo having short hash collision:
diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
@@ -1289,13 +1289,64 @@  Test working-directory integer revision 
   2147483647
   $ hg debugrevspec '0:wdir() & ffffffffffffffffffffffffffffffffffffffff'
   2147483647
+  $ hg debugrevspec '0:wdir() & ffffffffffff'
+  2147483647
   $ hg debugrevspec '0:wdir() & id(ffffffffffffffffffffffffffffffffffffffff)'
   2147483647
   $ hg debugrevspec '0:wdir() & id(ffffffffffff)'
-BROKEN: should be '2147483647'
+  2147483647
+
+  $ cd ..
+
+Test short 'ff...' hash collision
+(BUG: '0:wdir()' is still needed to populate wdir revision)
+
+  $ hg init wdir-hashcollision
+  $ cd wdir-hashcollision
+  $ cat <<EOF >> .hg/hgrc
+  > [experimental]
+  > evolution = createmarkers
+  > EOF
+  $ echo 0 > a
+  $ hg ci -qAm 0
+  $ for i in 2463 2961 6726 78127; do
+  >   hg up -q 0
+  >   echo $i > a
+  >   hg ci -qm $i
+  > done
+  $ hg up -q null
+  $ hg log -r '0:wdir()' -T '{rev}:{node} {shortest(node, 3)}\n'
+  0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a b4e
+  1:fffbae3886c8fbb2114296380d276fd37715d571 fffba
+  2:fffb6093b00943f91034b9bdad069402c834e572 fffb6
+  3:fff48a9b9de34a4d64120c29548214c67980ade3 fff4
+  4:ffff85cff0ff78504fcdc3c0bc10de0c65379249 ffff8
+  2147483647:ffffffffffffffffffffffffffffffffffffffff fffff
+  $ hg debugobsolete fffbae3886c8fbb2114296380d276fd37715d571
+
+  $ hg debugrevspec '0:wdir() & fff'
+  abort: 00changelog.i@fff: ambiguous identifier!
+  [255]
+  $ hg debugrevspec '0:wdir() & ffff'
+  abort: 00changelog.i@ffff: ambiguous identifier!
+  [255]
+  $ hg debugrevspec '0:wdir() & fffb'
+  abort: 00changelog.i@fffb: ambiguous identifier!
+  [255]
+BROKEN should be '2' (node lookup uses unfiltered repo since dc25ed84bee8)
+  $ hg debugrevspec '0:wdir() & id(fffb)'
+  2
+  $ hg debugrevspec '0:wdir() & ffff8'
+  4
+  $ hg debugrevspec '0:wdir() & fffff'
+  2147483647
+
+  $ cd ..
 
 Test branch() with wdir()
 
+  $ cd repo
+
   $ log '0:wdir() & branch("literal:é")'
   8
   9