# HG changeset patch # User Pulkit Goyal <7895pulkit@gmail.com> # Date 1516357538 -19800 # Node ID 908d2b5dfa7e6484961891f08b659c1b6c7e61d4 # Parent f994c480cea91dadf971ae77a35d9208d4af7387 evolvecmd: move more code from __init__.py to evolvecmd.py We are now very close to have most of the evolve related code in evolvecmd.py. diff -r f994c480cea9 -r 908d2b5dfa7e hgext3rd/evolve/__init__.py --- a/hgext3rd/evolve/__init__.py Fri Jan 19 15:22:28 2018 +0530 +++ b/hgext3rd/evolve/__init__.py Fri Jan 19 15:55:38 2018 +0530 @@ -347,7 +347,6 @@ aliases, entry = cmdutil.findcmd('commit', commands.table) commitopts3 = cmdrewrite.commitopts3 interactiveopt = cmdrewrite.interactiveopt -_bookmarksupdater = rewriteutil.bookmarksupdater rewrite = rewriteutil.rewrite # This extension contains the following code @@ -1113,60 +1112,6 @@ rdependencies[succ].add(r) return dependencies, rdependencies -def _dedupedivergents(repo, revs): - """Dedupe the divergents revs in revs to get one from each group with the - lowest revision numbers - """ - repo = repo.unfiltered() - res = set() - # To not reevaluate divergents of the same group once one is encountered - discarded = set() - for rev in revs: - if rev in discarded: - continue - divergent = repo[rev] - base, others = divergentdata(divergent) - othersrevs = [o.rev() for o in others] - res.add(min([divergent.rev()] + othersrevs)) - discarded.update(othersrevs) - return res - -instabilities_map = { - 'contentdivergent': "content-divergent", - 'phasedivergent': "phase-divergent" -} - -def _selectrevs(repo, allopt, revopt, anyopt, targetcat): - """select troubles in repo matching according to given options""" - revs = set() - if allopt or revopt: - revs = repo.revs("%s()" % targetcat) - if revopt: - revs = scmutil.revrange(repo, revopt) & revs - elif not anyopt: - topic = getattr(repo, 'currenttopic', '') - if topic: - revs = repo.revs('topic(%s)', topic) & revs - elif targetcat == 'orphan': - revs = _aspiringdescendant(repo, - repo.revs('(.::) - obsolete()::')) - revs = set(revs) - if targetcat == 'contentdivergent': - # Pick one divergent per group of divergents - revs = _dedupedivergents(repo, revs) - elif anyopt: - revs = repo.revs('first(%s())' % (targetcat)) - elif targetcat == 'orphan': - revs = set(_aspiringchildren(repo, repo.revs('(.::) - obsolete()::'))) - if 1 < len(revs): - msg = "multiple evolve candidates" - hint = (_("select one of %s with --rev") - % ', '.join([str(repo[r]) for r in sorted(revs)])) - raise error.Abort(msg, hint=hint) - elif instabilities_map.get(targetcat, targetcat) in repo['.'].instabilities(): - revs = set([repo['.'].rev()]) - return revs - def _orderrevs(repo, revs): """Compute an ordering to solve instability for the given revs @@ -1505,7 +1450,7 @@ cmdutil.bailifchanged(repo) - revs = _selectrevs(repo, allopt, revopt, anyopt, targetcat) + revs = evolvecmd._selectrevs(repo, allopt, revopt, anyopt, targetcat) if not revs: return _handlenotrouble(ui, repo, allopt, revopt, anyopt, targetcat) @@ -1567,75 +1512,6 @@ return opts -def _possibledestination(repo, rev): - """return all changesets that may be a new parent for REV""" - tonode = repo.changelog.node - parents = repo.changelog.parentrevs - torev = repo.changelog.rev - dest = set() - tovisit = list(parents(rev)) - while tovisit: - r = tovisit.pop() - succsets = compat.successorssets(repo, tonode(r)) - if not succsets: - tovisit.extend(parents(r)) - else: - # We should probably pick only one destination from split - # (case where '1 < len(ss)'), This could be the currently tipmost - # but logic is less clear when result of the split are now on - # multiple branches. - for ss in succsets: - for n in ss: - dest.add(torev(n)) - return dest - -def _aspiringchildren(repo, revs): - """Return a list of changectx which can be stabilized on top of pctx or - one of its descendants. Empty list if none can be found.""" - target = set(revs) - result = [] - for r in repo.revs('orphan() - %ld', revs): - dest = _possibledestination(repo, r) - if target & dest: - result.append(r) - return result - -def _aspiringdescendant(repo, revs): - """Return a list of changectx which can be stabilized on top of pctx or - one of its descendants recursively. Empty list if none can be found.""" - target = set(revs) - result = set(target) - paths = collections.defaultdict(set) - for r in repo.revs('orphan() - %ld', revs): - for d in _possibledestination(repo, r): - paths[d].add(r) - - result = set(target) - tovisit = list(revs) - while tovisit: - base = tovisit.pop() - for unstable in paths[base]: - if unstable not in result: - tovisit.append(unstable) - result.add(unstable) - return sorted(result - target) - -def divergentdata(ctx): - """return base, other part of a conflict - - This only return the first one. - - XXX this woobly function won't survive XXX - """ - repo = ctx._repo.unfiltered() - for base in repo.set('reverse(allprecursors(%d))', ctx): - newer = compat.successorssets(ctx._repo, base.node()) - # drop filter and solution including the original ctx - newer = [n for n in newer if n and ctx.node() not in n] - if newer: - return base, tuple(ctx._repo[o] for o in newer[0]) - raise error.Abort("base of divergent changeset %s not found" % ctx, - hint='this case is not yet handled') def _gettopic(ctx): """handle topic fetching with or without the extension""" @@ -1826,7 +1702,7 @@ ui.warn(_('explicitly update to one of them\n')) result = 1 else: - aspchildren = _aspiringchildren(repo, [repo['.'].rev()]) + aspchildren = evolvecmd._aspiringchildren(repo, [repo['.'].rev()]) if topic: filtered.extend(repo[c] for c in children if repo[c].topic() != topic) diff -r f994c480cea9 -r 908d2b5dfa7e hgext3rd/evolve/evolvecmd.py --- a/hgext3rd/evolve/evolvecmd.py Fri Jan 19 15:22:28 2018 +0530 +++ b/hgext3rd/evolve/evolvecmd.py Fri Jan 19 15:55:38 2018 +0530 @@ -8,6 +8,7 @@ """logic related to hg evolve command""" +import collections import re from mercurial import ( @@ -22,6 +23,7 @@ node, obsolete, phases, + scmutil, util, ) @@ -40,7 +42,7 @@ _bookmarksupdater = rewriteutil.bookmarksupdater sha1re = re.compile(r'\b[0-9a-f]{6,40}\b') -from . import divergentdata +_bookmarksupdater = rewriteutil.bookmarksupdater def _solveone(ui, repo, ctx, dryrun, confirm, progresscb, category): """Resolve the troubles affecting one revision @@ -526,3 +528,127 @@ f.write(orig.topic()) return merge.graft(repo, orig, pctx, ['destination', 'evolving'], True) + +instabilities_map = { + 'contentdivergent': "content-divergent", + 'phasedivergent': "phase-divergent" +} + +def _selectrevs(repo, allopt, revopt, anyopt, targetcat): + """select troubles in repo matching according to given options""" + revs = set() + if allopt or revopt: + revs = repo.revs("%s()" % targetcat) + if revopt: + revs = scmutil.revrange(repo, revopt) & revs + elif not anyopt: + topic = getattr(repo, 'currenttopic', '') + if topic: + revs = repo.revs('topic(%s)', topic) & revs + elif targetcat == 'orphan': + revs = _aspiringdescendant(repo, + repo.revs('(.::) - obsolete()::')) + revs = set(revs) + if targetcat == 'contentdivergent': + # Pick one divergent per group of divergents + revs = _dedupedivergents(repo, revs) + elif anyopt: + revs = repo.revs('first(%s())' % (targetcat)) + elif targetcat == 'orphan': + revs = set(_aspiringchildren(repo, repo.revs('(.::) - obsolete()::'))) + if 1 < len(revs): + msg = "multiple evolve candidates" + hint = (_("select one of %s with --rev") + % ', '.join([str(repo[r]) for r in sorted(revs)])) + raise error.Abort(msg, hint=hint) + elif instabilities_map.get(targetcat, targetcat) in repo['.'].instabilities(): + revs = set([repo['.'].rev()]) + return revs + +def _dedupedivergents(repo, revs): + """Dedupe the divergents revs in revs to get one from each group with the + lowest revision numbers + """ + repo = repo.unfiltered() + res = set() + # To not reevaluate divergents of the same group once one is encountered + discarded = set() + for rev in revs: + if rev in discarded: + continue + divergent = repo[rev] + base, others = divergentdata(divergent) + othersrevs = [o.rev() for o in others] + res.add(min([divergent.rev()] + othersrevs)) + discarded.update(othersrevs) + return res + +def divergentdata(ctx): + """return base, other part of a conflict + + This only return the first one. + + XXX this woobly function won't survive XXX + """ + repo = ctx._repo.unfiltered() + for base in repo.set('reverse(allprecursors(%d))', ctx): + newer = compat.successorssets(ctx._repo, base.node()) + # drop filter and solution including the original ctx + newer = [n for n in newer if n and ctx.node() not in n] + if newer: + return base, tuple(ctx._repo[o] for o in newer[0]) + raise error.Abort("base of divergent changeset %s not found" % ctx, + hint='this case is not yet handled') + +def _aspiringdescendant(repo, revs): + """Return a list of changectx which can be stabilized on top of pctx or + one of its descendants recursively. Empty list if none can be found.""" + target = set(revs) + result = set(target) + paths = collections.defaultdict(set) + for r in repo.revs('orphan() - %ld', revs): + for d in _possibledestination(repo, r): + paths[d].add(r) + + result = set(target) + tovisit = list(revs) + while tovisit: + base = tovisit.pop() + for unstable in paths[base]: + if unstable not in result: + tovisit.append(unstable) + result.add(unstable) + return sorted(result - target) + +def _aspiringchildren(repo, revs): + """Return a list of changectx which can be stabilized on top of pctx or + one of its descendants. Empty list if none can be found.""" + target = set(revs) + result = [] + for r in repo.revs('orphan() - %ld', revs): + dest = _possibledestination(repo, r) + if target & dest: + result.append(r) + return result + +def _possibledestination(repo, rev): + """return all changesets that may be a new parent for REV""" + tonode = repo.changelog.node + parents = repo.changelog.parentrevs + torev = repo.changelog.rev + dest = set() + tovisit = list(parents(rev)) + while tovisit: + r = tovisit.pop() + succsets = compat.successorssets(repo, tonode(r)) + if not succsets: + tovisit.extend(parents(r)) + else: + # We should probably pick only one destination from split + # (case where '1 < len(ss)'), This could be the currently tipmost + # but logic is less clear when result of the split are now on + # multiple branches. + for ss in succsets: + for n in ss: + dest.add(torev(n)) + return dest