inhibit: create direct access extension
Since we want to use direct access without necessarily using inhibit, this
patch separates both extensions. Inhibit depends on direct access and we add
a test to check that it complains if that is not the case.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/directaccess.py Thu May 14 11:23:40 2015 -0700
@@ -0,0 +1,117 @@
+""" This extension provides 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 extensions
+from mercurial import cmdutil
+from mercurial import repoview
+from mercurial import branchmap
+from mercurial import revset
+from mercurial import error
+from mercurial import commands
+from mercurial.i18n import _
+
+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):
+ repo._explicitaccess = set()
+
+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 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):
+ extensions.wrapfunction(revset, 'posttreebuilthook', _posttreebuilthook)
+ setupdirectaccess()
+
+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)
+ 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:
+ 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):
+ 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()
--- a/hgext/inhibit.py Thu May 14 15:59:06 2015 -0700
+++ b/hgext/inhibit.py Thu May 14 11:23:40 2015 -0700
@@ -1,52 +1,33 @@
-"""Reduce the changesets evolution feature scope for early and noob friendly UI
+"""reduce the changesets evolution feature scope for early and noob friendly ui
-The full scale changeset evolution have some massive bleeding edge and it is
+the full scale changeset evolution have some massive bleeding edge and it is
very easy for people not very intimate with the concept to end up in intricate
-situation. In order to get some of the benefit sooner, this extension is
-disabling some of the less polished aspect of evolution. It should gradually
-get thinner and thinner as changeset evolution will get more polished. This
-extension is only recommended for large scale organisations. Individual user
-should probably stick on using Evolution in its current state, understand its
+situation. in order to get some of the benefit sooner, this extension is
+disabling some of the less polished aspect of evolution. it should gradually
+get thinner and thinner as changeset evolution will get more polished. this
+extension is only recommended for large scale organisations. individual user
+should probably stick on using evolution in its current state, understand its
concept and provide feedback
-The first feature provided by this extension is the ability to "inhibit"
-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.
+This extension provides the ability to "inhibit" 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.
"""
from mercurial import localrepo
from mercurial import obsolete
from mercurial import extensions
from mercurial import cmdutil
+from mercurial import error
from mercurial import scmutil
-from mercurial import repoview
-from mercurial import branchmap
-from mercurial import revset
-from mercurial import error
from mercurial import commands
from mercurial import lock as lockmod
from mercurial import bookmarks
-from mercurial import lock as lockmod
from mercurial.i18n import _
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__):
@@ -66,36 +47,10 @@
return newnode
repo.__class__ = obsinhibitedrepo
- repo._explicitaccess = set()
- if not ui.configbool('inhibit', 'onlydirectaccess', False):
- # Wrapping this to inhibit obsolete revs resulting from a transaction
- 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
+ # Wrapping this to inhibit obsolete revs resulting from a transaction
+ extensions.wrapfunction(localrepo.localrepository,
+ 'transaction', transactioncallback)
-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
@@ -211,7 +166,6 @@
finally:
tr.release()
-
def transactioncallback(orig, repo, *args, **kwargs):
""" Wrap localrepo.transaction to inhibit new obsolete changes """
def inhibitposttransaction(transaction):
@@ -226,16 +180,6 @@
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
@@ -249,77 +193,29 @@
for n in repo._obsinhibit:
obs.discard(getrev(n))
return obs
+ try:
+ extensions.find('directaccess')
+ except KeyError:
+ errormsg = _('Cannot use inhibit without the direct access extension')
+ raise error.Abort(errormsg)
obsolete.cachefuncs['obsolete'] = _computeobsoleteset
# wrap create marker to make it able to lift the inhibition
extensions.wrapfunction(obsolete, 'createmarkers', _createmarkers)
- 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()
- # drop bumped computation since it is incompatible with "light revive"
- obsolete.cachefuncs['bumped'] = lambda repo: set()
- # wrap update to make sure that no obsolete commit is visible after an
- # update
- extensions.wrapcommand(commands.table, 'update', _update)
- # There are two ways to save bookmark changes during a transation, we
- # wrap both to add inhibition markers.
- extensions.wrapfunction(bookmarks.bmstore, 'recordchange', _bookmarkchanged)
- extensions.wrapfunction(bookmarks.bmstore, 'write', _bookmarkchanged)
- # Add bookmark -D option
- entry = extensions.wrapcommand(commands.table, 'bookmark', _bookmark)
- entry[1].append(('D','prune',None,
- _('delete the bookmark and prune the commits underneath')))
-
-
-
-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)
- 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:
- 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):
- 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()
+ # drop divergence computation since it is incompatible with "light revive"
+ obsolete.cachefuncs['divergent'] = lambda repo: set()
+ # drop bumped computation since it is incompatible with "light revive"
+ obsolete.cachefuncs['bumped'] = lambda repo: set()
+ # wrap update to make sure that no obsolete commit is visible after an
+ # update
+ extensions.wrapcommand(commands.table, 'update', _update)
+ # There are two ways to save bookmark changes during a transation, we
+ # wrap both to add inhibition markers.
+ extensions.wrapfunction(bookmarks.bmstore, 'recordchange', _bookmarkchanged)
+ extensions.wrapfunction(bookmarks.bmstore, 'write', _bookmarkchanged)
+ # Add bookmark -D option
+ entry = extensions.wrapcommand(commands.table, 'bookmark', _bookmark)
+ entry[1].append(('D','prune',None,
+ _('delete the bookmark and prune the commits underneath')))
@command('debugobsinhibit', [], '')
def cmddebugobsinhibit(ui, repo, *revs):
--- a/tests/test-inhibit.t Thu May 14 15:59:06 2015 -0700
+++ b/tests/test-inhibit.t Thu May 14 11:23:40 2015 -0700
@@ -9,6 +9,7 @@
> strip=
> EOF
$ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+ $ echo "directaccess=$(echo $(dirname $TESTDIR))/hgext/directaccess.py" >> $HGRCPATH
$ echo "inhibit=$(echo $(dirname $TESTDIR))/hgext/inhibit.py" >> $HGRCPATH
$ mkcommit() {
> echo "$1" > "$1"
@@ -562,17 +563,17 @@
added 2 changesets with 1 changes to 2 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
-Only allow direct access and check that evolve works like before
+ Only allow direct access and check that evolve works like before
$ cat >> $HGRCPATH <<EOF
- > [inhibit]
- > onlydirectaccess = True
+ > [extensions]
+ > inhibit=!
> EOF
$ hg up 15
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ working directory parent is obsolete!
$ echo "CM" > cM
$ hg amend
- 1 new unstable changesets
$ hg log -G
@ 21:721c3c279519 add cM
|
@@ -582,10 +583,8 @@
|/
o 14:d66ccb8c5871 add cL
|
- | o 9:55c73a90e4b4 add cJ
- | |
- o | 7:18214586bf78 add cJ
- |/
+ o 7:18214586bf78 add cJ
+ |
o 6:cf5c4f4554ce add cH
|
o 5:5419eb264a33 add cG
@@ -594,3 +593,15 @@
|
o 0:54ccbc537fc2 add cA
+
+Inhibit should not work without directaccess
+ $ cat >> $HGRCPATH <<EOF
+ > [extensions]
+ > directaccess=!
+ > EOF
+ $ echo "inhibit=$(echo $(dirname $TESTDIR))/hgext/inhibit.py" >> $HGRCPATH
+
+ $ hg up 15
+ abort: Cannot use inhibit without the direct access extension
+ [255]
+