hgext/inhibit.py
changeset 1232 37c00aeb4762
parent 1225 577f5340be6f
child 1233 63ee05dd557a
--- 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