Patchwork [1,of,6,evolve-ext,for-the-record] add a 'inhibit' extension

login
register
mail settings
Submitter Pierre-Yves David
Date April 1, 2015, 11:50 p.m.
Message ID <859a854cedc355792297.1427932208@marginatus.alto.octopoid.net>
Download mbox | patch
Permalink /patch/8431/
State Accepted
Headers show

Comments

Pierre-Yves David - April 1, 2015, 11:50 p.m.
# HG changeset patch
# User Pierre-Yves David <pierre-yves.david@fb.com>
# Date 1425705944 28800
#      Fri Mar 06 21:25:44 2015 -0800
# Node ID 859a854cedc3557922978415708ad6ce2e5ab785
# Parent  4e7da688a066470aeb49a8c97d35aa4e0af18594
add a 'inhibit' extension

This extension will be used to reduce the scope of evolve in order to make some
of its features available to the mass earlier.

See extension documentation for details.
Pierre-Yves David - April 2, 2015, 12:23 a.m.
On 04/01/2015 04:50 PM, Pierre-Yves David wrote:
> # HG changeset patch
> # User Pierre-Yves David <pierre-yves.david@fb.com>
> # Date 1425705944 28800
> #      Fri Mar 06 21:25:44 2015 -0800
> # Node ID 859a854cedc3557922978415708ad6ce2e5ab785
> # Parent  4e7da688a066470aeb49a8c97d35aa4e0af18594
> add a 'inhibit' extension

These patches, that recently made it to the evolve repository introduce 
a new extension that reduce some of the evolve feature that are not 
really ready for generic user. The idea here is to ease the technical 
jump from "using strip" to "creating obsolescence marker and repository 
filtering" by purging all the UI and conceptual change coming along with 
it. Once the technical jump is made it will be much easier for huge 
organization as Facebook to polish and slowly turn every semantical 
aspect of changesets evolution on.
Augie Fackler - April 3, 2015, 2:55 p.m.
On Wed, Apr 01, 2015 at 05:23:22PM -0700, Pierre-Yves David wrote:
>
>
> On 04/01/2015 04:50 PM, Pierre-Yves David wrote:
> ># HG changeset patch
> ># User Pierre-Yves David <pierre-yves.david@fb.com>
> ># Date 1425705944 28800
> >#      Fri Mar 06 21:25:44 2015 -0800
> ># Node ID 859a854cedc3557922978415708ad6ce2e5ab785
> ># Parent  4e7da688a066470aeb49a8c97d35aa4e0af18594
> >add a 'inhibit' extension
>
> These patches, that recently made it to the evolve repository introduce a
> new extension that reduce some of the evolve feature that are not really
> ready for generic user. The idea here is to ease the technical jump from
> "using strip" to "creating obsolescence marker and repository filtering" by
> purging all the UI and conceptual change coming along with it. Once the
> technical jump is made it will be much easier for huge organization as
> Facebook to polish and slowly turn every semantical aspect of changesets
> evolution on.

Interesting. We should probably have a wiki page or repo of markdown
documents or something where we can talk more about what we need to do
with the evolve UI so that things like this can be watched by those
who are interested but can't stay up on changes to the evolve
repo. What do you think?

>
> --
> Pierre-Yves David
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel@selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel

Patch

diff --git a/hgext/inhibit.py b/hgext/inhibit.py
new file mode 100644
--- /dev/null
+++ b/hgext/inhibit.py
@@ -0,0 +1,125 @@ 
+"""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
+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
+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.
+"""
+from mercurial import localrepo
+from mercurial import obsolete
+from mercurial import extensions
+from mercurial import cmdutil
+from mercurial import scmutil
+
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+
+def reposetup(ui, repo):
+
+    class obsinhibitedrepo(repo.__class__):
+
+        @localrepo.storecache('obsinhibit')
+        def _obsinhibit(self):
+            # XXX we should make sure it is invalidated by transaction failure
+            obsinhibit = set()
+            raw = self.sopener.tryread('obsinhibit')
+            for i in xrange(0, len(raw), 20):
+                obsinhibit.add(raw[i:i+20])
+            return obsinhibit
+
+    repo.__class__ = obsinhibitedrepo
+
+# obsolescence inhibitor
+########################
+
+def _schedulewrite(tr, obsinhibit):
+    """Make sure on disk content will be updated on transaction commit"""
+    def writer(fp):
+        """Serialize the inhibited list to disk.
+        """
+        raw = ''.join(obsinhibit)
+        fp.write(raw)
+    tr.addfilegenerator('obsinhibit', ('obsinhibit',), writer)
+    tr.hookargs['obs_inbihited'] = '1'
+
+def _inhibitmarkers(repo, nodes):
+    """add marker inhibitor for all obsolete revision under <nodes>
+
+    Content of <nodes> and all mutable ancestors are considered. Marker for
+    obsolete revision only are created.
+    """
+    newinhibit = repo.set('::%ln and obsolete()', nodes)
+    if newinhibit:
+        tr = repo.transaction('obsinhibit')
+        try:
+            repo._obsinhibit.update(c.node() for c in newinhibit)
+            _schedulewrite(tr, repo._obsinhibit)
+            repo.invalidatevolatilesets()
+            tr.close()
+        finally:
+            tr.release()
+
+def _deinhibitmarkers(repo, nodes):
+    """lift obsolescence inhibition on a set of nodes
+
+    This will be triggered when inhibited nodes received new obsolescence
+    markers. Otherwise the new obsolescence markers would also be inhibited.
+    """
+    deinhibited = repo._obsinhibit & set(nodes)
+    if deinhibited:
+        tr = repo.transaction('obsinhibit')
+        try:
+            repo._obsinhibit -= deinhibited
+            _schedulewrite(tr, repo._obsinhibit)
+            repo.invalidatevolatilesets()
+            tr.close()
+        finally:
+            tr.release()
+
+def _createmarkers(orig, repo, relations, flag=0, date=None, metadata=None):
+    """wrap markers create to make sure we de-inhibit target nodes"""
+    # wrapping transactio to unify the one in each function
+    tr = repo.transaction('add-obsolescence-marker')
+    try:
+        orig(repo, relations, flag, date, metadata)
+        precs = (r[0].node() for r in relations)
+        _deinhibitmarkers(repo, precs)
+        tr.close()
+    finally:
+        tr.release()
+
+def extsetup(ui):
+    # lets wrap the computation of the obsolete set
+    # We apply inhibition there
+    obsfunc = obsolete.cachefuncs['obsolete']
+    def _computeobsoleteset(repo):
+        """remove any inhibited nodes from the obsolete set
+
+        This will trickle down to other part of mercurial (hidden, log, etc)"""
+        obs = obsfunc(repo)
+        getrev = repo.changelog.nodemap.get
+        for n in repo._obsinhibit:
+            obs.discard(getrev(n))
+        return obs
+    obsolete.cachefuncs['obsolete'] = _computeobsoleteset
+    # 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 create marker to make it able to lift the inhibition
+    extensions.wrapfunction(obsolete, 'createmarkers', _createmarkers)
+
+@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)
diff --git a/tests/test-inhibit.t b/tests/test-inhibit.t
new file mode 100644
--- /dev/null
+++ b/tests/test-inhibit.t
@@ -0,0 +1,129 @@ 
+  $ cat >> $HGRCPATH <<EOF
+  > [ui]
+  > logtemplate = {rev}:{node|short} {desc}\n
+  > [extensions]
+  > EOF
+  $ echo "evolve=$(echo $(dirname $TESTDIR))/hgext/evolve.py" >> $HGRCPATH
+  $ echo "inhibit=$(echo $(dirname $TESTDIR))/hgext/inhibit.py" >> $HGRCPATH
+  $ mkcommit() {
+  >    echo "$1" > "$1"
+  >    hg add "$1"
+  >    hg ci -m "add $1"
+  > }
+
+  $ hg init inhibit
+  $ cd inhibit
+  $ mkcommit cA
+  $ mkcommit cB
+  $ mkcommit cC
+  $ mkcommit cD
+  $ hg up 'desc(cA)'
+  0 files updated, 0 files merged, 3 files removed, 0 files unresolved
+  $ mkcommit cE
+  created new head
+  $ mkcommit cG
+  $ mkcommit cH
+  $ mkcommit cJ
+  $ hg log -G 
+  @  7:18214586bf78 add cJ
+  |
+  o  6:cf5c4f4554ce add cH
+  |
+  o  5:5419eb264a33 add cG
+  |
+  o  4:98065434e5c6 add cE
+  |
+  | o  3:2db36d8066ff add cD
+  | |
+  | o  2:7df62a38b9bf add cC
+  | |
+  | o  1:02bcbc3f6e56 add cB
+  |/
+  o  0:54ccbc537fc2 add cA
+  
+
+plain prune
+
+  $ hg prune 1::
+  3 changesets pruned
+  $ hg log -G
+  @  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 debugobsinhibit --hidden 1::
+  $ hg log -G
+  @  7:18214586bf78 add cJ
+  |
+  o  6:cf5c4f4554ce add cH
+  |
+  o  5:5419eb264a33 add cG
+  |
+  o  4:98065434e5c6 add cE
+  |
+  | o  3:2db36d8066ff add cD
+  | |
+  | o  2:7df62a38b9bf add cC
+  | |
+  | o  1:02bcbc3f6e56 add cB
+  |/
+  o  0:54ccbc537fc2 add cA
+  
+  $ hg prune --hidden 1::
+  3 changesets pruned
+  $ hg log -G
+  @  7:18214586bf78 add cJ
+  |
+  o  6:cf5c4f4554ce add cH
+  |
+  o  5:5419eb264a33 add cG
+  |
+  o  4:98065434e5c6 add cE
+  |
+  o  0:54ccbc537fc2 add cA
+  
+
+after amend
+
+  $ echo babar > cJ
+  $ hg amend
+  $ hg log -G
+  @  9:55c73a90e4b4 add cJ
+  |
+  o  6:cf5c4f4554ce add cH
+  |
+  o  5:5419eb264a33 add cG
+  |
+  o  4:98065434e5c6 add cE
+  |
+  o  0:54ccbc537fc2 add cA
+  
+  $ hg debugobsinhibit --hidden 18214586bf78
+  $ 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
+  
+
+and no divergence
+
+  $ hg summary
+  parent: 9:55c73a90e4b4 tip
+   add cJ
+  branch: default
+  commit: (clean)
+  update: 1 new changesets, 2 branch heads (merge)