hgext3rd/evolve/stablerange.py
changeset 3243 556316fe4b4f
parent 3240 9361149224a7
child 3244 d5a7edd5d008
--- a/hgext3rd/evolve/stablerange.py	Wed Nov 29 12:48:45 2017 -0500
+++ b/hgext3rd/evolve/stablerange.py	Thu Nov 23 16:34:50 2017 +0100
@@ -7,7 +7,6 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import collections
 import heapq
 import math
 import os
@@ -16,8 +15,6 @@
 import weakref
 
 from mercurial import (
-    commands,
-    cmdutil,
     error,
     localrepo,
     node as nodemod,
@@ -29,12 +26,12 @@
 from mercurial.i18n import _
 
 from . import (
-    depthcache,
+    stablesort,
     exthelper,
 )
 
 eh = exthelper.exthelper()
-eh.merge(depthcache.eh)
+eh.merge(stablesort.eh)
 
 # prior to hg-4.2 there are not util.timer
 if util.safehasattr(util, 'timer'):
@@ -46,106 +43,6 @@
 else:
     timer = time.time
 
-##################################
-### Stable topological sorting ###
-##################################
-@eh.command(
-    'debugstablesort',
-    [
-        ('', 'rev', [], 'heads to start from'),
-    ] + commands.formatteropts,
-    _(''))
-def debugstablesort(ui, repo, **opts):
-    """display the ::REVS set topologically sorted in a stable way
-    """
-    revs = scmutil.revrange(repo, opts['rev'])
-    displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
-    for r in stablesort(repo, revs):
-        ctx = repo[r]
-        displayer.show(ctx)
-        displayer.flush(ctx)
-    displayer.close()
-
-def stablesort(repo, revs, mergecallback=None):
-    """return '::revs' topologically sorted in "stable" order
-
-    This is a depth first traversal starting from 'nullrev', using node as a
-    tie breaker.
-    """
-    # Various notes:
-    #
-    # * Bitbucket is used dates as tie breaker, that might be a good idea.
-    #
-    # * It seemds we can traverse in the same order from (one) head to bottom,
-    #   if we the following record data for each merge:
-    #
-    #  - highest (stablesort-wise) common ancestors,
-    #  - order of parents (tablesort-wise)
-    cl = repo.changelog
-    parents = cl.parentrevs
-    nullrev = nodemod.nullrev
-    n = cl.node
-    # step 1: We need a parents -> children mapping for 2 reasons.
-    #
-    # * we build the order from nullrev to tip
-    #
-    # * we need to detect branching
-    children = collections.defaultdict(list)
-    for r in cl.ancestors(revs, inclusive=True):
-        p1, p2 = parents(r)
-        children[p1].append(r)
-        if p2 != nullrev:
-            children[p2].append(r)
-    # step two: walk back up
-    # * pick lowest node in case of branching
-    # * stack disregarded part of the branching
-    # * process merge when both parents are yielded
-
-    # track what changeset has been
-    seen = [0] * (max(revs) + 2)
-    seen[-1] = True # nullrev is known
-    # starts from repository roots
-    # reuse the list form the mapping as we won't need it again anyway
-    stack = children[nullrev]
-    if not stack:
-        return []
-    if 1 < len(stack):
-        stack.sort(key=n, reverse=True)
-
-    # list of rev, maybe we should yield, but since we built a children mapping we are 'O(N)' already
-    result = []
-
-    current = stack.pop()
-    while current is not None or stack:
-        if current is None:
-            # previous iteration reached a merge or an unready merge,
-            current = stack.pop()
-            if seen[current]:
-                current = None
-                continue
-        p1, p2 = parents(current)
-        if not (seen[p1] and seen[p2]):
-            # we can't iterate on this merge yet because other child is not
-            # yielded yet (and we are topo sorting) we can discard it for now
-            # because it will be reached from the other child.
-            current = None
-            continue
-        assert not seen[current]
-        seen[current] = True
-        result.append(current) # could be yield, cf earlier comment
-        if mergecallback is not None and p2 != nullrev:
-            mergecallback(result, current)
-        cs = children[current]
-        if not cs:
-            current = None
-        elif 1 == len(cs):
-            current = cs[0]
-        else:
-            cs.sort(key=n, reverse=True)
-            current = cs.pop() # proceed on smallest
-            stack.extend(cs)   # stack the rest for later
-    assert len(result) == len(set(result))
-    return result
 
 #################################
 ### Stable Range computation  ###
@@ -369,8 +266,9 @@
             if allrevs is None:
                 allrevs = self._getrevsfrommerge(repo, headrev)
                 if allrevs is None:
-                    allrevs = stablesort(repo, [headrev],
-                                         mergecallback=self._filestablesortcache)
+                    mc = self._filestablesortcache
+                    allrevs = stablesort.stablesort(repo, [headrev],
+                                                    mergecallback=mc)
                 self._stablesortcache[headrev] = allrevs
             # takes from index
             revs = allrevs[index:]