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.
39
mainline = branch.revision_history()
40
graph_parents = branch.repository.get_revision_graph(start)
48
41
graph_children = {}
49
for (revid, parent_revids) in graph.iter_ancestry(start_revs):
50
if parent_revids is None:
53
if parent_revids == (NULL_REVISION,):
54
graph_parents[revid] = ()
56
graph_parents[revid] = parent_revids
57
for parent in parent_revids:
58
graph_children.setdefault(parent, []).append(revid)
59
graph_children.setdefault(revid, [])
61
for ghost_child in graph_children[ghost]:
62
graph_parents[ghost_child] = [p for p in graph_parents[ghost_child]
64
graph_parents["top:"] = start_revs
66
if len(graph_parents)>0:
67
merge_sorted_revisions = merge_sort(
72
merge_sorted_revisions = ()
75
merge_sorted_revisions = [elem for elem in merge_sorted_revisions \
78
assert merge_sorted_revisions[0][1] == "top:"
79
merge_sorted_revisions = merge_sorted_revisions[1:]
42
for revid in graph_parents.keys():
43
graph_children[revid] = []
45
merge_sorted_revisions = merge_sort(
84
# This will hold an item for each "branch". For a revisions, the revsion
85
# number less the least significant digit is the branch_id, and used as the
86
# key for the dict. Hence revision with the same revsion number less the
87
# least significant digit are considered to be in the same branch line.
88
# e.g.: for revisions 290.12.1 and 290.12.2, the branch_id would be 290.12,
89
# and these two revisions will be in the same branch line. Each value is
90
# a list of rev_indexes in the branch.
95
56
for (rev_index, (sequence_number,
99
60
end_of_merge)) in enumerate(merge_sorted_revisions):
100
if maxnum and rev_index >= maxnum:
102
62
revid_index[revid] = rev_index
63
revno_index[revno_sequence] = rev_index
65
branch_id = revno_sequence[0:-1]
68
if branch_id not in branch_lines:
69
branch_line = {"line_type": "branch_line",
70
"branch_id": branch_id,
72
"min_index": rev_index,
74
branch_lines[branch_id] = branch_line
76
branch_line = branch_lines[branch_id]
77
branch_line["rev_indexes"].append(rev_index)
78
if rev_index > branch_line["max_index"]:
79
branch_line["max_index"] = rev_index
104
81
parents = graph_parents[revid]
82
for parent_revid in parents:
83
graph_children[parent_revid].append(revid)
105
85
linegraph.append([revid,
113
revno_index[revno_sequence] = rev_index
115
branch_id = revno_sequence[0:-1]
118
if branch_id not in branch_lines:
120
branch_lines[branch_id] = branch_line
122
branch_line = branch_lines[branch_id]
124
branch_line.append(rev_index)
127
branch_ids = branch_lines.keys()
129
def branch_id_cmp(x, y):
130
"""Compaire branch_id's first by the number of digits, then reversed
136
return cmp(len_x, len_y)
138
branch_ids.sort(branch_id_cmp)
139
# This will hold a tuple of (child_index, parent_index, col_index) for each
140
# line that needs to be drawn. If col_index is not none, then the line is
141
# drawn along that column, else the the line can be drawn directly between
142
# the child and parent because either the child and parent are in the same
143
# branch line, or the child and parent are 1 row apart.
145
empty_column = [False for i in range(len(graph_parents))]
146
# This will hold a bit map for each cell. If the cell is true, then the
147
# cell allready contains a node or line. This use when deciding what column
148
# to place a branch line or line in, without it overlaping something else.
149
columns = [list(empty_column)]
152
for branch_id in branch_ids:
153
branch_line = branch_lines[branch_id]
155
# Find the col_index for the direct parent branch. This will be the
156
# starting point when looking for a free column.
159
if len(branch_id) > 1:
160
parent_revno = branch_id[0:-1]
161
if parent_revno in revno_index:
162
parent_index = revno_index[parent_revno]
163
parent_node = linegraph[parent_index][1]
165
parent_col_index = parent_node[0]
92
branch_ids = branch_lines.keys()
93
def branch_id_cmp(x, y):
98
return cmp(len_x, len_y)
100
branch_ids.sort(branch_id_cmp)
104
for branch_id in branch_ids:
105
branch_line = branch_lines[branch_id]
107
append_line(columns, branch_line)
108
branch_id = branch_line["branch_id"]
109
color = reduce(lambda x, y: x+y, branch_id, 0)
110
col_index = branch_line["col_index"]
111
node = (col_index, color)
113
for rev_index in branch_line["rev_indexes"]:
118
end_of_merge) = merge_sorted_revisions[rev_index]
120
linegraph[rev_index][1] = node
121
linegraph[rev_index][4] = graph_children[revid]
123
for parent_revid in graph_parents[revid]:
124
if parent_revid in revid_index:
125
parent_index = revid_index[parent_revid]
126
parent_revno = merge_sorted_revisions[parent_index][3]
127
parent_branch_id = parent_revno[0:-1]
128
line = {"line_type": "inter_branch_line",
129
"min_index": rev_index,
130
"max_index": parent_index}
132
if branch_id != parent_branch_id and \
133
parent_index - rev_index > 1:
134
append_line(columns, line)
137
parent_index = line["max_index"]
138
parent_node = linegraph[parent_index][1]
139
parent_col_index = parent_node[0]
140
color = parent_node[1]
142
child_index = line["min_index"]
143
child_col_index = linegraph[child_index][1][0]
145
if "col_index" in line:
146
line_col_index = line["col_index"]
147
linegraph[child_index][2].append(
151
for line_part_index in range(child_index+1, parent_index-1):
152
linegraph[line_part_index][2].append(
156
linegraph[parent_index-1][2].append(
161
linegraph[child_index][2].append(
165
for line_part_index in range(child_index+1, parent_index):
166
linegraph[line_part_index][2].append(
168
col_search_order = _branch_line_col_search_order(columns,
170
color = reduce(lambda x, y: x+y, branch_id, 0)
174
last_rev_index = None
175
for rev_index in branch_line:
177
if broken_line_length and \
178
rev_index - last_rev_index > broken_line_length:
179
line_range.append(last_rev_index+1)
180
line_range.append(rev_index-1)
182
line_range.extend(range(last_rev_index+1, rev_index))
184
line_range.append(rev_index)
185
last_rev_index = rev_index
188
if broken_line_length and \
189
parent_index - last_rev_index > broken_line_length:
190
line_range.append(last_rev_index+1)
192
line_range.extend(range(last_rev_index+1, parent_index))
194
col_index = _find_free_column(columns,
198
node = (col_index, color)
199
for rev_index in branch_line:
200
linegraph[rev_index][1] = node
201
columns[col_index][rev_index] = True
203
for rev_index in branch_line:
208
end_of_merge) = merge_sorted_revisions[rev_index]
210
linegraph[rev_index][4] = graph_children[revid]
211
col_index = linegraph[rev_index][1][0]
213
for parent_revid in graph_parents[revid]:
214
if parent_revid in revid_index:
216
parent_index = revid_index[parent_revid]
217
parent_node = linegraph[parent_index][1]
219
parent_col_index = parent_node[0]
221
parent_col_index = None
223
_line_col_search_order(columns,
227
# If this line is really long, break it.
228
if len(branch_id) > 0 and \
229
broken_line_length and \
230
parent_index - rev_index > broken_line_length:
231
child_line_col_index = \
232
_find_free_column(columns,
236
_mark_column_as_used(columns,
237
child_line_col_index,
240
# Recall _line_col_search_order to reset it back to
243
_line_col_search_order(columns,
246
parent_col_line_index = \
247
_find_free_column(columns,
251
_mark_column_as_used(columns,
252
parent_col_line_index,
254
lines.append((rev_index,
256
(child_line_col_index,
257
parent_col_line_index)))
259
line_col_index = col_index
260
if parent_index - rev_index >1:
261
line_range = range(rev_index + 1, parent_index)
263
_find_free_column(columns,
267
_mark_column_as_used(columns,
270
lines.append((rev_index,
274
for (child_index, parent_index, line_col_indexes) in lines:
275
(child_col_index, child_color) = linegraph[child_index][1]
276
(parent_col_index, parent_color) = linegraph[parent_index][1]
278
if len(line_col_indexes) == 1:
279
if parent_index - child_index == 1:
280
linegraph[child_index][2].append(
285
# line from the child's column to the lines column
286
linegraph[child_index][2].append(
290
# lines down the line's column
291
for line_part_index in range(child_index+1, parent_index-1):
292
linegraph[line_part_index][2].append(
293
(line_col_indexes[0],
296
# line from the line's column to the parent's column
297
linegraph[parent_index-1][2].append(
298
(line_col_indexes[0],
303
# line from the child's column to the lines column
304
linegraph[child_index][2].append(
309
linegraph[child_index+1][2].append(
310
(line_col_indexes[0],
315
linegraph[parent_index-2][2].append(
319
# line from the line's column to the parent's column
320
linegraph[parent_index-1][2].append(
321
(line_col_indexes[1],
324
return (linegraph, revid_index, len(columns))
326
return (linegraph, revid_index, 0)
329
def _branch_line_col_search_order(columns, parent_col_index):
330
for col_index in range(parent_col_index, len(columns)):
332
for col_index in range(parent_col_index-1, -1, -1):
335
def _line_col_search_order(columns, parent_col_index, child_col_index):
336
if parent_col_index is not None:
337
max_index = max(parent_col_index, child_col_index)
338
min_index = min(parent_col_index, child_col_index)
339
for col_index in range(max_index, min_index -1, -1):
342
max_index = child_col_index
343
min_index = child_col_index
344
yield child_col_index
346
while max_index + i < len(columns) or \
348
if max_index + i < len(columns):
350
if min_index - i > -1:
354
def _find_free_column(columns, empty_column, col_search_order, line_range):
355
for col_index in col_search_order:
356
column = columns[col_index]
172
return (linegraph, revid_index)
174
def append_line(columns, line):
175
for col_index, column in enumerate(columns):
357
176
has_overlaping_line = False
358
for row_index in line_range:
359
if column[row_index]:
177
for col_line in column:
178
if not (col_line["min_index"] >= line["max_index"] or \
179
col_line["max_index"] <= line["min_index"]):
360
180
has_overlaping_line = True
362
182
if not has_overlaping_line:
365
185
col_index = len(columns)
366
column = list(empty_column)
367
columns.append(column)
187
line["col_index"] = col_index
188
columns[col_index].append(line)
370
def _mark_column_as_used(columns, col_index, line_range):
371
column = columns[col_index]
372
for row_index in line_range:
373
column[row_index] = True
375
192
def same_branch(a, b):
376
193
"""Return whether we think revisions a and b are on the same branch."""