changeset 437:48ac58354b7b

obsolete: sort all code Move (splitting some function) all code in dedicated section The hook wrapping have disapeared in the process.
author Pierre-Yves David <pierre-yves.david@logilab.fr>
date Tue, 07 Aug 2012 15:02:54 +0200
parents 1e042eeb2d1a
children b1b7b5ef506a
files hgext/obsolete.py
diffstat 1 files changed, 408 insertions(+), 396 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/obsolete.py
+++ b/hgext/obsolete.py
@@ -79,7 +79,7 @@
 
 
 #####################################################################
-### Extension helper                                             ####
+### Extension helper                                              ###
 #####################################################################
 
 class exthelper(object):
@@ -307,9 +307,9 @@
 extsetup = eh.final_extsetup
 reposetup = eh.final_reposetup
 
-
-### Patch changectx
-#############################
+#####################################################################
+### Obsolescence Caching Logic                                    ###
+#####################################################################
 
 @eh.addattr(context.changectx, 'unstable')
 def unstable(ctx):
@@ -326,32 +326,6 @@
         return False
     return ctx.rev() in ctx._repo._extinctset
 
-@eh.addattr(context.changectx, 'latecomer')
-def latecomer(ctx):
-    """is the changeset latecomer (Try to succeed to public change)"""
-    if ctx.node() is None:
-        return False
-    return ctx.rev() in ctx._repo._latecomerset
-
-@eh.addattr(context.changectx, 'conflicting')
-def conflicting(ctx):
-    """is the changeset conflicting (Try to succeed to public change)"""
-    if ctx.node() is None:
-        return False
-    return ctx.rev() in ctx._repo._conflictingset
-
-
-### revset
-#############################
-
-@eh.revset('hidden')
-def revsethidden(repo, subset, x):
-    """``hidden()``
-    Changeset is hidden.
-    """
-    args = revset.getargs(x, 0, 0, 'hidden takes no argument')
-    return [r for r in subset if r in repo.hiddenrevs]
-
 @eh.revset('obsolete')
 def revsetobsolete(repo, subset, x):
     """``obsolete()``
@@ -368,14 +342,6 @@
     args = revset.getargs(x, 0, 0, 'unstable takes no arguments')
     return [r for r in subset if r in repo._unstableset]
 
-@eh.revset('suspended')
-def revsetsuspended(repo, subset, x):
-    """``suspended()``
-    Obsolete changesets with non-obsolete descendants.
-    """
-    args = revset.getargs(x, 0, 0, 'suspended takes no arguments')
-    return [r for r in subset if r in repo._suspendedset]
-
 @eh.revset('extinct')
 def revsetextinct(repo, subset, x):
     """``extinct()``
@@ -384,21 +350,125 @@
     args = revset.getargs(x, 0, 0, 'extinct takes no arguments')
     return [r for r in subset if r in repo._extinctset]
 
-@eh.revset('latecomer')
-def revsetlatecomer(repo, subset, x):
-    """``latecomer()``
-    Changesets marked as successors of public changesets.
-    """
-    args = revset.getargs(x, 0, 0, 'latecomer takes no arguments')
-    return [r for r in subset if r in repo._latecomerset]
+
+@eh.wrapfunction(phases, 'advanceboundary')
+def wrapclearcache(orig, repo, *args, **kwargs):
+    try:
+        return orig(repo, *args, **kwargs)
+    finally:
+        repo._clearobsoletecache()
+
+@eh.reposetup
+def _repocachesetup(ui, repo):
+    if not repo.local():
+        return
+
+    o_updatebranchcache = repo.updatebranchcache
+    class cachedobsolescencegrepo(repo.__class__):
+
+        # XXX move me on obssotre
+        @util.propertycache
+        def _obsoleteset(self):
+            """the set of obsolete revision"""
+            obs = set()
+            nm = self.changelog.nodemap
+            for prec in self.obsstore.precursors:
+                rev = nm.get(prec)
+                if rev is not None:
+                    obs.add(rev)
+            return obs
+
+        # XXX move me on obssotre
+        @util.propertycache
+        def _unstableset(self):
+            """the set of non obsolete revision with obsolete parent"""
+            return set(self.revs('(obsolete()::) - obsolete()'))
+
+        # XXX move me on obssotre
+        @util.propertycache
+        def _suspendedset(self):
+            """the set of obsolete parent with non obsolete descendant"""
+            return set(self.revs('obsolete() and obsolete()::unstable()'))
+
+        # XXX move me on obssotre
+        @util.propertycache
+        def _extinctset(self):
+            """the set of obsolete parent without non obsolete descendant"""
+            return set(self.revs('obsolete() - obsolete()::unstable()'))
+
+        # XXX move me on obssotre
+        @util.propertycache
+        def _latecomerset(self):
+            """the set of rev trying to obsolete public revision"""
+            query = 'allsuccessors(public()) - obsolete() - public()'
+            return set(self.revs(query))
 
-@eh.revset('conflicting')
-def revsetconflicting(repo, subset, x):
-    """``conflicting()``
-    Changesets marked as successors of a same changeset.
-    """
-    args = revset.getargs(x, 0, 0, 'conflicting takes no arguments')
-    return [r for r in subset if r in repo._conflictingset]
+        # XXX move me on obssotre
+        @util.propertycache
+        def _conflictingset(self):
+            """the set of rev trying to obsolete public revision"""
+            conflicting = set()
+            obsstore = self.obsstore
+            newermap = {}
+            for ctx in self.set('(not public()) - obsolete()'):
+                prec = obsstore.successors.get(ctx.node(), ())
+                toprocess = set(prec)
+                while toprocess:
+                    prec = toprocess.pop()[0]
+                    if prec not in newermap:
+                        newermap[prec] = newerversion(self, prec)
+                    newer = [n for n in newermap[prec] if n] # filter kill
+                    if len(newer) > 1:
+                        conflicting.add(ctx.rev())
+                        break
+                toprocess.update(obsstore.successors.get(prec, ()))
+            return conflicting
+
+        def _clearobsoletecache(self):
+            if '_obsoleteset' in vars(self):
+                del self._obsoleteset
+            self._clearunstablecache()
+
+        def updatebranchcache(self):
+            o_updatebranchcache()
+            self._clearunstablecache()
+
+        def _clearunstablecache(self):
+            if '_unstableset' in vars(self):
+                del self._unstableset
+            if '_suspendedset' in vars(self):
+                del self._suspendedset
+            if '_extinctset' in vars(self):
+                del self._extinctset
+            if '_latecomerset' in vars(self):
+                del self._latecomerset
+            if '_conflictingset' in vars(self):
+                del self._conflictingset
+
+    repo.__class__ = cachedobsolescencegrepo
+
+#####################################################################
+### Complete troubles computation logic                           ###
+#####################################################################
+
+@eh.addattr(context.changectx, 'latecomer')
+def latecomer(ctx):
+    """is the changeset latecomer (Try to succeed to public change)"""
+    if ctx.node() is None:
+        return False
+    return ctx.rev() in ctx._repo._latecomerset
+
+@eh.addattr(context.changectx, 'conflicting')
+def conflicting(ctx):
+    """is the changeset conflicting (Try to succeed to public change)"""
+    if ctx.node() is None:
+        return False
+    return ctx.rev() in ctx._repo._conflictingset
+
+
+#####################################################################
+### Additional Utilities functions                                ###
+#####################################################################
 
 def _precursors(repo, s):
     """Precursor of a changeset"""
@@ -412,16 +482,6 @@
                 cs.add(pr)
     return cs
 
-@eh.revset('obsparents')
-@eh.revset('precursors')
-def revsetprecursors(repo, subset, x):
-    """``precursors(set)``
-    Immediate precursors of changesets in set.
-    """
-    s = revset.getset(repo, range(len(repo)), x)
-    cs = _precursors(repo, s)
-    return [r for r in subset if r in cs]
-
 def _allprecursors(repo, s):  # XXX we need a better naming
     """transitive precursors of a subset"""
     toproceed = [repo[r].node() for r in s]
@@ -442,16 +502,6 @@
             cs.add(pr)
     return cs
 
-@eh.revset('obsancestors')
-@eh.revset('allprecursors')
-def revsetallprecursors(repo, subset, x):
-    """``allprecursors(set)``
-    Transitive precursors of changesets in set.
-    """
-    s = revset.getset(repo, range(len(repo)), x)
-    cs = _allprecursors(repo, s)
-    return [r for r in subset if r in cs]
-
 def _successors(repo, s):
     """Successors of a changeset"""
     cs = set()
@@ -465,16 +515,6 @@
                     cs.add(sr)
     return cs
 
-@eh.revset('obschildrend')
-@eh.revset('successors')
-def revsetsuccessors(repo, subset, x):
-    """``successors(set)``
-    Immediate successors of changesets in set.
-    """
-    s = revset.getset(repo, range(len(repo)), x)
-    cs = _successors(repo, s)
-    return [r for r in subset if r in cs]
-
 def _allsuccessors(repo, s):  # XXX we need a better naming
     """transitive successors of a subset"""
     toproceed = [repo[r].node() for r in s]
@@ -495,6 +535,178 @@
             cs.add(sr)
     return cs
 
+
+### diagnostique tools
+
+def unstables(repo):
+    """Return all unstable changeset"""
+    return scmutil.revrange(repo, ['obsolete():: and (not obsolete())'])
+
+def newerversion(repo, obs):
+    """Return the newer version of an obsolete changeset"""
+    toproceed = set([(obs,)])
+    # XXX known optimization available
+    newer = set()
+    objectrels = repo.obsstore.precursors
+    while toproceed:
+        current = toproceed.pop()
+        assert len(current) <= 1, 'splitting not handled yet. %r' % current
+        current = [n for n in current if n != nullid]
+        if current:
+            n, = current
+            if n in objectrels:
+                markers = objectrels[n]
+                for mark in markers:
+                    toproceed.add(tuple(mark[1]))
+            else:
+                newer.add(tuple(current))
+        else:
+            newer.add(())
+    return sorted(newer)
+
+cmdtable = {}
+command = cmdutil.command(cmdtable)
+@command('debugsuccessors', [], '')
+def cmddebugsuccessors(ui, repo):
+    """dump obsolete changesets and their successors
+
+    Each line matches an existing marker, the first identifier is the
+    obsolete changeset identifier, followed by it successors.
+    """
+    lock = repo.lock()
+    try:
+        allsuccessors = repo.obsstore.precursors
+        for old in sorted(allsuccessors):
+            successors = [sorted(m[1]) for m in allsuccessors[old]]
+            for i, group in enumerate(sorted(successors)):
+                ui.write('%s' % short(old))
+                for new in group:
+                    ui.write(' %s' % short(new))
+                ui.write('\n')
+    finally:
+        lock.release()
+
+
+@eh.reposetup
+def _repoobsutilsetup(ui, repo):
+    if not repo.local():
+        return
+
+    class obsoletingrepo(repo.__class__):
+
+        # XXX kill me
+        def addobsolete(self, sub, obj):
+            """Add a relation marking that node <sub> is a new version of <obj>"""
+            assert sub != obj
+            if not repo[obj].phase():
+                if sub is None:
+                    self.ui.warn(
+                        _("trying to kill immutable changeset %(obj)s\n")
+                        % {'obj': short(obj)})
+                if sub is not None:
+                    self.ui.warn(
+                        _("%(sub)s try to obsolete immutable changeset %(obj)s\n")
+                        % {'sub': short(sub), 'obj': short(obj)})
+            lock = self.lock()
+            try:
+                tr = self.transaction('add-obsolete')
+                try:
+                    meta = {
+                        'date':  '%i %i' % util.makedate(),
+                        'user': ui.username(),
+                        }
+                    subs = (sub == nullid) and [] or [sub]
+                    mid = self.obsstore.create(tr, obj, subs, 0, meta)
+                    tr.close()
+                    self._clearobsoletecache()
+                    return mid
+                finally:
+                    tr.release()
+            finally:
+                lock.release()
+
+        # XXX kill me
+        def addcollapsedobsolete(self, oldnodes, newnode):
+            """Mark oldnodes as collapsed into newnode."""
+            # Assume oldnodes are all descendants of a single rev
+            rootrevs = self.revs('roots(%ln)', oldnodes)
+            assert len(rootrevs) == 1, rootrevs
+            #rootnode = self[rootrevs[0]].node()
+            for n in oldnodes:
+                self.addobsolete(newnode, n)
+    repo.__class__ = obsoletingrepo
+
+#####################################################################
+### Extending revset and template                                 ###
+#####################################################################
+
+@eh.revset('hidden')
+def revsethidden(repo, subset, x):
+    """``hidden()``
+    Changeset is hidden.
+    """
+    args = revset.getargs(x, 0, 0, 'hidden takes no argument')
+    return [r for r in subset if r in repo.hiddenrevs]
+
+## troubles
+
+@eh.revset('suspended')
+def revsetsuspended(repo, subset, x):
+    """``suspended()``
+    Obsolete changesets with non-obsolete descendants.
+    """
+    args = revset.getargs(x, 0, 0, 'suspended takes no arguments')
+    return [r for r in subset if r in repo._suspendedset]
+
+@eh.revset('latecomer')
+def revsetlatecomer(repo, subset, x):
+    """``latecomer()``
+    Changesets marked as successors of public changesets.
+    """
+    args = revset.getargs(x, 0, 0, 'latecomer takes no arguments')
+    return [r for r in subset if r in repo._latecomerset]
+
+@eh.revset('conflicting')
+def revsetconflicting(repo, subset, x):
+    """``conflicting()``
+    Changesets marked as successors of a same changeset.
+    """
+    args = revset.getargs(x, 0, 0, 'conflicting takes no arguments')
+    return [r for r in subset if r in repo._conflictingset]
+
+
+@eh.revset('obsparents')
+@eh.revset('precursors')
+def revsetprecursors(repo, subset, x):
+    """``precursors(set)``
+    Immediate precursors of changesets in set.
+    """
+    s = revset.getset(repo, range(len(repo)), x)
+    cs = _precursors(repo, s)
+    return [r for r in subset if r in cs]
+
+
+@eh.revset('obsancestors')
+@eh.revset('allprecursors')
+def revsetallprecursors(repo, subset, x):
+    """``allprecursors(set)``
+    Transitive precursors of changesets in set.
+    """
+    s = revset.getset(repo, range(len(repo)), x)
+    cs = _allprecursors(repo, s)
+    return [r for r in subset if r in cs]
+
+
+@eh.revset('obschildrend')
+@eh.revset('successors')
+def revsetsuccessors(repo, subset, x):
+    """``successors(set)``
+    Immediate successors of changesets in set.
+    """
+    s = revset.getset(repo, range(len(repo)), x)
+    cs = _successors(repo, s)
+    return [r for r in subset if r in cs]
+
 @eh.revset('obsdescendants')
 @eh.revset('allsuccessors')
 def revsetallsuccessors(repo, subset, x):
@@ -505,9 +717,7 @@
     cs = _allsuccessors(repo, s)
     return [r for r in subset if r in cs]
 
-
 ### template keywords
-#####################
 
 @eh.templatekw('obsolete')
 def obsoletekw(repo, ctx, templ, **args):
@@ -523,9 +733,121 @@
         return 'unstable'
     return 'stable'
 
-### Other Extension compat
-############################
+#####################################################################
+### Various trouble warning                                       ###
+#####################################################################
+
+
+### Discovery wrapping
+
+@eh.wrapfunction(discovery, 'checkheads')
+def wrapcheckheads(orig, repo, remote, outgoing, *args, **kwargs):
+    """wrap mercurial.discovery.checkheads
+
+    * prevent unstability to be pushed
+    * patch remote to ignore obsolete heads on remote
+    """
+    # do not push instability
+    for h in outgoing.missingheads:
+        # Checking heads is enough, obsolete descendants are either
+        # obsolete or unstable.
+        ctx = repo[h]
+        if ctx.latecomer():
+            raise util.Abort(_("push includes a latecomer changeset: %s!")
+                             % ctx)
+        if ctx.conflicting():
+            raise util.Abort(_("push includes a conflicting changeset: %s!")
+                             % ctx)
+    return orig(repo, remote, outgoing, *args, **kwargs)
+
+@eh.wrapcommand("update")
+@eh.wrapcommand("pull")
+def wrapmayobsoletewc(origfn, ui, repo, *args, **opts):
+    res = origfn(ui, repo, *args, **opts)
+    if repo['.'].obsolete():
+        ui.warn(_('Working directory parent is obsolete\n'))
+    return res
 
+@eh.wrapcommand("commit")
+@eh.wrapcommand("push")
+@eh.wrapcommand("pull")
+@eh.wrapcommand("graft")
+@eh.wrapcommand("phase")
+@eh.wrapcommand("unbundle")
+def warnobserrors(orig, ui, repo, *args, **kwargs):
+    """display warning is the command resulted in more instable changeset"""
+    priorunstables = len(repo.revs('unstable()'))
+    priorlatecomers = len(repo.revs('latecomer()'))
+    priorconflictings = len(repo.revs('conflicting()'))
+    #print orig, priorunstables
+    #print len(repo.revs('secret() - obsolete()'))
+    try:
+        return orig(ui, repo, *args, **kwargs)
+    finally:
+        newunstables = len(repo.revs('unstable()')) - priorunstables
+        newlatecomers = len(repo.revs('latecomer()')) - priorlatecomers
+        newconflictings = len(repo.revs('conflicting()')) - priorconflictings
+        #print orig, newunstables
+        #print len(repo.revs('secret() - obsolete()'))
+        if newunstables > 0:
+            ui.warn(_('%i new unstables changesets\n') % newunstables)
+        if newlatecomers > 0:
+            ui.warn(_('%i new latecomers changesets\n') % newlatecomers)
+        if newconflictings > 0:
+            ui.warn(_('%i new conflictings changesets\n') % newconflictings)
+
+@eh.reposetup
+def _repostabilizesetup(ui, repo):
+    if not repo.local():
+        return
+
+    opush = repo.push
+
+    class stabilizerrepo(repo.__class__):
+        def push(self, remote, *args, **opts):
+            """wrapper around pull that pull obsolete relation"""
+            try:
+                result = opush(remote, *args, **opts)
+            except util.Abort, ex:
+                hint = _("use 'hg stabilize' to get a stable history "
+                         "or --force to ignore warnings")
+                if (len(ex.args) >= 1
+                    and ex.args[0].startswith('push includes ')
+                    and ex.hint is None):
+                    ex.hint = hint
+                raise
+            return result
+    repo.__class__ = stabilizerrepo
+
+#####################################################################
+### Other extension compat                                        ###
+#####################################################################
+
+### commit --amend
+
+@eh.wrapfunction(cmdutil, 'amend')
+def wrapcmdutilamend(orig, ui, repo, commitfunc, old, *args, **kwargs):
+    oldnode = old.node()
+    new = orig(ui, repo, commitfunc, old, *args, **kwargs)
+    if new != oldnode:
+        lock = repo.lock()
+        try:
+            tr = repo.transaction('post-amend-obst')
+            try:
+                meta = {
+                    'date':  '%i %i' % util.makedate(),
+                    'user': ui.username(),
+                    }
+                repo.obsstore.create(tr, oldnode, [new], 0, meta)
+                tr.close()
+                repo._clearobsoletecache()
+            finally:
+                tr.release()
+        finally:
+            lock.release()
+    return new
+
+### rebase
 
 def buildstate(orig, repo, dest, rebaseset, *ags, **kws):
     """wrapper for rebase 's buildstate that exclude obsolete changeset"""
@@ -620,316 +942,6 @@
     except KeyError:
         pass  # rebase not found
 
-### Discovery wrapping
-#############################
-
-@eh.wrapfunction(discovery, 'checkheads')
-def wrapcheckheads(orig, repo, remote, outgoing, *args, **kwargs):
-    """wrap mercurial.discovery.checkheads
-
-    * prevent unstability to be pushed
-    * patch remote to ignore obsolete heads on remote
-    """
-    # do not push instability
-    for h in outgoing.missingheads:
-        # Checking heads is enough, obsolete descendants are either
-        # obsolete or unstable.
-        ctx = repo[h]
-        if ctx.latecomer():
-            raise util.Abort(_("push includes a latecomer changeset: %s!")
-                             % ctx)
-        if ctx.conflicting():
-            raise util.Abort(_("push includes a conflicting changeset: %s!")
-                             % ctx)
-    return orig(repo, remote, outgoing, *args, **kwargs)
-
-@eh.wrapfunction(phases, 'advanceboundary')
-def wrapclearcache(orig, repo, *args, **kwargs):
-    try:
-        return orig(repo, *args, **kwargs)
-    finally:
-        repo._clearobsoletecache()
-
-
-### New commands
-#############################
-
-cmdtable = {}
-command = cmdutil.command(cmdtable)
-
-
-
-@command('debugsuccessors', [], '')
-def cmddebugsuccessors(ui, repo):
-    """dump obsolete changesets and their successors
-
-    Each line matches an existing marker, the first identifier is the
-    obsolete changeset identifier, followed by it successors.
-    """
-    lock = repo.lock()
-    try:
-        allsuccessors = repo.obsstore.precursors
-        for old in sorted(allsuccessors):
-            successors = [sorted(m[1]) for m in allsuccessors[old]]
-            for i, group in enumerate(sorted(successors)):
-                ui.write('%s' % short(old))
-                for new in group:
-                    ui.write(' %s' % short(new))
-                ui.write('\n')
-    finally:
-        lock.release()
-
-### Altering existing command
-#############################
-
-@eh.wrapcommand("update")
-@eh.wrapcommand("pull")
-def wrapmayobsoletewc(origfn, ui, repo, *args, **opts):
-    res = origfn(ui, repo, *args, **opts)
-    if repo['.'].obsolete():
-        ui.warn(_('Working directory parent is obsolete\n'))
-    return res
-
-def warnobserrors(orig, ui, repo, *args, **kwargs):
-    """display warning is the command resulted in more instable changeset"""
-    priorunstables = len(repo.revs('unstable()'))
-    priorlatecomers = len(repo.revs('latecomer()'))
-    priorconflictings = len(repo.revs('conflicting()'))
-    #print orig, priorunstables
-    #print len(repo.revs('secret() - obsolete()'))
-    try:
-        return orig(ui, repo, *args, **kwargs)
-    finally:
-        newunstables = len(repo.revs('unstable()')) - priorunstables
-        newlatecomers = len(repo.revs('latecomer()')) - priorlatecomers
-        newconflictings = len(repo.revs('conflicting()')) - priorconflictings
-        #print orig, newunstables
-        #print len(repo.revs('secret() - obsolete()'))
-        if newunstables > 0:
-            ui.warn(_('%i new unstables changesets\n') % newunstables)
-        if newlatecomers > 0:
-            ui.warn(_('%i new latecomers changesets\n') % newlatecomers)
-        if newconflictings > 0:
-            ui.warn(_('%i new conflictings changesets\n') % newconflictings)
-
-@eh.extsetup
-def _coreobserrorwrapping(ui):
-    # warning about more obsolete
-    for cmd in ['commit', 'push', 'pull', 'graft', 'phase', 'unbundle']:
-        entry = extensions.wrapcommand(commands.table, cmd, warnobserrors)
-
-@eh.wrapfunction(cmdutil, 'amend')
-def wrapcmdutilamend(orig, ui, repo, commitfunc, old, *args, **kwargs):
-    oldnode = old.node()
-    new = orig(ui, repo, commitfunc, old, *args, **kwargs)
-    if new != oldnode:
-        lock = repo.lock()
-        try:
-            tr = repo.transaction('post-amend-obst')
-            try:
-                meta = {
-                    'date':  '%i %i' % util.makedate(),
-                    'user': ui.username(),
-                    }
-                repo.obsstore.create(tr, oldnode, [new], 0, meta)
-                tr.close()
-                repo._clearobsoletecache()
-            finally:
-                tr.release()
-        finally:
-            lock.release()
-    return new
-
-
-### diagnostique tools
-#############################
-
-def unstables(repo):
-    """Return all unstable changeset"""
-    return scmutil.revrange(repo, ['obsolete():: and (not obsolete())'])
-
-def newerversion(repo, obs):
-    """Return the newer version of an obsolete changeset"""
-    toproceed = set([(obs,)])
-    # XXX known optimization available
-    newer = set()
-    objectrels = repo.obsstore.precursors
-    while toproceed:
-        current = toproceed.pop()
-        assert len(current) <= 1, 'splitting not handled yet. %r' % current
-        current = [n for n in current if n != nullid]
-        if current:
-            n, = current
-            if n in objectrels:
-                markers = objectrels[n]
-                for mark in markers:
-                    toproceed.add(tuple(mark[1]))
-            else:
-                newer.add(tuple(current))
-        else:
-            newer.add(())
-    return sorted(newer)
-
-### repo subclassing
-#############################
-
-@eh.reposetup
-def _reposetup(ui, repo):
-    if not repo.local():
-        return
-
-    opush = repo.push
-    o_updatebranchcache = repo.updatebranchcache
-
-    o_hook = repo.hook
-
-
-    class obsoletingrepo(repo.__class__):
-
-        # workaround
-        def hook(self, name, throw=False, **args):
-            if 'pushkey' in name:
-                args.pop('new')
-                args.pop('old')
-            return o_hook(name, throw=False, **args)
-
-        # XXX move me on obssotre
-        @util.propertycache
-        def _obsoleteset(self):
-            """the set of obsolete revision"""
-            obs = set()
-            nm = self.changelog.nodemap
-            for prec in self.obsstore.precursors:
-                rev = nm.get(prec)
-                if rev is not None:
-                    obs.add(rev)
-            return obs
-
-        # XXX move me on obssotre
-        @util.propertycache
-        def _unstableset(self):
-            """the set of non obsolete revision with obsolete parent"""
-            return set(self.revs('(obsolete()::) - obsolete()'))
-
-        # XXX move me on obssotre
-        @util.propertycache
-        def _suspendedset(self):
-            """the set of obsolete parent with non obsolete descendant"""
-            return set(self.revs('obsolete() and obsolete()::unstable()'))
-
-        # XXX move me on obssotre
-        @util.propertycache
-        def _extinctset(self):
-            """the set of obsolete parent without non obsolete descendant"""
-            return set(self.revs('obsolete() - obsolete()::unstable()'))
-
-        # XXX move me on obssotre
-        @util.propertycache
-        def _latecomerset(self):
-            """the set of rev trying to obsolete public revision"""
-            query = 'allsuccessors(public()) - obsolete() - public()'
-            return set(self.revs(query))
-
-        # XXX move me on obssotre
-        @util.propertycache
-        def _conflictingset(self):
-            """the set of rev trying to obsolete public revision"""
-            conflicting = set()
-            obsstore = self.obsstore
-            newermap = {}
-            for ctx in self.set('(not public()) - obsolete()'):
-                prec = obsstore.successors.get(ctx.node(), ())
-                toprocess = set(prec)
-                while toprocess:
-                    prec = toprocess.pop()[0]
-                    if prec not in newermap:
-                        newermap[prec] = newerversion(self, prec)
-                    newer = [n for n in newermap[prec] if n] # filter kill
-                    if len(newer) > 1:
-                        conflicting.add(ctx.rev())
-                        break
-                toprocess.update(obsstore.successors.get(prec, ()))
-            return conflicting
-
-        def _clearobsoletecache(self):
-            if '_obsoleteset' in vars(self):
-                del self._obsoleteset
-            self._clearunstablecache()
-
-        def updatebranchcache(self):
-            o_updatebranchcache()
-            self._clearunstablecache()
-
-        def _clearunstablecache(self):
-            if '_unstableset' in vars(self):
-                del self._unstableset
-            if '_suspendedset' in vars(self):
-                del self._suspendedset
-            if '_extinctset' in vars(self):
-                del self._extinctset
-            if '_latecomerset' in vars(self):
-                del self._latecomerset
-            if '_conflictingset' in vars(self):
-                del self._conflictingset
-
-        # XXX kill me
-        def addobsolete(self, sub, obj):
-            """Add a relation marking that node <sub> is a new version of <obj>"""
-            assert sub != obj
-            if not repo[obj].phase():
-                if sub is None:
-                    self.ui.warn(
-                        _("trying to kill immutable changeset %(obj)s\n")
-                        % {'obj': short(obj)})
-                if sub is not None:
-                    self.ui.warn(
-                        _("%(sub)s try to obsolete immutable changeset %(obj)s\n")
-                        % {'sub': short(sub), 'obj': short(obj)})
-            lock = self.lock()
-            try:
-                tr = self.transaction('add-obsolete')
-                try:
-                    meta = {
-                        'date':  '%i %i' % util.makedate(),
-                        'user': ui.username(),
-                        }
-                    subs = (sub == nullid) and [] or [sub]
-                    mid = self.obsstore.create(tr, obj, subs, 0, meta)
-                    tr.close()
-                    self._clearobsoletecache()
-                    return mid
-                finally:
-                    tr.release()
-            finally:
-                lock.release()
-
-        # XXX kill me
-        def addcollapsedobsolete(self, oldnodes, newnode):
-            """Mark oldnodes as collapsed into newnode."""
-            # Assume oldnodes are all descendants of a single rev
-            rootrevs = self.revs('roots(%ln)', oldnodes)
-            assert len(rootrevs) == 1, rootrevs
-            #rootnode = self[rootrevs[0]].node()
-            for n in oldnodes:
-                self.addobsolete(newnode, n)
-
-        ### pull // push support
-
-        def push(self, remote, *args, **opts):
-            """wrapper around pull that pull obsolete relation"""
-            try:
-                result = opush(remote, *args, **opts)
-            except util.Abort, ex:
-                hint = _("use 'hg stabilize' to get a stable history "
-                         "or --force to ignore warnings")
-                if (len(ex.args) >= 1
-                    and ex.args[0].startswith('push includes ')
-                    and ex.hint is None):
-                    ex.hint = hint
-                raise
-            return result
-    repo.__class__ = obsoletingrepo
-
 
 #####################################################################
 ### Older format management                                       ###