--- a/hgext/obsolete.py Tue Aug 07 14:38:28 2012 +0200
+++ b/hgext/obsolete.py Tue Aug 07 15:02:54 2012 +0200
@@ -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 ###