79
79
if rev_id == 'null:':
80
return None, 'Null Revision', None, None
80
return None, 'Null Revision', None
82
82
rev = source.get_revision(rev_id)
83
83
except NoSuchRevision:
85
85
committer = '-'.join(rev_id.split('-')[:-2]).strip(' ')
86
86
if committer == '':
87
return None, None, None, None
87
return None, None, None
89
return None, None, None, None
89
return None, None, None
91
91
committer = short_committer(rev.committer)
92
92
if rev.message is not None:
93
93
message = rev.message.split('\n')[0]
94
94
gmtime = time.gmtime(rev.timestamp + (rev.timezone or 0))
95
95
date = time.strftime('%Y/%m/%d', gmtime)
96
nick = rev.properties.get('branch-nick')
97
96
if '@' in committer:
99
98
committer = mail_map[committer]
103
102
committer = committer_alias[committer]
106
return committer, message, nick, date
105
return committer, message, date
108
107
class Grapher(object):
110
108
def __init__(self, branch, other_branch=None):
111
109
object.__init__(self)
112
110
self.branch = branch
113
111
self.other_branch = other_branch
112
revision_a = self.branch.last_revision()
114
113
if other_branch is not None:
115
other_repo = other_branch.repository
114
branch.fetch(other_branch)
116
115
revision_b = self.other_branch.last_revision()
117
self.root, self.ancestors, self.descendants, self.common = \
118
combined_graph(revision_a, revision_b,
119
self.branch.repository)
120
except bzrlib.errors.NoCommonRoot:
121
raise bzrlib.errors.NoCommonAncestor(revision_a, revision_b)
120
self.graph = self.branch.repository.get_graph(other_repo)
121
revision_a = self.branch.last_revision()
122
self.scan_graph(revision_a, revision_b)
123
self.root, self.ancestors, self.descendants = \
124
revision_graph(revision_a, branch.repository)
123
127
self.n_history = branch.revision_history()
124
self.n_revnos = branch.get_revision_id_to_revno_map()
125
self.distances = node_distances(self.descendants, self.ancestors,
128
self.distances = node_distances(self.descendants, self.ancestors,
127
130
if other_branch is not None:
128
131
self.base = select_farthest(self.distances, self.common)
129
self.m_history = other_branch.revision_history()
130
self.m_revnos = other_branch.get_revision_id_to_revno_map()
131
self.new_base = self.graph.find_unique_lca(revision_a,
133
self.lcas = self.graph.find_lca(revision_a, revision_b)
132
self.m_history = other_branch.revision_history()
138
135
self.m_history = []
141
def scan_graph(self, revision_a, revision_b):
142
a_ancestors = dict(self.graph.iter_ancestry([revision_a]))
143
self.ancestors = a_ancestors
144
self.root = NULL_REVISION
145
if revision_b is not None:
146
b_ancestors = dict(self.graph.iter_ancestry([revision_b]))
147
self.common = set(a_ancestors.keys())
148
self.common.intersection_update(b_ancestors)
149
self.ancestors.update(b_ancestors)
153
self.descendants = {}
155
for revision, parents in self.ancestors.iteritems():
156
self.descendants.setdefault(revision, [])
159
parents = [NULL_REVISION]
160
for parent in parents:
161
self.descendants.setdefault(parent, []).append(revision)
163
self.ancestors[ghost] = [NULL_REVISION]
166
def _get_revno_str(prefix, revno_map, revision_id):
168
revno = revno_map[revision_id]
171
return '%s%s' % (prefix, '.'.join(str(n) for n in revno))
173
137
def dot_node(self, node, num):
246
196
d_node.node_style.append('dotted')
250
def get_relations(self, collapse=False, max_distance=None):
200
def get_relations(self, collapse=False):
252
202
node_relations = []
255
exceptions = self.lcas.union([self.base, self.new_base])
256
visible_ancestors = compact_ancestors(self.descendants,
205
visible_ancestors = compact_ancestors(self.descendants,
206
self.ancestors, (self.base,))
260
visible_ancestors = {}
261
for revision, parents in self.ancestors.iteritems():
262
visible_ancestors[revision] = dict((p, 0) for p in parents)
263
if max_distance is not None:
264
min_distance = max(self.distances.values()) - max_distance
265
visible_ancestors = dict((n, p) for n, p in
266
visible_ancestors.iteritems() if
267
self.distances[n] >= min_distance)
208
visible_ancestors = self.ancestors
268
209
for node, parents in visible_ancestors.iteritems():
269
210
if node not in dot_nodes:
270
211
dot_nodes[node] = self.dot_node(node, num)
272
for parent, skipped in parents.iteritems():
213
if visible_ancestors is self.ancestors:
214
parent_iter = ((f, 0) for f in parents)
216
parent_iter = (f for f in parents.iteritems())
217
for parent, skipped in parent_iter:
273
218
if parent not in dot_nodes:
274
219
dot_nodes[parent] = self.dot_node(parent, num)