From patchwork Wed May 13 00:03:43 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [evolve-ext-V4] inhibit: direct access with and without warning on a per command basis From: Laurent Charignon X-Patchwork-Id: 9036 Message-Id: <7cf844bacf42376584a2.1431475423@lcharignon-mbp.dhcp.thefacebook.com> To: Date: Tue, 12 May 2015 17:03:43 -0700 # HG changeset patch # User Laurent Charignon # Date 1431463949 25200 # Tue May 12 13:52:29 2015 -0700 # Node ID 7cf844bacf42376584a2d87df88205e446959a89 # Parent 5e82d78f5872c9503d7b6691c594a13794a9b4a4 inhibit: direct access with and without warning on a per command basis We introduce a new filtername visibile-directaccess-nowarn to enable direct access with no warning on a per command basis. The motivation behing this change is to display warning when attempting direct access in destructive commands. diff --git a/hgext/inhibit.py b/hgext/inhibit.py --- a/hgext/inhibit.py +++ b/hgext/inhibit.py @@ -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 @@ repo.__class__ = obsinhibitedrepo 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 _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 @@ -212,8 +255,8 @@ 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) + setupdirectaccess() # wrap update to make sure that no obsolete commit is visible after an # update extensions.wrapcommand(commands.table, 'update', _update) @@ -250,8 +293,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: @@ -264,6 +311,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', [], '') @@ -271,12 +324,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 diff --git a/tests/test-inhibit.t b/tests/test-inhibit.t --- a/tests/test-inhibit.t +++ b/tests/test-inhibit.t @@ -397,6 +397,9 @@ (use --hidden to access hidden revisions) [255] $ hg rebase -r ad78ff7d621f -r 53a94305e133 -d 2db36d8066ff + Warning: accessing hidden changesets 2db36d8066ff for write operation + Warning: accessing hidden changesets ad78ff7d621f for write operation + Warning: accessing hidden changesets 53a94305e133 for write operation rebasing 10:ad78ff7d621f "add cK" rebasing 11:53a94305e133 "add cL" $ hg log -G