1
from dotgraph import Node, dot_output, invoke_dot, invoke_dot_aa, NoDot, NoRsvg
2
from dotgraph import mail_map
3
from bzrlib.branch import Branch
4
from bzrlib.errors import BzrCommandError
9
mail_map.update({'aaron.bentley@utoronto.ca' : 'Aaron Bentley',
10
'abentley@panoramicfeedback.com': 'Aaron Bentley',
11
'john@arbash-meinel.com' : 'John A. Meinel',
12
'mbp@sourcefrog.net' : 'Martin Pool'
15
def add_relations(rev_id):
16
if rev_id in ancestors:
19
if rev_id not in nodes:
20
nodes[rev_id] = Node("n%d" % counter, label = rev_id)
22
revision = branch.get_revision(rev_id)
23
ancestors [rev_id] = []
24
for p in (p.revision_id for p in revision.parents):
26
if p not in descendants:
28
descendants[p].append(rev_id)
29
ancestors [rev_id].append(rev_id)
31
def short_committer(committer):
32
new_committer = re.sub('<.*>', '', committer).strip(' ')
33
if len(new_committer) < 2:
37
def can_skip(rev_id, descendants, ancestors):
38
if rev_id not in descendants:
40
elif len(ancestors[rev_id]) != 1:
42
elif len(descendants[ancestors[rev_id][0]]) != 1:
44
elif len(descendants[rev_id]) != 1:
49
def compact_descendants(descendants, ancestors):
52
for me, my_descendants in descendants.iteritems():
55
new_descendants[me] = []
56
for descendant in my_descendants:
57
new_descendant = descendant
58
while can_skip(new_descendant, descendants, ancestors):
59
skip.add(new_descendant)
60
if new_descendant in new_descendants:
61
del new_descendants[new_descendant]
62
new_descendant = descendants[new_descendant][0]
63
new_descendants[me].append(new_descendant)
64
return new_descendants
67
def graph_ancestry(branch, collapse=True):
69
q = ((i+1, n) for (i, n) in enumerate(branch.revision_history()))
72
branch_name = os.path.basename(branch.base)
73
except AttributeError:
75
for (revno, rev_id) in q:
76
nodes[rev_id] = Node("R%d" % revno, color="#ffff00", rev_id=rev_id,
82
lines = [branch.last_patch()]
86
if rev_id not in nodes:
87
nodes[rev_id] = Node("n%d" % counter, label=rev_id,
92
revision = branch.get_revision(rev_id)
93
except bzrlib.errors.NoSuchRevision:
94
nodes[rev_id].node_style.append('dotted')
96
if nodes[rev_id].committer is None:
97
nodes[rev_id].committer = short_committer(revision.committer)
98
parent_ids = [r.revision_id for r in revision.parents]
99
ancestors [rev_id] = parent_ids
100
for parent in parent_ids:
101
if parent not in ancestors:
102
new_lines.add(parent)
103
descendants[parent] = []
104
descendants[parent].append(rev_id)
109
visible_descendants = compact_descendants(descendants, ancestors)
111
visible_descendants = descendants
113
for key, values in visible_descendants.iteritems():
115
node_relations.append((nodes[key], nodes[value]))
116
return node_relations
118
def write_ancestry_file(branch, filename, collapse=True, antialias=True):
120
relations = graph_ancestry(b, collapse)
121
ext = filename.split('.')[-1]
122
if antialias and ext in ('png', 'jpg'):
124
invoke_dot_aa(dot_output(relations), filename, ext)
126
raise BzrCommandError("Can't find 'dot'. Please ensure Graphviz"\
127
" is installed correctly.")
129
raise BzrCommandError("Can't find 'rsvg'. Please ensure "\
130
"librsvg-bin is installed correctly, or use --noantialias.")
131
elif ext in ('svg', 'svgz', 'gif', 'jpg', 'ps', 'fig', 'mif', 'png'):
133
invoke_dot(dot_output(relations), filename, ext)
135
raise BzrCommandError("Can't find 'dot'. Please ensure Graphviz"\
136
" is installed correctly, or use --noantialias")
138
file(filename, 'wb').write("".join(list(dot_output(relations))))
140
print "Unknown file extension: %s" % ext