hgext/inhibit.py
changeset 1334 b8f880d4171d
parent 1332 1ed337c7f061
child 1338 77cbf9121e8a
--- a/hgext/inhibit.py	Tue May 12 12:26:46 2015 -0700
+++ b/hgext/inhibit.py	Tue May 12 13:52:29 2015 -0700
@@ -26,6 +26,7 @@
 from mercurial import cmdutil
 from mercurial import scmutil
 from mercurial import repoview
+from mercurial import branchmap
 from mercurial import revset
 from mercurial import error
 from mercurial import commands
@@ -37,6 +38,15 @@
 cmdtable = {}
 command = cmdutil.command(cmdtable)
 
+# List of commands where no warning is shown for direct access
+directaccesslevel = [
+    # warning or not, extension (None if core), command name
+    (False, None, 'update'), 
+    (False, None, 'export'),
+    (True,  'rebase', 'rebase'),
+    (False,  'evolve', 'prune'),
+]
+
 def reposetup(ui, repo):
 
     class obsinhibitedrepo(repo.__class__):
@@ -62,7 +72,30 @@
         extensions.wrapfunction(localrepo.localrepository,
                                 'transaction', transactioncallback)
 
+def _computehidden(repo):
+    hidden = repoview.computehidden(repo)
+    cl = repo.changelog
+    dynamic = hidden & repo._explicitaccess
+    if dynamic:
+        blocked = cl.ancestors(dynamic, inclusive=True)
+        hidden = frozenset(r for r in hidden if r not in blocked)
+    return hidden
 
+def setupdirectaccess():
+    """ Add two new filtername that behave like visible to provide direct access
+    and direct access with warning. Wraps the commands to setup direct access """
+    repoview.filtertable.update({'visible-directaccess-nowarn': _computehidden})
+    repoview.filtertable.update({'visible-directaccess-warn': _computehidden})
+    branchmap.subsettable['visible-directaccess-nowarn'] = 'visible'
+    branchmap.subsettable['visible-directaccess-warn'] = 'visible'
+
+    for warn, ext, cmd in directaccesslevel:
+        cmdtable = extensions.find(ext).cmdtable if ext else commands.table
+        wrapper = wrapwithwarning if warn else wrapwithoutwarning
+        try:
+            extensions.wrapcommand(cmdtable, cmd, wrapper)
+        except error.UnknownCommand:
+            pass
 def _update(orig, ui, repo, *args, **kwargs):
     """
     When moving to a commit we want to inhibit any obsolete commit affecting
@@ -192,6 +225,16 @@
     transaction.addpostclose('inhibitposttransaction', inhibitposttransaction)
     return transaction
 
+def wrapwithoutwarning(orig, ui, repo, *args, **kwargs):
+    if repo and repo.filtername == 'visible':
+        repo = repo.filtered("visible-directaccess-nowarn")
+    return orig(ui, repo, *args, **kwargs)
+
+def wrapwithwarning(orig, ui, repo, *args, **kwargs):
+    if repo and repo.filtername == 'visible':
+        repo = repo.filtered("visible-directaccess-warn")
+    return orig(ui, repo, *args, **kwargs)
+
 def extsetup(ui):
     # lets wrap the computation of the obsolete set
     # We apply inhibition there
@@ -208,8 +251,8 @@
     obsolete.cachefuncs['obsolete'] = _computeobsoleteset
     # 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)
+    setupdirectaccess()
     if not ui.configbool('inhibit', 'onlydirectaccess', False):
         # drop divergence computation since it is incompatible with "light revive"
         obsolete.cachefuncs['divergent'] = lambda repo: set()
@@ -251,8 +294,12 @@
     # We extract the symbols that look like hashes and add them to the
     # explicitaccess set
     orig(tree, repo)
-    if repo is not None and repo.filtername == 'visible':
+    filternm = ""
+    if repo is not None:
+        filternm = repo.filtername
+    if filternm is not None and filternm.startswith('visible-directaccess'):
         prelength = len(repo._explicitaccess)
+        accessbefore = set(repo._explicitaccess)
         repo.symbols = gethashsymbols(tree)
         cl = repo.unfiltered().changelog
         for node in repo.symbols:
@@ -265,6 +312,12 @@
                 if rev not in repo.changelog:
                     repo._explicitaccess.add(rev)
         if prelength != len(repo._explicitaccess):
+            if repo.filtername != 'visible-directaccess-nowarn':
+                unhiddencommits = repo._explicitaccess - accessbefore
+                repo.ui.warn( _("Warning: accessing hidden changesets %s " 
+                                "for write operation\n") % 
+                                (",".join([str(repo.unfiltered()[l]) 
+                                    for l in unhiddencommits])))
             repo.invalidatevolatilesets()
 
 @command('debugobsinhibit', [], '')
@@ -272,12 +325,3 @@
     """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