131
by Aaron Bentley
Added required filename parameter |
1 |
from dotgraph import Node, dot_output, invoke_dot |
128
by Aaron Bentley
Got initial graphing functionality working |
2 |
from bzrlib.branch import Branch |
3 |
import bzrlib.errors |
|
130
by Aaron Bentley
Added committer to revisions |
4 |
import re |
128
by Aaron Bentley
Got initial graphing functionality working |
5 |
|
6 |
def add_relations(rev_id): |
|
7 |
if rev_id in ancestors: |
|
8 |
return
|
|
9 |
print rev_id |
|
10 |
if rev_id not in nodes: |
|
11 |
nodes[rev_id] = Node("n%d" % counter, label = rev_id) |
|
12 |
counter += 1 |
|
13 |
revision = branch.get_revision(rev_id) |
|
14 |
ancestors [rev_id] = [] |
|
15 |
for p in (p.revision_id for p in revision.parents): |
|
16 |
add_relations(p) |
|
17 |
if p not in descendants: |
|
18 |
descendants[p] = [] |
|
19 |
descendants[p].append(rev_id) |
|
20 |
ancestors [rev_id].append(rev_id) |
|
21 |
||
130
by Aaron Bentley
Added committer to revisions |
22 |
def short_committer(committer): |
135
by Aaron Bentley
Enhanced revision-crediting |
23 |
new_committer = re.sub('<.*>', '', committer).strip(' ') |
130
by Aaron Bentley
Added committer to revisions |
24 |
if len(new_committer) < 2: |
25 |
return committer |
|
26 |
return new_committer |
|
136
by Aaron Bentley
Allowed disabling ancestry collapsing |
27 |
|
28 |
||
29 |
def compact_descendants(descendants, ancestors): |
|
30 |
new_descendants={} |
|
31 |
skip = set() |
|
32 |
for me, my_descendants in descendants.iteritems(): |
|
33 |
if me in skip: |
|
34 |
continue
|
|
35 |
new_descendants[me] = [] |
|
36 |
for descendant in my_descendants: |
|
37 |
new_descendant = descendant |
|
38 |
while new_descendant in descendants and \ |
|
39 |
len(ancestors[new_descendant]) == 1 and \ |
|
40 |
len(descendants[new_descendant]) == 1: |
|
41 |
skip.add(new_descendant) |
|
42 |
if new_descendant in new_descendants: |
|
43 |
del new_descendants[new_descendant] |
|
44 |
new_descendant = descendants[new_descendant][0] |
|
45 |
new_descendants[me].append(new_descendant) |
|
46 |
return new_descendants |
|
47 |
||
48 |
||
49 |
def graph_ancestry(branch, collapse=True): |
|
128
by Aaron Bentley
Got initial graphing functionality working |
50 |
nodes = {} |
51 |
q = ((i+1, n) for (i, n) in enumerate(branch.revision_history())) |
|
52 |
r = 1 |
|
53 |
for (revno, rev_id) in q: |
|
135
by Aaron Bentley
Enhanced revision-crediting |
54 |
nodes[rev_id] = Node("R%d" % revno, color="#ffff00", rev_id=rev_id) |
128
by Aaron Bentley
Got initial graphing functionality working |
55 |
|
56 |
ancestors = {} |
|
57 |
descendants = {} |
|
58 |
counter = 0 |
|
59 |
lines = [branch.last_patch()] |
|
60 |
while len(lines) > 0: |
|
61 |
new_lines = set() |
|
62 |
for rev_id in lines: |
|
63 |
if rev_id not in nodes: |
|
135
by Aaron Bentley
Enhanced revision-crediting |
64 |
nodes[rev_id] = Node("n%d" % counter, label=rev_id, |
65 |
rev_id=rev_id) |
|
128
by Aaron Bentley
Got initial graphing functionality working |
66 |
counter+=1 |
67 |
||
68 |
try: |
|
69 |
revision = branch.get_revision(rev_id) |
|
70 |
except bzrlib.errors.NoSuchRevision: |
|
137
by Aaron Bentley
Put dotted outlines on missing revisions |
71 |
nodes[rev_id].node_style.append('dotted') |
128
by Aaron Bentley
Got initial graphing functionality working |
72 |
continue
|
130
by Aaron Bentley
Added committer to revisions |
73 |
if nodes[rev_id].committer is None: |
74 |
nodes[rev_id].committer = short_committer(revision.committer) |
|
128
by Aaron Bentley
Got initial graphing functionality working |
75 |
parent_ids = [r.revision_id for r in revision.parents] |
76 |
ancestors [rev_id] = parent_ids |
|
77 |
for parent in parent_ids: |
|
78 |
if parent not in ancestors: |
|
79 |
new_lines.add(parent) |
|
80 |
descendants[parent] = [] |
|
81 |
descendants[parent].append(rev_id) |
|
82 |
lines = new_lines |
|
83 |
node_relations = [] |
|
136
by Aaron Bentley
Allowed disabling ancestry collapsing |
84 |
|
85 |
if collapse: |
|
86 |
visible_descendants = compact_descendants(descendants, ancestors) |
|
87 |
else: |
|
88 |
visible_descendants = descendants |
|
129
by Aaron Bentley
Added collapsing for lines of development. |
89 |
|
136
by Aaron Bentley
Allowed disabling ancestry collapsing |
90 |
for key, values in visible_descendants.iteritems(): |
128
by Aaron Bentley
Got initial graphing functionality working |
91 |
for value in values: |
92 |
node_relations.append((nodes[key], nodes[value])) |
|
93 |
return node_relations |
|
131
by Aaron Bentley
Added required filename parameter |
94 |
|
136
by Aaron Bentley
Allowed disabling ancestry collapsing |
95 |
def write_ancestry_file(branch, filename, collapse=True): |
131
by Aaron Bentley
Added required filename parameter |
96 |
b = Branch(branch) |
136
by Aaron Bentley
Allowed disabling ancestry collapsing |
97 |
relations = graph_ancestry(b, collapse) |
134
by Aaron Bentley
support multiple image formats for graph-ancestry |
98 |
ext = filename.split('.')[-1] |
99 |
if ext in ('svg', 'svgz', 'gif', 'jpg', 'ps', 'fig', 'mif', 'png'): |
|
100 |
invoke_dot(dot_output(relations), filename, ext) |
|
101 |
elif ext=='dot': |
|
102 |
file(filename, 'wb').write("".join(list(dot_output(relations)))) |
|
103 |
else: |
|
104 |
print "Unknown file extension: %s" % ext |
|
131
by Aaron Bentley
Added required filename parameter |
105 |