rework refactor _aspiringchildren by introducing _possibledestination
authorPierre-Yves David <pierre-yves.david@fb.com>
Tue, 23 Jun 2015 00:02:23 -0700
changeset 1421 8f18c7b3af14
parent 1420 0b714c4ad9ff
child 1422 c868a69c29c5
rework refactor _aspiringchildren by introducing _possibledestination This allows us to reuse some of the logic for evolve from _aspiringchildren for the new implementation of evolve --all. The logic is also better as some previously selected changesets may not actually evolve on the target, and some changesets that does not would not.
hgext/evolve.py
--- a/hgext/evolve.py	Mon Jun 22 19:24:21 2015 -0700
+++ b/hgext/evolve.py	Tue Jun 23 00:02:23 2015 -0700
@@ -1410,7 +1410,7 @@
     elif anyopt:
         revs = repo.revs('first(%s())' % (targetcat))
     elif targetcat == 'unstable':
-        revs = set(_aspiringchildren(repo, repo['.']))
+        revs = set(_aspiringchildren(repo, repo.revs('(.::) - obsolete()::')))
         if 1 < len(revs):
             msg = "multiple evolve candidates"
             hint = (_("select one of %s with --rev")
@@ -1589,29 +1589,37 @@
     progresscb()
     _cleanup(ui, repo, startnode, showprogress)
 
-def _aspiringchildren(repo, pctx):
+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 = obsolete.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.
-    """
-    def selfanddescendants(repo, pctx):
-        yield pctx
-        for prec in repo.set('allprecursors(%d)', pctx):
-            yield prec
-        for ctx in pctx.descendants():
-            yield ctx
-            for prec in repo.set('allprecursors(%d)', ctx):
-                yield prec
-
-    # Look for an unstable which can be stabilized as a child of
-    # node. The unstable must be a child of one of node predecessors.
+    one of its descendants. Empty list if none can be found."""
+    target = set(revs)
     result = []
-    directdesc = set([pctx.rev()])
-    for ctx in selfanddescendants(repo, pctx):
-        for child in ctx.children():
-            if ctx.rev() in directdesc and not child.obsolete():
-                directdesc.add(child.rev())
-            elif child.unstable():
-                result.append(child)
+    for r in repo.revs('unstable() - %ld', revs):
+        dest = _possibledestination(repo, r)
+        if target & dest:
+            result.append(r)
     return result
 
 def _solveunstable(ui, repo, orig, dryrun=False, confirm=False,