42
35
It's up to you how to actually draw the nodes and lines (straight,
43
36
curved, kinked, etc.) and to pick the actual colours for each index.
46
graph = repository.get_graph()
39
mainline = branch.revision_history()
40
graph_parents = branch.repository.get_revision_graph(start)
49
41
graph_children = {}
50
for (revid, parent_revids) in graph.iter_ancestry(start_revs):
51
if parent_revids is None:
54
if parent_revids == (NULL_REVISION,):
55
graph_parents[revid] = ()
57
graph_parents[revid] = parent_revids
58
for parent in parent_revids:
59
graph_children.setdefault(parent, []).append(revid)
60
graph_children.setdefault(revid, [])
62
for ghost_child in graph_children[ghost]:
63
graph_parents[ghost_child] = [p for p in graph_parents[ghost_child]
65
graph_parents["top:"] = start_revs
67
if len(graph_parents)>0:
68
merge_sorted_revisions = merge_sort(
73
merge_sorted_revisions = ()
76
merge_sorted_revisions = [elem for elem in merge_sorted_revisions \
79
assert merge_sorted_revisions[0][1] == "top:"
80
merge_sorted_revisions = merge_sorted_revisions[1:]
42
for revid in graph_parents.keys():
43
graph_children[revid] = []
45
merge_sorted_revisions = merge_sort(
85
# This will hold an item for each "branch". For a revisions, the revsion
86
# number less the least significant digit is the branch_id, and used as the
87
# key for the dict. Hence revision with the same revsion number less the
88
# least significant digit are considered to be in the same branch line.
89
# e.g.: for revisions 290.12.1 and 290.12.2, the branch_id would be 290.12,
90
# and these two revisions will be in the same branch line. Each value is
91
# a list of rev_indexes in the branch.
96
for (rev_index, (sequence_number,
100
end_of_merge)) in enumerate(merge_sorted_revisions):
101
if maxnum and rev_index >= maxnum:
103
revid_index[revid] = rev_index
56
for (index, (sequence_number,
60
end_of_merge)) in enumerate(merge_sorted_revisions):
62
revid_index[revid] = index
63
revno_index[revno_sequence] = index
65
branch_id = revno_sequence[0:-1]
68
if branch_id not in branch_lines:
70
branch_lines[branch_id] = branch_line
71
branch_line["rev_indexes"] = []
72
branch_line["min_index"] = index - 1
73
branch_line["max_index"] = 0
75
branch_line = branch_lines[branch_id]
76
branch_line["rev_indexes"].append(index)
105
78
parents = graph_parents[revid]
79
for parent_revid in parents:
80
graph_children[parent_revid].append(revid)
106
82
linegraph.append([revid,
114
revno_index[revno_sequence] = rev_index
116
branch_id = revno_sequence[0:-1]
119
if branch_id not in branch_lines:
121
branch_lines[branch_id] = branch_line
123
branch_line = branch_lines[branch_id]
125
branch_line.append(rev_index)
128
branch_ids = branch_lines.keys()
89
branch_ids = branch_lines.keys()
130
def branch_id_cmp(x, y):
131
"""Compaire branch_id's first by the number of digits, then reversed
137
return cmp(len_x, len_y)
139
branch_ids.sort(branch_id_cmp)
140
# This will hold a tuple of (child_index, parent_index, col_index) for each
141
# line that needs to be drawn. If col_index is not none, then the line is
142
# drawn along that column, else the the line can be drawn directly between
143
# the child and parent because either the child and parent are in the same
144
# branch line, or the child and parent are 1 row apart.
146
empty_column = [False for i in range(len(graph_parents))]
147
# This will hold a bit map for each cell. If the cell is true, then the
148
# cell allready contains a node or line. This use when deciding what column
149
# to place a branch line or line in, without it overlaping something else.
150
columns = [list(empty_column)]
153
for branch_id in branch_ids:
154
branch_line = branch_lines[branch_id]
156
# Find the col_index for the direct parent branch. This will be the
157
# starting point when looking for a free column.
160
if len(branch_id) > 1:
161
parent_revno = branch_id[0:-1]
162
if parent_revno in revno_index:
163
parent_index = revno_index[parent_revno]
164
parent_node = linegraph[parent_index][1]
166
parent_col_index = parent_node[0]
169
col_search_order = _branch_line_col_search_order(columns,
171
color = reduce(lambda x, y: x+y, branch_id, 0)
175
last_rev_index = None
176
for rev_index in branch_line:
178
if broken_line_length and \
179
rev_index - last_rev_index > broken_line_length:
180
line_range.append(last_rev_index+1)
181
line_range.append(rev_index-1)
93
for branch_id in branch_ids:
94
branch_line = branch_lines[branch_id]
95
branch_line["inward_line_ends"] = []
96
for rev_index in branch_line["rev_indexes"]:
101
end_of_merge) = merge_sorted_revisions[rev_index]
102
for parent_revid in graph_parents[revid]:
103
if parent_revid in revid_index:
104
parent_index = revid_index[parent_revid]
105
parent_merge_depth = merge_sorted_revisions[parent_index][2]
106
if parent_merge_depth < merge_depth:
107
branch_line["inward_line_ends"].append(parent_index)
108
if branch_line["max_index"] < parent_index:
109
branch_line["max_index"] =parent_index
111
for child_revid in graph_children[revid]:
112
if child_revid in revid_index:
113
child_index = revid_index[child_revid]
114
child_merge_depth = merge_sorted_revisions[child_index][2]
115
if child_merge_depth < merge_depth:
116
branch_line["inward_line_ends"].append(child_index)
121
start_col_index = branch_lines[branch_id[0:-2]]["col_index"]+1
122
for col_search_index in range(start_col_index,len(columns)):
123
column = columns[col_search_index]
126
if (line["min_index"] <= branch_line["min_index"] and \
127
line["max_index"] > branch_line["min_index"]) or \
128
(line["max_index"] >= branch_line["max_index"] and \
129
line["min_index"] < branch_line["max_index"]):
130
clashing_lines.append(line)
132
if not clashing_lines:
133
col_index = col_search_index
137
col_index = len(columns)
140
columns[col_index].append(branch_line)
141
branch_line["col_index"] = col_index
144
for branch_id in branch_ids:
145
branch_line = branch_lines[branch_id]
146
color = reduce(lambda x, y: x+y, branch_id, 0)
147
col_index = branch_line["col_index"]
148
node = (col_index, color)
150
for rev_index in branch_line["rev_indexes"]:
155
end_of_merge) = merge_sorted_revisions[rev_index]
156
children = graph_children[revid]
158
linegraph[rev_index][1] = node
159
linegraph[rev_index][4] = children
160
for child_revid in children:
161
if child_revid in revid_index:
162
child_index = revid_index[child_revid]
163
child_revno_sequence = \
164
merge_sorted_revisions[child_index][3]
165
child_merge_depth = merge_sorted_revisions[child_index][2]
166
child_branch_id = child_revno_sequence[0:-1]
167
child_col_index = branch_lines[child_branch_id]["col_index"]
168
if child_merge_depth < merge_depth:
169
#out from the child to line
170
linegraph[child_index][2].append(
174
for line_part_index in range(child_index+1, rev_index):
175
linegraph[line_part_index][2].append(
183
line_range.extend(range(last_rev_index+1, rev_index))
185
line_range.append(rev_index)
186
last_rev_index = rev_index
189
if broken_line_length and \
190
parent_index - last_rev_index > broken_line_length:
191
line_range.append(last_rev_index+1)
193
line_range.extend(range(last_rev_index+1, parent_index))
195
col_index = _find_free_column(columns,
199
node = (col_index, color)
200
for rev_index in branch_line:
201
linegraph[rev_index][1] = node
202
columns[col_index][rev_index] = True
204
for rev_index in branch_line:
209
end_of_merge) = merge_sorted_revisions[rev_index]
211
linegraph[rev_index][4] = graph_children[revid]
212
col_index = linegraph[rev_index][1][0]
214
for parent_revid in graph_parents[revid]:
215
if parent_revid in revid_index:
217
parent_index = revid_index[parent_revid]
218
parent_node = linegraph[parent_index][1]
220
parent_col_index = parent_node[0]
222
parent_col_index = None
224
_line_col_search_order(columns,
228
# If this line is really long, break it.
229
if len(branch_id) > 0 and \
230
broken_line_length and \
231
parent_index - rev_index > broken_line_length:
232
child_line_col_index = \
233
_find_free_column(columns,
237
_mark_column_as_used(columns,
238
child_line_col_index,
241
# Recall _line_col_search_order to reset it back to
244
_line_col_search_order(columns,
247
parent_col_line_index = \
248
_find_free_column(columns,
252
_mark_column_as_used(columns,
253
parent_col_line_index,
255
lines.append((rev_index,
257
(child_line_col_index,
258
parent_col_line_index)))
260
line_col_index = col_index
261
if parent_index - rev_index >1:
262
line_range = range(rev_index + 1, parent_index)
264
_find_free_column(columns,
268
_mark_column_as_used(columns,
271
lines.append((rev_index,
275
for (child_index, parent_index, line_col_indexes) in lines:
276
(child_col_index, child_color) = linegraph[child_index][1]
277
(parent_col_index, parent_color) = linegraph[parent_index][1]
279
if len(line_col_indexes) == 1:
280
if parent_index - child_index == 1:
281
linegraph[child_index][2].append(
286
# line from the child's column to the lines column
287
linegraph[child_index][2].append(
291
# lines down the line's column
292
for line_part_index in range(child_index+1, parent_index-1):
293
linegraph[line_part_index][2].append(
294
(line_col_indexes[0],
297
# line from the line's column to the parent's column
298
linegraph[parent_index-1][2].append(
299
(line_col_indexes[0],
304
# line from the child's column to the lines column
305
linegraph[child_index][2].append(
310
linegraph[child_index+1][2].append(
311
(line_col_indexes[0],
316
linegraph[parent_index-2][2].append(
320
# line from the line's column to the parent's column
321
linegraph[parent_index-1][2].append(
322
(line_col_indexes[1],
325
return (linegraph, revid_index, len(columns))
327
return (linegraph, revid_index, 0)
180
for line_part_index in range(child_index, rev_index-1):
181
linegraph[line_part_index][2].append(
186
linegraph[rev_index-1][2].append(
330
def _branch_line_col_search_order(columns, parent_col_index):
331
for col_index in range(parent_col_index, len(columns)):
333
for col_index in range(parent_col_index-1, -1, -1):
336
def _line_col_search_order(columns, parent_col_index, child_col_index):
337
if parent_col_index is not None:
338
max_index = max(parent_col_index, child_col_index)
339
min_index = min(parent_col_index, child_col_index)
340
for col_index in range(max_index, min_index -1, -1):
343
max_index = child_col_index
344
min_index = child_col_index
345
yield child_col_index
347
while max_index + i < len(columns) or \
349
if max_index + i < len(columns):
351
if min_index - i > -1:
355
def _find_free_column(columns, empty_column, col_search_order, line_range):
356
for col_index in col_search_order:
357
column = columns[col_index]
358
has_overlaping_line = False
359
for row_index in line_range:
360
if column[row_index]:
361
has_overlaping_line = True
363
if not has_overlaping_line:
366
col_index = len(columns)
367
column = list(empty_column)
368
columns.append(column)
371
def _mark_column_as_used(columns, col_index, line_range):
372
column = columns[col_index]
373
for row_index in line_range:
374
column[row_index] = True
191
return (linegraph, revid_index)
376
194
def same_branch(a, b):
377
195
"""Return whether we think revisions a and b are on the same branch."""