inhibit: enable direct access from parsing the revset tree
authorLaurent Charignon <lcharignon@fb.com>
Fri, 27 Mar 2015 10:58:04 -0700
changeset 1232 37c00aeb4762
parent 1227 3d9c5f5df6d8
child 1233 63ee05dd557a
inhibit: enable direct access from parsing the revset tree To enable direct access we: - detect explicit hexadical reference to node in the revset tree - add these hashes to the static blockers to make them and their parent visible for the command to run
hgext/inhibit.py
tests/test-inhibit.t
--- a/hgext/inhibit.py	Wed Apr 01 14:26:10 2015 -0700
+++ b/hgext/inhibit.py	Fri Mar 27 10:58:04 2015 -0700
@@ -13,12 +13,21 @@
 obsolescence markers. Obsolete revision can be cheaply brought back to life
 that way. However as the inhibitor are not fitting in an append only model,
 this is incompatible with sharing mutable history.
+
+The second feature is called direct access. It is the ability to refer and
+access hidden sha in commands provided that you know their value.
+For example hg log -r XXX where XXX is a commit has should work whether XXX is
+hidden or not as we assume that the user knows what he is doing when referring
+to XXX.
 """
 from mercurial import localrepo
 from mercurial import obsolete
 from mercurial import extensions
 from mercurial import cmdutil
 from mercurial import scmutil
+from mercurial import repoview
+from mercurial import revset
+from mercurial import error
 
 cmdtable = {}
 command = cmdutil.command(cmdtable)
@@ -37,6 +46,7 @@
             return obsinhibit
 
     repo.__class__ = obsinhibitedrepo
+    repo._explicitaccess = set()
 
 # obsolescence inhibitor
 ########################
@@ -125,9 +135,58 @@
     obsolete.cachefuncs['bumped'] = lambda repo: set()
     # wrap create marker to make it able to lift the inhibition
     extensions.wrapfunction(obsolete, 'createmarkers', _createmarkers)
+    extensions.wrapfunction(repoview, '_getdynamicblockers', _accessvisible)
+    extensions.wrapfunction(revset, 'posttreebuilthook', _posttreebuilthook)
+
+def gethashsymbols(tree):
+    # Returns the list of symbols of the tree that look like hashes
+    # for example for the revset 3::abe3ff it will return ('abe3ff')
+    if not tree:
+        return []
+
+    if len(tree) == 2 and tree[0] == "symbol":
+        try:
+            int(tree[1])
+            return []
+        except ValueError as e:
+            return [tree[1]]
+    elif len(tree) == 3:
+        return gethashsymbols(tree[1]) + gethashsymbols(tree[2])
+    else:
+        return []
+
+def _posttreebuilthook(orig, tree, repo):
+    # This is use to enabled direct hash access
+    # We extract the symbols that look like hashes and add them to the
+    # explicitaccess set
+    orig(tree, repo)
+    if repo and repo.filtername == 'visible':
+        prelength = len(repo._explicitaccess)
+        repo.symbols = gethashsymbols(tree)
+        cl = repo.unfiltered().changelog
+        for node in repo.symbols:
+            try:
+                node = cl._partialmatch(node)
+            except error.LookupError:
+                node = None
+            if node is not None:
+                rev = cl.rev(node)
+                if rev not in repo.changelog:
+                    repo._explicitaccess.add(rev)
+        if prelength != len(repo._explicitaccess):
+            repo.invalidatevolatilesets()
 
 @command('debugobsinhibit', [], '')
 def cmddebugobsinhibit(ui, repo, *revs):
     """inhibit obsolescence markers effect on a set of revs"""
     nodes = (repo[r].node() for r in scmutil.revrange(repo, revs))
     _inhibitmarkers(repo, nodes)
+
+# ensure revision accessed by hash are visible
+###############################################
+
+def _accessvisible(orig, repo):
+    """ensure accessed revs stay visible"""
+    blockers = orig(repo)
+    blockers.update(getattr(repo, '_explicitaccess', ()))
+    return blockers
--- a/tests/test-inhibit.t	Wed Apr 01 14:26:10 2015 -0700
+++ b/tests/test-inhibit.t	Fri Mar 27 10:58:04 2015 -0700
@@ -2,6 +2,7 @@
   > [ui]
   > logtemplate = {rev}:{node|short} {desc}\n
   > [extensions]
+  > rebase=
   > EOF
   $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
   $ echo "inhibit=$(echo $(dirname $TESTDIR))/hgext/inhibit.py" >> $HGRCPATH
@@ -173,3 +174,127 @@
   o  0:54ccbc537fc2 add cA
   
 
+Test that direct access make changesets visible
+
+  $ hg export 2db36d8066ff 02bcbc3f6e56
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 2db36d8066ff50e8be3d3e6c2da1ebc0a8381d82
+  # Parent  7df62a38b9bf9daf968de235043ba88a8ef43393
+  add cD
+  
+  diff -r 7df62a38b9bf -r 2db36d8066ff cD
+  --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/cD	Thu Jan 01 00:00:00 1970 +0000
+  @@ -0,0 +1,1 @@
+  +cD
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 02bcbc3f6e56fb2928efec2c6e24472720bf5511
+  # Parent  54ccbc537fc2d6845a5d61337c1cfb80d1d2815e
+  add cB
+  
+  diff -r 54ccbc537fc2 -r 02bcbc3f6e56 cB
+  --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/cB	Thu Jan 01 00:00:00 1970 +0000
+  @@ -0,0 +1,1 @@
+  +cB
+
+But only with hash
+
+  $ hg export 2db36d8066ff::
+  # HG changeset patch
+  # User test
+  # Date 0 0
+  #      Thu Jan 01 00:00:00 1970 +0000
+  # Node ID 2db36d8066ff50e8be3d3e6c2da1ebc0a8381d82
+  # Parent  7df62a38b9bf9daf968de235043ba88a8ef43393
+  add cD
+  
+  diff -r 7df62a38b9bf -r 2db36d8066ff cD
+  --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+  +++ b/cD	Thu Jan 01 00:00:00 1970 +0000
+  @@ -0,0 +1,1 @@
+  +cD
+
+  $ hg export 1 3
+  abort: hidden revision '1'!
+  (use --hidden to access hidden revisions)
+  [255]
+
+
+With severals hidden sha, rebase of one hidden stack onto another one:
+  $ hg update -C 0
+  0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+  $ mkcommit cK
+  created new head
+  $ mkcommit cL
+  $ hg update -C 9
+  4 files updated, 0 files merged, 2 files removed, 0 files unresolved
+  $ hg log -G
+  o  11:53a94305e133 add cL
+  |
+  o  10:ad78ff7d621f add cK
+  |
+  | @  9:55c73a90e4b4 add cJ
+  | |
+  | | o  7:18214586bf78 add cJ
+  | |/
+  | o  6:cf5c4f4554ce add cH
+  | |
+  | o  5:5419eb264a33 add cG
+  | |
+  | o  4:98065434e5c6 add cE
+  |/
+  o  0:54ccbc537fc2 add cA
+  
+  $ hg prune 10:
+  2 changesets pruned
+  $ hg log -G
+  @  9:55c73a90e4b4 add cJ
+  |
+  | o  7:18214586bf78 add cJ
+  |/
+  o  6:cf5c4f4554ce add cH
+  |
+  o  5:5419eb264a33 add cG
+  |
+  o  4:98065434e5c6 add cE
+  |
+  o  0:54ccbc537fc2 add cA
+  
+  $ hg rebase -s 10 -d 3 
+  abort: hidden revision '3'!
+  (use --hidden to access hidden revisions)
+  [255]
+  $ hg rebase -r ad78ff7d621f -r 53a94305e133 -d  2db36d8066ff
+  rebasing 10:ad78ff7d621f "add cK"
+  rebasing 11:53a94305e133 "add cL"
+  2 new unstable changesets
+  $ hg log -G
+  o  13:2f7b7704d714 add cL
+  |
+  o  12:fe1634cbe235 add cK
+  |
+  | @  9:55c73a90e4b4 add cJ
+  | |
+  | | o  7:18214586bf78 add cJ
+  | |/
+  | o  6:cf5c4f4554ce add cH
+  | |
+  | o  5:5419eb264a33 add cG
+  | |
+  | o  4:98065434e5c6 add cE
+  | |
+  x |  3:2db36d8066ff add cD
+  | |
+  x |  2:7df62a38b9bf add cC
+  | |
+  x |  1:02bcbc3f6e56 add cB
+  |/
+  o  0:54ccbc537fc2 add cA
+