3246.2.2
by Martin Pool
Fix up import of tsort |
1 |
# Copyright (C) 2005, 2006, 2008 Canonical Ltd
|
1185.16.113
by mbp at sourcefrog
Add topo_sort utility function |
2 |
#
|
3 |
# This program is free software; you can redistribute it and/or modify
|
|
4 |
# it under the terms of the GNU General Public License as published by
|
|
5 |
# the Free Software Foundation; either version 2 of the License, or
|
|
6 |
# (at your option) any later version.
|
|
7 |
#
|
|
8 |
# This program is distributed in the hope that it will be useful,
|
|
9 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11 |
# GNU General Public License for more details.
|
|
12 |
#
|
|
13 |
# You should have received a copy of the GNU General Public License
|
|
14 |
# along with this program; if not, write to the Free Software
|
|
4183.7.1
by Sabin Iacob
update FSF mailing address |
15 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
1185.16.113
by mbp at sourcefrog
Add topo_sort utility function |
16 |
|
6379.6.7
by Jelmer Vernooij
Move importing from future until after doc string, otherwise the doc string will disappear. |
17 |
"""Topological sorting routines."""
|
18 |
||
6379.6.3
by Jelmer Vernooij
Use absolute_import. |
19 |
from __future__ import absolute_import |
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
20 |
|
21 |
||
4593.5.30
by John Arbash Meinel
Move the topo_sort implementation into KnownGraph, rather than calling back to it. |
22 |
from bzrlib import ( |
23 |
errors, |
|
24 |
graph as _mod_graph, |
|
25 |
revision as _mod_revision, |
|
26 |
)
|
|
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
27 |
|
1185.16.114
by mbp at sourcefrog
Improved topological sort |
28 |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
29 |
__all__ = ["topo_sort", "TopoSorter", "merge_sort", "MergeSorter"] |
30 |
||
31 |
||
1185.16.114
by mbp at sourcefrog
Improved topological sort |
32 |
def topo_sort(graph): |
1185.16.113
by mbp at sourcefrog
Add topo_sort utility function |
33 |
"""Topological sort a graph.
|
34 |
||
1185.16.114
by mbp at sourcefrog
Improved topological sort |
35 |
graph -- sequence of pairs of node->parents_list.
|
36 |
||
4593.5.3
by John Arbash Meinel
Bring in the optimized tsort code. |
37 |
The result is a list of node names, such that all parents come before their
|
38 |
children.
|
|
1185.16.114
by mbp at sourcefrog
Improved topological sort |
39 |
|
1185.16.113
by mbp at sourcefrog
Add topo_sort utility function |
40 |
node identifiers can be any hashable object, and are typically strings.
|
4577.2.3
by Maarten Bosmans
tsort.topo_sort: new algorithm, improving performance |
41 |
|
42 |
This function has the same purpose as the TopoSorter class, but uses a
|
|
4593.5.3
by John Arbash Meinel
Bring in the optimized tsort code. |
43 |
different algorithm to sort the graph. That means that while both return a
|
44 |
list with parents before their child nodes, the exact ordering can be
|
|
45 |
different.
|
|
4577.2.3
by Maarten Bosmans
tsort.topo_sort: new algorithm, improving performance |
46 |
|
4593.5.3
by John Arbash Meinel
Bring in the optimized tsort code. |
47 |
topo_sort is faster when the whole list is needed, while when iterating
|
48 |
over a part of the list, TopoSorter.iter_topo_order should be used.
|
|
1185.16.113
by mbp at sourcefrog
Add topo_sort utility function |
49 |
"""
|
4593.5.43
by John Arbash Meinel
The api for topo_sort() was to allow a list of (key, value) |
50 |
kg = _mod_graph.KnownGraph(dict(graph)) |
4593.5.30
by John Arbash Meinel
Move the topo_sort implementation into KnownGraph, rather than calling back to it. |
51 |
return kg.topo_sort() |
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
52 |
|
53 |
||
54 |
class TopoSorter(object): |
|
55 |
||
56 |
def __init__(self, graph): |
|
57 |
"""Topological sorting of a graph.
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
58 |
|
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
59 |
:param graph: sequence of pairs of node_name->parent_names_list.
|
60 |
i.e. [('C', ['B']), ('B', ['A']), ('A', [])]
|
|
61 |
For this input the output from the sort or
|
|
62 |
iter_topo_order routines will be:
|
|
63 |
'A', 'B', 'C'
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
64 |
|
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
65 |
node identifiers can be any hashable object, and are typically strings.
|
66 |
||
1587.1.2
by Robert Collins
Review comments for reconcile. |
67 |
If you have a graph like [('a', ['b']), ('a', ['c'])] this will only use
|
68 |
one of the two values for 'a'.
|
|
69 |
||
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
70 |
The graph is sorted lazily: until you iterate or sort the input is
|
71 |
not processed other than to create an internal representation.
|
|
72 |
||
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
73 |
iteration or sorting may raise GraphCycleError if a cycle is present
|
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
74 |
in the graph.
|
75 |
"""
|
|
4577.2.2
by Maarten Bosmans
tsort.TopoSorter: performance improvements |
76 |
# store a dict of the graph.
|
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
77 |
self._graph = dict(graph) |
78 |
||
79 |
def sorted(self): |
|
80 |
"""Sort the graph and return as a list.
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
81 |
|
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
82 |
After calling this the sorter is empty and you must create a new one.
|
83 |
"""
|
|
84 |
return list(self.iter_topo_order()) |
|
85 |
||
86 |
### Useful if fiddling with this code.
|
|
87 |
### # cross check
|
|
88 |
### sorted_names = list(self.iter_topo_order())
|
|
89 |
### for index in range(len(sorted_names)):
|
|
90 |
### rev = sorted_names[index]
|
|
91 |
### for left_index in range(index):
|
|
92 |
### if rev in self.original_graph[sorted_names[left_index]]:
|
|
93 |
### print "revision in parent list of earlier revision"
|
|
94 |
### import pdb;pdb.set_trace()
|
|
95 |
||
96 |
def iter_topo_order(self): |
|
1587.1.3
by Robert Collins
Typos for reconcile - docstring in tsort.py was out of sync with code. |
97 |
"""Yield the nodes of the graph in a topological order.
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
98 |
|
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
99 |
After finishing iteration the sorter is empty and you cannot continue
|
100 |
iteration.
|
|
101 |
"""
|
|
4577.2.2
by Maarten Bosmans
tsort.TopoSorter: performance improvements |
102 |
graph = self._graph |
103 |
visitable = set(graph) |
|
104 |
||
105 |
# this is a stack storing the depth first search into the graph.
|
|
106 |
pending_node_stack = [] |
|
107 |
# at each level of 'recursion' we have to check each parent. This
|
|
108 |
# stack stores the parents we have not yet checked for the node at the
|
|
109 |
# matching depth in pending_node_stack
|
|
110 |
pending_parents_stack = [] |
|
111 |
||
112 |
# this is a set of the completed nodes for fast checking whether a
|
|
113 |
# parent in a node we are processing on the stack has already been
|
|
114 |
# emitted and thus can be skipped.
|
|
115 |
completed_node_names = set() |
|
116 |
||
117 |
while graph: |
|
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
118 |
# now pick a random node in the source graph, and transfer it to the
|
4577.2.2
by Maarten Bosmans
tsort.TopoSorter: performance improvements |
119 |
# top of the depth first search stack of pending nodes.
|
120 |
node_name, parents = graph.popitem() |
|
121 |
pending_node_stack.append(node_name) |
|
122 |
pending_parents_stack.append(list(parents)) |
|
123 |
||
124 |
# loop until pending_node_stack is empty
|
|
125 |
while pending_node_stack: |
|
126 |
parents_to_visit = pending_parents_stack[-1] |
|
127 |
# if there are no parents left, the revision is done
|
|
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
128 |
if not parents_to_visit: |
129 |
# append the revision to the topo sorted list
|
|
4577.2.2
by Maarten Bosmans
tsort.TopoSorter: performance improvements |
130 |
# all the nodes parents have been added to the output,
|
131 |
# now we can add it to the output.
|
|
132 |
popped_node = pending_node_stack.pop() |
|
133 |
pending_parents_stack.pop() |
|
134 |
completed_node_names.add(popped_node) |
|
135 |
yield popped_node |
|
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
136 |
else: |
4577.2.2
by Maarten Bosmans
tsort.TopoSorter: performance improvements |
137 |
# recurse depth first into a single parent
|
138 |
next_node_name = parents_to_visit.pop() |
|
139 |
||
140 |
if next_node_name in completed_node_names: |
|
141 |
# parent was already completed by a child, skip it.
|
|
142 |
continue
|
|
143 |
if next_node_name not in visitable: |
|
144 |
# parent is not a node in the original graph, skip it.
|
|
145 |
continue
|
|
146 |
||
147 |
# transfer it along with its parents from the source graph
|
|
148 |
# into the top of the current depth first search stack.
|
|
149 |
try: |
|
150 |
parents = graph.pop(next_node_name) |
|
151 |
except KeyError: |
|
152 |
# if the next node is not in the source graph it has
|
|
153 |
# already been popped from it and placed into the
|
|
154 |
# current search stack (but not completed or we would
|
|
155 |
# have hit the continue 6 lines up). this indicates a
|
|
156 |
# cycle.
|
|
157 |
raise errors.GraphCycleError(pending_node_stack) |
|
158 |
pending_node_stack.append(next_node_name) |
|
159 |
pending_parents_stack.append(list(parents)) |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
160 |
|
161 |
||
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
162 |
def merge_sort(graph, branch_tip, mainline_revisions=None, generate_revno=False): |
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
163 |
"""Topological sort a graph which groups merges.
|
164 |
||
165 |
:param graph: sequence of pairs of node->parents_list.
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
166 |
:param branch_tip: the tip of the branch to graph. Revisions not
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
167 |
reachable from branch_tip are not included in the
|
168 |
output.
|
|
1624.1.3
by Robert Collins
Convert log to use the new tsort.merge_sort routine. |
169 |
:param mainline_revisions: If not None this forces a mainline to be
|
170 |
used rather than synthesised from the graph.
|
|
171 |
This must be a valid path through some part
|
|
172 |
of the graph. If the mainline does not cover all
|
|
173 |
the revisions, output stops at the start of the
|
|
174 |
old revision listed in the mainline revisions
|
|
175 |
list.
|
|
176 |
The order for this parameter is oldest-first.
|
|
1988.4.4
by Robert Collins
Tidy up the patch. |
177 |
:param generate_revno: Optional parameter controlling the generation of
|
178 |
revision number sequences in the output. See the output description of
|
|
179 |
the MergeSorter docstring for details.
|
|
180 |
:result: See the MergeSorter docstring for details.
|
|
5891.1.2
by Andrew Bennetts
Fix a bunch of docstring formatting nits, making pydoctor a bit happier. |
181 |
|
182 |
Node identifiers can be any hashable object, and are typically strings.
|
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
183 |
"""
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
184 |
return MergeSorter(graph, branch_tip, mainline_revisions, |
185 |
generate_revno).sorted() |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
186 |
|
187 |
||
188 |
class MergeSorter(object): |
|
189 |
||
2425.4.1
by John Arbash Meinel
Use __slots__ for MergeSorter |
190 |
__slots__ = ['_node_name_stack', |
191 |
'_node_merge_depth_stack', |
|
192 |
'_pending_parents_stack', |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
193 |
'_first_child_stack', |
2425.4.1
by John Arbash Meinel
Use __slots__ for MergeSorter |
194 |
'_left_subtree_pushed_stack', |
195 |
'_generate_revno', |
|
196 |
'_graph', |
|
197 |
'_mainline_revisions', |
|
198 |
'_stop_revision', |
|
199 |
'_original_graph', |
|
200 |
'_revnos', |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
201 |
'_revno_to_branch_count', |
2425.4.1
by John Arbash Meinel
Use __slots__ for MergeSorter |
202 |
'_completed_node_names', |
203 |
'_scheduled_nodes', |
|
204 |
]
|
|
205 |
||
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
206 |
def __init__(self, graph, branch_tip, mainline_revisions=None, |
207 |
generate_revno=False): |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
208 |
"""Merge-aware topological sorting of a graph.
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
209 |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
210 |
:param graph: sequence of pairs of node_name->parent_names_list.
|
211 |
i.e. [('C', ['B']), ('B', ['A']), ('A', [])]
|
|
212 |
For this input the output from the sort or
|
|
213 |
iter_topo_order routines will be:
|
|
214 |
'A', 'B', 'C'
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
215 |
:param branch_tip: the tip of the branch to graph. Revisions not
|
1624.1.3
by Robert Collins
Convert log to use the new tsort.merge_sort routine. |
216 |
reachable from branch_tip are not included in the
|
217 |
output.
|
|
218 |
:param mainline_revisions: If not None this forces a mainline to be
|
|
219 |
used rather than synthesised from the graph.
|
|
220 |
This must be a valid path through some part
|
|
221 |
of the graph. If the mainline does not cover all
|
|
222 |
the revisions, output stops at the start of the
|
|
223 |
old revision listed in the mainline revisions
|
|
224 |
list.
|
|
225 |
The order for this parameter is oldest-first.
|
|
1988.4.4
by Robert Collins
Tidy up the patch. |
226 |
:param generate_revno: Optional parameter controlling the generation of
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
227 |
revision number sequences in the output. See the output description
|
228 |
for more details.
|
|
229 |
||
1988.4.4
by Robert Collins
Tidy up the patch. |
230 |
The result is a list sorted so that all parents come before
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
231 |
their children. Each element of the list is a tuple containing:
|
232 |
(sequence_number, node_name, merge_depth, end_of_merge)
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
233 |
* sequence_number: The sequence of this row in the output. Useful for
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
234 |
GUIs.
|
1988.4.4
by Robert Collins
Tidy up the patch. |
235 |
* node_name: The node name: opaque text to the merge routine.
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
236 |
* merge_depth: How many levels of merging deep this node has been
|
237 |
found.
|
|
238 |
* revno_sequence: When requested this field provides a sequence of
|
|
239 |
revision numbers for all revisions. The format is:
|
|
3170.3.7
by John Arbash Meinel
update MergeSorter.__init__() docstring |
240 |
(REVNO, BRANCHNUM, BRANCHREVNO). BRANCHNUM is the number of the
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
241 |
branch that the revno is on. From left to right the REVNO numbers
|
242 |
are the sequence numbers within that branch of the revision.
|
|
243 |
For instance, the graph {A:[], B:['A'], C:['A', 'B']} will get
|
|
244 |
the following revno_sequences assigned: A:(1,), B:(1,1,1), C:(2,).
|
|
245 |
This should be read as 'A is the first commit in the trunk',
|
|
246 |
'B is the first commit on the first branch made from A', 'C is the
|
|
247 |
second commit in the trunk'.
|
|
248 |
* end_of_merge: When True the next node is part of a different merge.
|
|
1624.1.3
by Robert Collins
Convert log to use the new tsort.merge_sort routine. |
249 |
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
250 |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
251 |
node identifiers can be any hashable object, and are typically strings.
|
252 |
||
253 |
If you have a graph like [('a', ['b']), ('a', ['c'])] this will only use
|
|
254 |
one of the two values for 'a'.
|
|
255 |
||
256 |
The graph is sorted lazily: until you iterate or sort the input is
|
|
257 |
not processed other than to create an internal representation.
|
|
258 |
||
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
259 |
iteration or sorting may raise GraphCycleError if a cycle is present
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
260 |
in the graph.
|
261 |
||
262 |
Background information on the design:
|
|
263 |
-------------------------------------
|
|
264 |
definition: the end of any cluster or 'merge' occurs when:
|
|
265 |
1 - the next revision has a lower merge depth than we do.
|
|
266 |
i.e.
|
|
267 |
A 0
|
|
268 |
B 1
|
|
269 |
C 2
|
|
270 |
D 1
|
|
271 |
E 0
|
|
272 |
C, D are the ends of clusters, E might be but we need more data.
|
|
273 |
2 - or the next revision at our merge depth is not our left most
|
|
274 |
ancestor.
|
|
275 |
This is required to handle multiple-merges in one commit.
|
|
276 |
i.e.
|
|
277 |
A 0 [F, B, E]
|
|
278 |
B 1 [D, C]
|
|
279 |
C 2 [D]
|
|
280 |
D 1 [F]
|
|
281 |
E 1 [F]
|
|
282 |
F 0
|
|
283 |
C is the end of a cluster due to rule 1.
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
284 |
D is not the end of a cluster from rule 1, but is from rule 2: E
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
285 |
is not its left most ancestor
|
286 |
E is the end of a cluster due to rule 1
|
|
287 |
F might be but we need more data.
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
288 |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
289 |
we show connecting lines to a parent when:
|
290 |
- The parent is the start of a merge within this cluster.
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
291 |
That is, the merge was not done to the mainline before this cluster
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
292 |
was merged to the mainline.
|
293 |
This can be detected thus:
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
294 |
* The parent has a higher merge depth and is the next revision in
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
295 |
the list.
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
296 |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
297 |
The next revision in the list constraint is needed for this case:
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
298 |
A 0 [D, B]
|
299 |
B 1 [C, F] # we do not want to show a line to F which is depth 2
|
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
300 |
but not a merge
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
301 |
C 1 [H] # note that this is a long line to show back to the
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
302 |
ancestor - see the end of merge rules.
|
303 |
D 0 [G, E]
|
|
304 |
E 1 [G, F]
|
|
305 |
F 2 [G]
|
|
306 |
G 1 [H]
|
|
307 |
H 0
|
|
308 |
- Part of this merges 'branch':
|
|
309 |
The parent has the same merge depth and is our left most parent and we
|
|
310 |
are not the end of the cluster.
|
|
311 |
A 0 [C, B] lines: [B, C]
|
|
312 |
B 1 [E, C] lines: [C]
|
|
313 |
C 0 [D] lines: [D]
|
|
314 |
D 0 [F, E] lines: [E, F]
|
|
315 |
E 1 [F] lines: [F]
|
|
316 |
F 0
|
|
317 |
- The end of this merge/cluster:
|
|
318 |
we can ONLY have multiple parents at the end of a cluster if this
|
|
319 |
branch was previously merged into the 'mainline'.
|
|
320 |
- if we have one and only one parent, show it
|
|
321 |
Note that this may be to a greater merge depth - for instance if
|
|
322 |
this branch continued from a deeply nested branch to add something
|
|
323 |
to it.
|
|
324 |
- if we have more than one parent - show the second oldest (older ==
|
|
325 |
further down the list) parent with
|
|
326 |
an equal or lower merge depth
|
|
327 |
XXXX revisit when awake. ddaa asks about the relevance of each one
|
|
328 |
- maybe more than one parent is relevant
|
|
329 |
"""
|
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
330 |
self._generate_revno = generate_revno |
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
331 |
# a dict of the graph.
|
332 |
self._graph = dict(graph) |
|
1624.1.3
by Robert Collins
Convert log to use the new tsort.merge_sort routine. |
333 |
# if there is an explicit mainline, alter the graph to match. This is
|
334 |
# easier than checking at every merge whether we are on the mainline and
|
|
335 |
# if so which path to take.
|
|
336 |
if mainline_revisions is None: |
|
337 |
self._mainline_revisions = [] |
|
338 |
self._stop_revision = None |
|
339 |
else: |
|
340 |
self._mainline_revisions = list(mainline_revisions) |
|
341 |
self._stop_revision = self._mainline_revisions[0] |
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
342 |
# skip the first revision, its what we reach and its parents are
|
1624.1.3
by Robert Collins
Convert log to use the new tsort.merge_sort routine. |
343 |
# therefore irrelevant
|
344 |
for index, revision in enumerate(self._mainline_revisions[1:]): |
|
345 |
# NB: index 0 means self._mainline_revisions[1]
|
|
346 |
# if the mainline matches the graph, nothing to do.
|
|
347 |
parent = self._mainline_revisions[index] |
|
348 |
if parent is None: |
|
349 |
# end of mainline_revisions history
|
|
350 |
continue
|
|
3533.2.1
by John Arbash Meinel
(bug #243536) tsort.merge_sorted() should work even with a ghost in mainline. |
351 |
graph_parent_ids = self._graph[revision] |
352 |
if not graph_parent_ids: |
|
353 |
# We ran into a ghost, skip over it, this is a workaround for
|
|
354 |
# bug #243536, the _graph has had ghosts stripped, but the
|
|
355 |
# mainline_revisions have not
|
|
356 |
continue
|
|
357 |
if graph_parent_ids[0] == parent: |
|
1624.1.3
by Robert Collins
Convert log to use the new tsort.merge_sort routine. |
358 |
continue
|
359 |
# remove it from its prior spot
|
|
360 |
self._graph[revision].remove(parent) |
|
361 |
# insert it into the start of the mainline
|
|
362 |
self._graph[revision].insert(0, parent) |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
363 |
# we need to do a check late in the process to detect end-of-merges
|
364 |
# which requires the parents to be accessible: its easier for now
|
|
365 |
# to just keep the original graph around.
|
|
1624.1.3
by Robert Collins
Convert log to use the new tsort.merge_sort routine. |
366 |
self._original_graph = dict(self._graph.items()) |
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
367 |
# we need to know the revision numbers of revisions to determine
|
368 |
# the revision numbers of their descendants
|
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
369 |
# this is a graph from node to [revno_tuple, first_child]
|
370 |
# where first_child is True if no other children have seen this node
|
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
371 |
# and revno_tuple is the tuple that was assigned to the node.
|
372 |
# we dont know revnos to start with, so we start it seeded with
|
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
373 |
# [None, True]
|
374 |
self._revnos = dict((revision, [None, True]) |
|
375 |
for revision in self._graph) |
|
376 |
# Each mainline revision counts how many child branches have spawned from it.
|
|
377 |
self._revno_to_branch_count = {} |
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
378 |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
379 |
# this is a stack storing the depth first search into the graph.
|
380 |
self._node_name_stack = [] |
|
381 |
# at each level of recursion we need the merge depth this node is at:
|
|
382 |
self._node_merge_depth_stack = [] |
|
383 |
# at each level of 'recursion' we have to check each parent. This
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
384 |
# stack stores the parents we have not yet checked for the node at the
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
385 |
# matching depth in _node_name_stack
|
386 |
self._pending_parents_stack = [] |
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
387 |
# When we first look at a node we assign it a seqence number from its
|
388 |
# leftmost parent.
|
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
389 |
self._first_child_stack = [] |
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
390 |
# this is a set of the nodes who have been completely analysed for fast
|
391 |
# membership checking
|
|
392 |
self._completed_node_names = set() |
|
393 |
# this is the scheduling of nodes list.
|
|
394 |
# Nodes are scheduled
|
|
395 |
# from the bottom left of the tree: in the tree
|
|
396 |
# A 0 [D, B]
|
|
397 |
# B 1 [C]
|
|
398 |
# C 1 [D]
|
|
399 |
# D 0 [F, E]
|
|
400 |
# E 1 [F]
|
|
401 |
# F 0
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
402 |
# the scheduling order is: F, E, D, C, B, A
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
403 |
# that is - 'left subtree, right subtree, node'
|
404 |
# which would mean that when we schedule A we can emit the entire tree.
|
|
405 |
self._scheduled_nodes = [] |
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
406 |
# This records for each node when we have processed its left most
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
407 |
# unmerged subtree. After this subtree is scheduled, all other subtrees
|
408 |
# have their merge depth increased by one from this nodes merge depth.
|
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
409 |
# it contains tuples - name, merge_depth
|
410 |
self._left_subtree_pushed_stack = [] |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
411 |
|
412 |
# seed the search with the tip of the branch
|
|
3236.2.1
by Michael Hudson
test and fix |
413 |
if (branch_tip is not None and |
4593.5.42
by John Arbash Meinel
Turns out that some code assumed passing NULL_REVISION to merge_sort |
414 |
branch_tip != _mod_revision.NULL_REVISION and |
415 |
branch_tip != (_mod_revision.NULL_REVISION,)): |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
416 |
parents = self._graph.pop(branch_tip) |
417 |
self._push_node(branch_tip, 0, parents) |
|
418 |
||
419 |
def sorted(self): |
|
420 |
"""Sort the graph and return as a list.
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
421 |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
422 |
After calling this the sorter is empty and you must create a new one.
|
423 |
"""
|
|
424 |
return list(self.iter_topo_order()) |
|
425 |
||
426 |
def iter_topo_order(self): |
|
427 |
"""Yield the nodes of the graph in a topological order.
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
428 |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
429 |
After finishing iteration the sorter is empty and you cannot continue
|
430 |
iteration.
|
|
431 |
"""
|
|
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
432 |
# These are safe to offload to local variables, because they are used
|
433 |
# as a stack and modified in place, never assigned to.
|
|
434 |
node_name_stack = self._node_name_stack |
|
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
435 |
node_merge_depth_stack = self._node_merge_depth_stack |
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
436 |
pending_parents_stack = self._pending_parents_stack |
437 |
left_subtree_pushed_stack = self._left_subtree_pushed_stack |
|
438 |
completed_node_names = self._completed_node_names |
|
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
439 |
scheduled_nodes = self._scheduled_nodes |
440 |
||
441 |
graph_pop = self._graph.pop |
|
442 |
||
443 |
def push_node(node_name, merge_depth, parents, |
|
444 |
node_name_stack_append=node_name_stack.append, |
|
445 |
node_merge_depth_stack_append=node_merge_depth_stack.append, |
|
446 |
left_subtree_pushed_stack_append=left_subtree_pushed_stack.append, |
|
447 |
pending_parents_stack_append=pending_parents_stack.append, |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
448 |
first_child_stack_append=self._first_child_stack.append, |
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
449 |
revnos=self._revnos, |
450 |
):
|
|
451 |
"""Add node_name to the pending node stack.
|
|
452 |
||
453 |
Names in this stack will get emitted into the output as they are popped
|
|
454 |
off the stack.
|
|
455 |
||
456 |
This inlines a lot of self._variable.append functions as local
|
|
457 |
variables.
|
|
458 |
"""
|
|
459 |
node_name_stack_append(node_name) |
|
460 |
node_merge_depth_stack_append(merge_depth) |
|
461 |
left_subtree_pushed_stack_append(False) |
|
462 |
pending_parents_stack_append(list(parents)) |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
463 |
# as we push it, check if it is the first child
|
4634.11.1
by John Arbash Meinel
Fix bug #419241. If a graph had a mainline ghost |
464 |
parent_info = None |
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
465 |
if parents: |
466 |
# node has parents, assign from the left most parent.
|
|
4634.11.1
by John Arbash Meinel
Fix bug #419241. If a graph had a mainline ghost |
467 |
try: |
468 |
parent_info = revnos[parents[0]] |
|
469 |
except KeyError: |
|
470 |
# Left-hand parent is a ghost, consider it not to exist
|
|
471 |
pass
|
|
472 |
if parent_info is not None: |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
473 |
first_child = parent_info[1] |
474 |
parent_info[1] = False |
|
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
475 |
else: |
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
476 |
# We don't use the same algorithm here, but we need to keep the
|
477 |
# stack in line
|
|
478 |
first_child = None |
|
479 |
first_child_stack_append(first_child) |
|
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
480 |
|
481 |
def pop_node(node_name_stack_pop=node_name_stack.pop, |
|
482 |
node_merge_depth_stack_pop=node_merge_depth_stack.pop, |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
483 |
first_child_stack_pop=self._first_child_stack.pop, |
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
484 |
left_subtree_pushed_stack_pop=left_subtree_pushed_stack.pop, |
485 |
pending_parents_stack_pop=pending_parents_stack.pop, |
|
486 |
original_graph=self._original_graph, |
|
487 |
revnos=self._revnos, |
|
488 |
completed_node_names_add=self._completed_node_names.add, |
|
489 |
scheduled_nodes_append=scheduled_nodes.append, |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
490 |
revno_to_branch_count=self._revno_to_branch_count, |
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
491 |
):
|
492 |
"""Pop the top node off the stack
|
|
493 |
||
494 |
The node is appended to the sorted output.
|
|
495 |
"""
|
|
496 |
# we are returning from the flattened call frame:
|
|
497 |
# pop off the local variables
|
|
498 |
node_name = node_name_stack_pop() |
|
499 |
merge_depth = node_merge_depth_stack_pop() |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
500 |
first_child = first_child_stack_pop() |
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
501 |
# remove this node from the pending lists:
|
502 |
left_subtree_pushed_stack_pop() |
|
503 |
pending_parents_stack_pop() |
|
504 |
||
505 |
parents = original_graph[node_name] |
|
4634.11.1
by John Arbash Meinel
Fix bug #419241. If a graph had a mainline ghost |
506 |
parent_revno = None |
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
507 |
if parents: |
508 |
# node has parents, assign from the left most parent.
|
|
4634.11.1
by John Arbash Meinel
Fix bug #419241. If a graph had a mainline ghost |
509 |
try: |
510 |
parent_revno = revnos[parents[0]][0] |
|
511 |
except KeyError: |
|
512 |
# left-hand parent is a ghost, treat it as not existing
|
|
513 |
pass
|
|
514 |
if parent_revno is not None: |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
515 |
if not first_child: |
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
516 |
# not the first child, make a new branch
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
517 |
base_revno = parent_revno[0] |
518 |
branch_count = revno_to_branch_count.get(base_revno, 0) |
|
519 |
branch_count += 1 |
|
520 |
revno_to_branch_count[base_revno] = branch_count |
|
521 |
revno = (parent_revno[0], branch_count, 1) |
|
522 |
# revno = (parent_revno[0], branch_count, parent_revno[-1]+1)
|
|
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
523 |
else: |
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
524 |
# as the first child, we just increase the final revision
|
525 |
# number
|
|
526 |
revno = parent_revno[:-1] + (parent_revno[-1] + 1,) |
|
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
527 |
else: |
528 |
# no parents, use the root sequence
|
|
3613.1.1
by John Arbash Meinel
Fix the merge_sort code so that it properly increments. |
529 |
root_count = revno_to_branch_count.get(0, -1) |
530 |
root_count += 1 |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
531 |
if root_count: |
532 |
revno = (0, root_count, 1) |
|
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
533 |
else: |
534 |
revno = (1,) |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
535 |
revno_to_branch_count[0] = root_count |
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
536 |
|
537 |
# store the revno for this node for future reference
|
|
538 |
revnos[node_name][0] = revno |
|
539 |
completed_node_names_add(node_name) |
|
540 |
scheduled_nodes_append((node_name, merge_depth, revno)) |
|
541 |
return node_name |
|
542 |
||
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
543 |
|
544 |
while node_name_stack: |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
545 |
# loop until this call completes.
|
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
546 |
parents_to_visit = pending_parents_stack[-1] |
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
547 |
# if all parents are done, the revision is done
|
548 |
if not parents_to_visit: |
|
549 |
# append the revision to the topo sorted scheduled list:
|
|
550 |
# all the nodes parents have been scheduled added, now
|
|
551 |
# we can add it to the output.
|
|
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
552 |
pop_node() |
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
553 |
else: |
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
554 |
while pending_parents_stack[-1]: |
555 |
if not left_subtree_pushed_stack[-1]: |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
556 |
# recurse depth first into the primary parent
|
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
557 |
next_node_name = pending_parents_stack[-1].pop(0) |
4615.1.1
by John Arbash Meinel
Change merge_sort to increase indent even for trivial merge histories. |
558 |
is_left_subtree = True |
559 |
left_subtree_pushed_stack[-1] = True |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
560 |
else: |
561 |
# place any merges in right-to-left order for scheduling
|
|
562 |
# which gives us left-to-right order after we reverse
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
563 |
# the scheduled queue. XXX: This has the effect of
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
564 |
# allocating common-new revisions to the right-most
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
565 |
# subtree rather than the left most, which will
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
566 |
# display nicely (you get smaller trees at the top
|
567 |
# of the combined merge).
|
|
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
568 |
next_node_name = pending_parents_stack[-1].pop() |
4615.1.1
by John Arbash Meinel
Change merge_sort to increase indent even for trivial merge histories. |
569 |
is_left_subtree = False |
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
570 |
if next_node_name in completed_node_names: |
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
571 |
# this parent was completed by a child on the
|
572 |
# call stack. skip it.
|
|
573 |
continue
|
|
574 |
# otherwise transfer it from the source graph into the
|
|
575 |
# top of the current depth first search stack.
|
|
576 |
try: |
|
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
577 |
parents = graph_pop(next_node_name) |
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
578 |
except KeyError: |
579 |
# if the next node is not in the source graph it has
|
|
580 |
# already been popped from it and placed into the
|
|
581 |
# current search stack (but not completed or we would
|
|
582 |
# have hit the continue 4 lines up.
|
|
583 |
# this indicates a cycle.
|
|
4593.5.25
by John Arbash Meinel
Add tests that we detect GraphCycleError |
584 |
if next_node_name in self._original_graph: |
585 |
raise errors.GraphCycleError(node_name_stack) |
|
586 |
else: |
|
587 |
# This is just a ghost parent, ignore it
|
|
588 |
continue
|
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
589 |
next_merge_depth = 0 |
4615.1.1
by John Arbash Meinel
Change merge_sort to increase indent even for trivial merge histories. |
590 |
if is_left_subtree: |
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
591 |
# a new child branch from name_stack[-1]
|
4615.1.1
by John Arbash Meinel
Change merge_sort to increase indent even for trivial merge histories. |
592 |
next_merge_depth = 0 |
593 |
else: |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
594 |
next_merge_depth = 1 |
595 |
next_merge_depth = ( |
|
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
596 |
node_merge_depth_stack[-1] + next_merge_depth) |
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
597 |
push_node( |
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
598 |
next_node_name, |
599 |
next_merge_depth, |
|
600 |
parents) |
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
601 |
# and do not continue processing parents until this 'call'
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
602 |
# has recursed.
|
603 |
break
|
|
2425.4.3
by John Arbash Meinel
Inline self._pop_node and self._push_node |
604 |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
605 |
# We have scheduled the graph. Now deliver the ordered output:
|
606 |
sequence_number = 0 |
|
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
607 |
stop_revision = self._stop_revision |
608 |
generate_revno = self._generate_revno |
|
609 |
original_graph = self._original_graph |
|
610 |
||
611 |
while scheduled_nodes: |
|
612 |
node_name, merge_depth, revno = scheduled_nodes.pop() |
|
613 |
if node_name == stop_revision: |
|
1624.1.3
by Robert Collins
Convert log to use the new tsort.merge_sort routine. |
614 |
return
|
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
615 |
if not len(scheduled_nodes): |
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
616 |
# last revision is the end of a merge
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
617 |
end_of_merge = True |
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
618 |
elif scheduled_nodes[-1][1] < merge_depth: |
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
619 |
# the next node is to our left
|
620 |
end_of_merge = True |
|
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
621 |
elif (scheduled_nodes[-1][1] == merge_depth and |
622 |
(scheduled_nodes[-1][0] not in |
|
623 |
original_graph[node_name])): |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
624 |
# the next node was part of a multiple-merge.
|
625 |
end_of_merge = True |
|
626 |
else: |
|
627 |
end_of_merge = False |
|
2425.4.2
by John Arbash Meinel
Change valid self._foo variables into local variables. |
628 |
if generate_revno: |
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
629 |
yield (sequence_number, node_name, merge_depth, revno, end_of_merge) |
630 |
else: |
|
631 |
yield (sequence_number, node_name, merge_depth, end_of_merge) |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
632 |
sequence_number += 1 |
633 |
||
634 |
def _push_node(self, node_name, merge_depth, parents): |
|
635 |
"""Add node_name to the pending node stack.
|
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
636 |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
637 |
Names in this stack will get emitted into the output as they are popped
|
638 |
off the stack.
|
|
639 |
"""
|
|
640 |
self._node_name_stack.append(node_name) |
|
641 |
self._node_merge_depth_stack.append(merge_depth) |
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
642 |
self._left_subtree_pushed_stack.append(False) |
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
643 |
self._pending_parents_stack.append(list(parents)) |
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
644 |
# as we push it, figure out if this is the first child
|
4634.11.1
by John Arbash Meinel
Fix bug #419241. If a graph had a mainline ghost |
645 |
parent_info = None |
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
646 |
if parents: |
647 |
# node has parents, assign from the left most parent.
|
|
4634.11.1
by John Arbash Meinel
Fix bug #419241. If a graph had a mainline ghost |
648 |
try: |
649 |
parent_info = self._revnos[parents[0]] |
|
650 |
except KeyError: |
|
651 |
# Left-hand parent is a ghost, consider it not to exist
|
|
652 |
pass
|
|
653 |
if parent_info is not None: |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
654 |
first_child = parent_info[1] |
655 |
parent_info[1] = False |
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
656 |
else: |
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
657 |
# We don't use the same algorithm here, but we need to keep the
|
658 |
# stack in line
|
|
659 |
first_child = None |
|
660 |
self._first_child_stack.append(first_child) |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
661 |
|
662 |
def _pop_node(self): |
|
3943.8.1
by Marius Kruger
remove all trailing whitespace from bzr source |
663 |
"""Pop the top node off the stack
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
664 |
|
665 |
The node is appended to the sorted output.
|
|
666 |
"""
|
|
667 |
# we are returning from the flattened call frame:
|
|
668 |
# pop off the local variables
|
|
669 |
node_name = self._node_name_stack.pop() |
|
670 |
merge_depth = self._node_merge_depth_stack.pop() |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
671 |
first_child = self._first_child_stack.pop() |
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
672 |
# remove this node from the pending lists:
|
673 |
self._left_subtree_pushed_stack.pop() |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
674 |
self._pending_parents_stack.pop() |
675 |
||
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
676 |
parents = self._original_graph[node_name] |
4634.11.1
by John Arbash Meinel
Fix bug #419241. If a graph had a mainline ghost |
677 |
parent_revno = None |
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
678 |
if parents: |
679 |
# node has parents, assign from the left most parent.
|
|
4634.11.1
by John Arbash Meinel
Fix bug #419241. If a graph had a mainline ghost |
680 |
try: |
681 |
parent_revno = self._revnos[parents[0]][0] |
|
682 |
except KeyError: |
|
683 |
# left-hand parent is a ghost, treat it as not existing
|
|
684 |
pass
|
|
685 |
if parent_revno is not None: |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
686 |
if not first_child: |
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
687 |
# not the first child, make a new branch
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
688 |
base_revno = parent_revno[0] |
689 |
branch_count = self._revno_to_branch_count.get(base_revno, 0) |
|
690 |
branch_count += 1 |
|
691 |
self._revno_to_branch_count[base_revno] = branch_count |
|
692 |
revno = (parent_revno[0], branch_count, 1) |
|
693 |
# revno = (parent_revno[0], branch_count, parent_revno[-1]+1)
|
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
694 |
else: |
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
695 |
# as the first child, we just increase the final revision
|
696 |
# number
|
|
697 |
revno = parent_revno[:-1] + (parent_revno[-1] + 1,) |
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
698 |
else: |
699 |
# no parents, use the root sequence
|
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
700 |
root_count = self._revno_to_branch_count.get(0, 0) |
4593.5.9
by John Arbash Meinel
Fix a bug in MergeSorter that was fixed only in the inlined pop_node |
701 |
root_count = self._revno_to_branch_count.get(0, -1) |
702 |
root_count += 1 |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
703 |
if root_count: |
704 |
revno = (0, root_count, 1) |
|
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
705 |
else: |
706 |
revno = (1,) |
|
3170.3.2
by John Arbash Meinel
Implement the new dotted revision numbering. |
707 |
self._revno_to_branch_count[0] = root_count |
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
708 |
|
709 |
# store the revno for this node for future reference
|
|
710 |
self._revnos[node_name][0] = revno |
|
1624.1.2
by Robert Collins
Add MergeSort facility to bzrlib.tsort. |
711 |
self._completed_node_names.add(node_name) |
1988.4.1
by Robert Collins
bzrlib.tsort.merge_sorted now accepts 'generate_revnos'. This parameter |
712 |
self._scheduled_nodes.append((node_name, merge_depth, self._revnos[node_name][0])) |
1570.1.7
by Robert Collins
Replace the slow topo_sort routine with a much faster one for non trivial datasets. |
713 |
return node_name |