comparison hgext3rd/topic/stack.py @ 1982:d87fc4f749e6

evolve: extract the code copied from evolve in a submodule This will allow us to use that code in other module.
author Pierre-Yves David <pierre-yves.david@ens-lyon.org>
date Mon, 15 Aug 2016 05:15:19 +0200
parents bee7a1ef8ba8
children 03d6b685c16a
comparison
equal deleted inserted replaced
1981:b467fe430404 1982:d87fc4f749e6
1 # stack.py - code related to stack workflow 1 # stack.py - code related to stack workflow
2 # 2 #
3 # This software may be used and distributed according to the terms of the 3 # This software may be used and distributed according to the terms of the
4 # GNU General Public License version 2 or any later version. 4 # GNU General Public License version 2 or any later version.
5 import collections
6 from mercurial.i18n import _ 5 from mercurial.i18n import _
7 from mercurial import ( 6 from mercurial import (
8 error, 7 error,
9 node, 8 node,
10 obsolete,
11 ) 9 )
10 from .evolvebits import builddependencies, _orderrevs, _singlesuccessor
12 11
13 def getstack(repo, topic): 12 def getstack(repo, topic):
14 # XXX need sorting 13 # XXX need sorting
15 trevs = repo.revs("topic(%s) - obsolete()", topic) 14 trevs = repo.revs("topic(%s) - obsolete()", topic)
16 return _orderrevs(repo, trevs) 15 return _orderrevs(repo, trevs)
78 deps, rdeps = builddependencies(repo, revs) 77 deps, rdeps = builddependencies(repo, revs)
79 data['headcount'] = len([r for r in revs if not rdeps[r]]) 78 data['headcount'] = len([r for r in revs if not rdeps[r]])
80 79
81 return data 80 return data
82 81
83 # Copied from evolve 081605c2e9b6
84
85 def _orderrevs(repo, revs):
86 """Compute an ordering to solve instability for the given revs
87
88 revs is a list of unstable revisions.
89
90 Returns the same revisions ordered to solve their instability from the
91 bottom to the top of the stack that the stabilization process will produce
92 eventually.
93
94 This ensures the minimal number of stabilizations, as we can stabilize each
95 revision on its final stabilized destination.
96 """
97 # Step 1: Build the dependency graph
98 dependencies, rdependencies = builddependencies(repo, revs)
99 # Step 2: Build the ordering
100 # Remove the revisions with no dependency(A) and add them to the ordering.
101 # Removing these revisions leads to new revisions with no dependency (the
102 # one depending on A) that we can remove from the dependency graph and add
103 # to the ordering. We progress in a similar fashion until the ordering is
104 # built
105 solvablerevs = [r for r in sorted(dependencies.keys())
106 if not dependencies[r]]
107 ordering = []
108 while solvablerevs:
109 rev = solvablerevs.pop()
110 for dependent in rdependencies[rev]:
111 dependencies[dependent].remove(rev)
112 if not dependencies[dependent]:
113 solvablerevs.append(dependent)
114 del dependencies[rev]
115 ordering.append(rev)
116
117 ordering.extend(sorted(dependencies))
118 return ordering
119
120 def builddependencies(repo, revs):
121 """returns dependency graphs giving an order to solve instability of revs
122 (see _orderrevs for more information on usage)"""
123
124 # For each troubled revision we keep track of what instability if any should
125 # be resolved in order to resolve it. Example:
126 # dependencies = {3: [6], 6:[]}
127 # Means that: 6 has no dependency, 3 depends on 6 to be solved
128 dependencies = {}
129 # rdependencies is the inverted dict of dependencies
130 rdependencies = collections.defaultdict(set)
131
132 for r in revs:
133 dependencies[r] = set()
134 for p in repo[r].parents():
135 try:
136 succ = _singlesuccessor(repo, p)
137 except MultipleSuccessorsError as exc:
138 dependencies[r] = exc.successorssets
139 continue
140 if succ in revs:
141 dependencies[r].add(succ)
142 rdependencies[succ].add(r)
143 return dependencies, rdependencies
144
145 def _singlesuccessor(repo, p):
146 """returns p (as rev) if not obsolete or its unique latest successors
147
148 fail if there are no such successor"""
149
150 if not p.obsolete():
151 return p.rev()
152 obs = repo[p]
153 ui = repo.ui
154 newer = obsolete.successorssets(repo, obs.node())
155 # search of a parent which is not killed
156 while not newer:
157 ui.debug("stabilize target %s is plain dead,"
158 " trying to stabilize on its parent\n" %
159 obs)
160 obs = obs.parents()[0]
161 newer = obsolete.successorssets(repo, obs.node())
162 if len(newer) > 1 or len(newer[0]) > 1:
163 raise MultipleSuccessorsError(newer)
164
165 return repo[newer[0][0]].rev()
166
167 class MultipleSuccessorsError(RuntimeError):
168 """Exception raised by _singlesuccessor when multiple successor sets exists
169
170 The object contains the list of successorssets in its 'successorssets'
171 attribute to call to easily recover.
172 """
173
174 def __init__(self, successorssets):
175 self.successorssets = successorssets