--- a/hgext/evolve.py Wed Oct 10 15:11:31 2012 +0200
+++ b/hgext/evolve.py Wed Oct 10 15:26:09 2012 +0200
@@ -313,184 +313,10 @@
yield marker
-#####################################################################
-### Obsolescence Caching Logic ###
-#####################################################################
-
-# IN CORE fb72eec7efd8
-
-# Obsolescence related logic can be very slow if we don't have efficient cache.
-#
-# This section implements a cache mechanism that did not make it into core for
-# time reason. It stores meaningful set of revisions related to obsolescence
-# (obsolete, unstable, etc.)
-#
-# Here is:
-#
-# - Computation of meaningful sets
-# - Cache access logic,
-# - Cache invalidation logic,
-# - revset and ctx using this cache.
-#
-
-
-### Computation of meaningful set
-#
-# Most set can be computed with "simple" revset.
-
-#: { set name -> function to compute this set } mapping
-#: function take a single "repo" argument.
-#:
-#: Use the `cachefor` decorator to register new cache function
-try:
- cachefuncs = obsolete.cachefuncs
- cachefor = obsolete.cachefor
- getobscache = obsolete.getobscache
- clearobscaches = obsolete.clearobscaches
-except AttributeError:
- cachefuncs = {}
-
- def cachefor(name):
- """Decorator to register a function as computing the cache for a set"""
- def decorator(func):
- assert name not in cachefuncs
- cachefuncs[name] = func
- return func
- return decorator
-
- @cachefor('obsolete')
- def _computeobsoleteset(repo):
- """the set of obsolete revisions"""
- obs = set()
- nm = repo.changelog.nodemap
- for prec in repo.obsstore.precursors:
- rev = nm.get(prec)
- if rev is not None:
- obs.add(rev)
- return set(repo.revs('%ld - public()', obs))
-
- @cachefor('unstable')
- def _computeunstableset(repo):
- """the set of non obsolete revisions with obsolete parents"""
- return set(repo.revs('(obsolete()::) - obsolete()'))
-
- @cachefor('suspended')
- def _computesuspendedset(repo):
- """the set of obsolete parents with non obsolete descendants"""
- return set(repo.revs('obsolete() and obsolete()::unstable()'))
-
- @cachefor('extinct')
- def _computeextinctset(repo):
- """the set of obsolete parents without non obsolete descendants"""
- return set(repo.revs('obsolete() - obsolete()::unstable()'))
-
- @eh.wrapfunction(obsolete.obsstore, '__init__')
- def _initobsstorecache(orig, obsstore, *args, **kwargs):
- """add a cache attribute to obsstore"""
- obsstore.caches = {}
- return orig(obsstore, *args, **kwargs)
-
-### Cache access
-
- def getobscache(repo, name):
- """Return the set of revision that belong to the <name> set
-
- Such access may compute the set and cache it for future use"""
- if not repo.obsstore:
- return ()
- if name not in repo.obsstore.caches:
- repo.obsstore.caches[name] = cachefuncs[name](repo)
- return repo.obsstore.caches[name]
-
-### Cache clean up
-#
-# To be simple we need to invalidate obsolescence cache when:
-#
-# - new changeset is added:
-# - public phase is changed
-# - obsolescence marker are added
-# - strip is used a repo
-
-
- def clearobscaches(repo):
- """Remove all obsolescence related cache from a repo
-
- This remove all cache in obsstore is the obsstore already exist on the
- repo.
-
- (We could be smarter here)"""
- if 'obsstore' in repo._filecache:
- repo.obsstore.caches.clear()
-
- @eh.wrapfunction(localrepo.localrepository, 'addchangegroup') # new changeset
- @eh.wrapfunction(phases, 'retractboundary') # phase movement
- @eh.wrapfunction(phases, 'advanceboundary') # phase movement
- @eh.wrapfunction(localrepo.localrepository, 'destroyed') # strip
- def wrapclearcache(orig, repo, *args, **kwargs):
- try:
- return orig(repo, *args, **kwargs)
- finally:
- # we are a bit wide here
- # we could restrict to:
- # advanceboundary + phase==public
- # retractboundary + phase==draft
- clearobscaches(repo)
-
- @eh.wrapfunction(obsolete.obsstore, 'add') # new marker
- def clearonadd(orig, obsstore, *args, **kwargs):
- try:
- return orig(obsstore, *args, **kwargs)
- finally:
- obsstore.caches.clear()
-
-### Use the case
-# Function in core that could benefic from the cache are overwritten by cache using version
-
-# changectx method
-
- @eh.addattr(context.changectx, 'unstable')
- def unstable(ctx):
- """is the changeset unstable (have obsolete ancestor)"""
- if ctx.node() is None:
- return False
- return ctx.rev() in getobscache(ctx._repo, 'unstable')
-
-
- @eh.addattr(context.changectx, 'extinct')
- def extinct(ctx):
- """is the changeset extinct by other"""
- if ctx.node() is None:
- return False
- return ctx.rev() in getobscache(ctx._repo, 'extinct')
-
-# revset
-
- @eh.revset('obsolete')
- def revsetobsolete(repo, subset, x):
- """``obsolete()``
- Changeset is obsolete.
- """
- args = revset.getargs(x, 0, 0, 'obsolete takes no argument')
- obsoletes = getobscache(repo, 'obsolete')
- return [r for r in subset if r in obsoletes]
-
- @eh.revset('unstable')
- def revsetunstable(repo, subset, x):
- """``unstable()``
- Unstable changesets are non-obsolete with obsolete ancestors.
- """
- args = revset.getargs(x, 0, 0, 'unstable takes no arguments')
- unstables = getobscache(repo, 'unstable')
- return [r for r in subset if r in unstables]
-
- @eh.revset('extinct')
- def revsetextinct(repo, subset, x):
- """``extinct()``
- Obsolete changesets with obsolete descendants only.
- """
- args = revset.getargs(x, 0, 0, 'extinct takes no arguments')
- extincts = getobscache(repo, 'extinct')
- return [r for r in subset if r in extincts]
+cachefuncs = obsolete.cachefuncs
+cachefor = obsolete.cachefor
+getobscache = obsolete.getobscache
+clearobscaches = obsolete.clearobscaches
#####################################################################
### Complete troubles computation logic ###
@@ -650,44 +476,7 @@
# - function to travel throught the obsolescence graph
# - function to find useful changeset to stabilize
-### Marker Create
-# NOW IN CORE f85816af6294
-try:
- createmarkers = obsolete.createmarkers
-except AttributeError:
- def createmarkers(repo, relations, metadata=None, flag=0):
- """Add obsolete markers between changeset in a repo
-
- <relations> must be an iterable of (<old>, (<new>, ...)) tuple.
- `old` and `news` are changectx.
-
- Current user and date are used except if specified otherwise in the
- metadata attribute.
-
- /!\ assume the repo have been locked by the user /!\
- """
- # prepare metadata
- if metadata is None:
- metadata = {}
- if 'date' not in metadata:
- metadata['date'] = '%i %i' % util.makedate()
- if 'user' not in metadata:
- metadata['user'] = repo.ui.username()
- # check future marker
- tr = repo.transaction('add-obsolescence-marker')
- try:
- for prec, sucs in relations:
- if not prec.mutable():
- raise util.Abort("cannot obsolete immutable changeset: %s" % prec)
- nprec = prec.node()
- nsucs = tuple(s.node() for s in sucs)
- if nprec in nsucs:
- raise util.Abort("changeset %s cannot obsolete himself" % prec)
- repo.obsstore.create(tr, nprec, nsucs, flag, metadata)
- clearobscaches(repo)
- tr.close()
- finally:
- tr.release()
+createmarkers = obsolete.createmarkers
### Useful alias
@@ -841,16 +630,6 @@
# they are subject to changes
-if 'hidden' not in revset.symbols:
- # in 2.3+
- @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]
-
### XXX I'm not sure this revset is useful
@eh.revset('suspended')
def revsetsuspended(repo, subset, x):
@@ -1008,134 +787,6 @@
### Core Other extension compat ###
#####################################################################
-# This section make official history rewritter create obsolete marker
-
-
-### commit --amend
-# make commit --amend create obsolete marker
-#
-# The precursor is still strip from the repository.
-
-# IN CORE 63e45aee46d4
-
-if getattr(cmdutil, 'obsolete', None) is None:
- @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()
- clearobscaches(repo)
- finally:
- tr.release()
- finally:
- lock.release()
- return new
-
-### rebase
-#
-# - ignore obsolete changeset
-# - create obsolete marker *instead of* striping
-
-def buildstate(orig, repo, dest, rebaseset, *ags, **kws):
- """wrapper for rebase 's buildstate that exclude obsolete changeset"""
-
- rebaseset = repo.revs('%ld - extinct()', rebaseset)
- if not rebaseset:
- repo.ui.warn(_('whole rebase set is extinct and ignored.\n'))
- return {}
- root = min(rebaseset)
- if (not getattr(repo, '_rebasekeep', False)
- and not repo[root].mutable()):
- raise util.Abort(_("can't rebase immutable changeset %s") % repo[root],
- hint=_('see hg help phases for details'))
- return orig(repo, dest, rebaseset, *ags, **kws)
-
-def defineparents(orig, repo, rev, target, state, *args, **kwargs):
- rebasestate = getattr(repo, '_rebasestate', None)
- if rebasestate is not None:
- repo._rebasestate = dict(state)
- repo._rebasetarget = target
- return orig(repo, rev, target, state, *args, **kwargs)
-
-def concludenode(orig, repo, rev, p1, *args, **kwargs):
- """wrapper for rebase 's concludenode that set obsolete relation"""
- newrev = orig(repo, rev, p1, *args, **kwargs)
- rebasestate = getattr(repo, '_rebasestate', None)
- if rebasestate is not None:
- if newrev is not None:
- nrev = repo[newrev].rev()
- else:
- nrev = p1
- repo._rebasestate[rev] = nrev
- return newrev
-
-def cmdrebase(orig, ui, repo, *args, **kwargs):
-
- reallykeep = kwargs.get('keep', False)
- kwargs = dict(kwargs)
- kwargs['keep'] = True
- repo._rebasekeep = reallykeep
-
- # We want to mark rebased revision as obsolete and set their
- # replacements if any. Doing it in concludenode() prevents
- # aborting the rebase, and is not called with all relevant
- # revisions in --collapse case. Instead, we try to track the
- # rebase state structure by sampling/updating it in
- # defineparents() and concludenode(). The obsolete markers are
- # added from this state after a successful call.
- repo._rebasestate = {}
- repo._rebasetarget = None
- try:
- l = repo.lock()
- try:
- res = orig(ui, repo, *args, **kwargs)
- if not reallykeep:
- # Filter nullmerge or unrebased entries
- repo._rebasestate = dict(p for p in repo._rebasestate.iteritems()
- if p[1] >= 0)
- if not res and not kwargs.get('abort') and repo._rebasestate:
- # Rebased revisions are assumed to be descendants of
- # targetrev. If a source revision is mapped to targetrev
- # or to another rebased revision, it must have been
- # removed.
- markers = []
- if kwargs.get('collapse'):
- # collapse assume revision disapear because they are all
- # in the created revision
- newrevs = set(repo._rebasestate.values())
- newrevs.remove(repo._rebasetarget)
- if newrevs:
- # we create new revision.
- # A single one by --collapse design
- assert len(newrevs) == 1
- new = tuple(repo[n] for n in newrevs)
- else:
- # every body died. no new changeset created
- new = (repo[repo._rebasetarget],)
- for rev, newrev in sorted(repo._rebasestate.items()):
- markers.append((repo[rev], new))
- else:
- # no collapse assume revision disapear because they are
- # contained in parent
- for rev, newrev in sorted(repo._rebasestate.items()):
- markers.append((repo[rev], (repo[newrev],)))
- createmarkers(repo, markers)
- return res
- finally:
- l.release()
- finally:
- delattr(repo, '_rebasestate')
- delattr(repo, '_rebasetarget')
@eh.extsetup
def _rebasewrapping(ui):
@@ -1143,14 +794,7 @@
try:
rebase = extensions.find('rebase')
if rebase:
- incore = getattr(rebase, 'obsolete', None) is not None
- if not incore:
- extensions.wrapcommand(rebase.cmdtable, "rebase", cmdrebase)
extensions.wrapcommand(rebase.cmdtable, 'rebase', warnobserrors)
- if not incore:
- extensions.wrapfunction(rebase, 'buildstate', buildstate)
- extensions.wrapfunction(rebase, 'defineparents', defineparents)
- extensions.wrapfunction(rebase, 'concludenode', concludenode)
except KeyError:
pass # rebase not found