206
202
if specific_fileid:
207
203
mutter('get log for file_id %r', specific_fileid)
204
generate_merge_revisions = getattr(lf, 'supports_merge_revisions', False)
205
allow_single_merge_revision = getattr(lf,
206
'supports_single_merge_revision', False)
207
view_revisions = calculate_view_revisions(branch, start_revision,
208
end_revision, direction,
210
generate_merge_revisions,
211
allow_single_merge_revision)
209
212
if search is not None:
210
213
searchRE = re.compile(search, re.IGNORECASE)
218
generate_tags = getattr(lf, 'supports_tags', False)
220
if branch.supports_tags():
221
rev_tag_dict = branch.tags.get_reverse_tag_dict()
223
generate_delta = verbose and getattr(lf, 'supports_delta', False)
225
# now we just print all the revisions
227
for (rev_id, revno, merge_depth), rev, delta in _iter_revisions(
228
branch.repository, view_revisions, generate_delta):
230
if not searchRE.search(rev.message):
233
lr = LogRevision(rev, revno, merge_depth, delta,
234
rev_tag_dict.get(rev_id))
238
if log_count >= limit:
242
def calculate_view_revisions(branch, start_revision, end_revision, direction,
243
specific_fileid, generate_merge_revisions,
244
allow_single_merge_revision):
245
if (not generate_merge_revisions and start_revision is end_revision is
246
None and direction == 'reverse' and specific_fileid is None):
247
return _linear_view_revisions(branch)
214
249
mainline_revs, rev_nos, start_rev_id, end_rev_id = \
215
250
_get_mainline_revs(branch, start_revision, end_revision)
216
251
if not mainline_revs:
219
254
if direction == 'reverse':
220
255
start_rev_id, end_rev_id = end_rev_id, start_rev_id
222
legacy_lf = getattr(lf, 'log_revision', None) is None
224
# pre-0.17 formatters use show for mainline revisions.
225
# how should we show merged revisions ?
226
# pre-0.11 api: show_merge
227
# 0.11-0.16 api: show_merge_revno
228
show_merge_revno = getattr(lf, 'show_merge_revno', None)
229
show_merge = getattr(lf, 'show_merge', None)
230
if show_merge is None and show_merge_revno is None:
231
# no merged-revno support
232
generate_merge_revisions = False
234
generate_merge_revisions = True
235
# tell developers to update their code
236
symbol_versioning.warn('LogFormatters should provide log_revision '
237
'instead of show and show_merge_revno since bzr 0.17.',
238
DeprecationWarning, stacklevel=3)
240
generate_merge_revisions = getattr(lf, 'supports_merge_revisions',
242
257
generate_single_revision = False
243
258
if ((not generate_merge_revisions)
244
259
and ((start_rev_id and (start_rev_id not in rev_nos))
245
260
or (end_rev_id and (end_rev_id not in rev_nos)))):
246
261
generate_single_revision = ((start_rev_id == end_rev_id)
247
and getattr(lf, 'supports_single_merge_revision', False))
262
and allow_single_merge_revision)
248
263
if not generate_single_revision:
249
264
raise errors.BzrCommandError('Selected log formatter only supports '
250
265
'mainline revisions.')
268
283
min_depth = min([d for r,n,d in view_revisions])
269
284
if min_depth != 0:
270
285
view_revisions = [(r,n,d-min_depth) for r,n,d in view_revisions]
273
generate_tags = getattr(lf, 'supports_tags', False)
275
if branch.supports_tags():
276
rev_tag_dict = branch.tags.get_reverse_tag_dict()
278
generate_delta = verbose and getattr(lf, 'supports_delta', False)
280
def iter_revisions():
286
return view_revisions
289
def _linear_view_revisions(branch):
290
start_revno, start_revision_id = branch.last_revision_info()
291
repo = branch.repository
292
revision_ids = repo.iter_reverse_revision_history(start_revision_id)
293
for num, revision_id in enumerate(revision_ids):
294
yield revision_id, str(start_revno - num), 0
297
def _iter_revisions(repository, view_revisions, generate_delta):
299
view_revisions = iter(view_revisions)
301
cur_view_revisions = [d for x, d in zip(range(num), view_revisions)]
302
if len(cur_view_revisions) == 0:
281
305
# r = revision, n = revno, d = merge depth
282
revision_ids = [r for r, n, d in view_revisions]
284
repository = branch.repository
287
revisions = repository.get_revisions(revision_ids[:num])
289
deltas = repository.get_deltas_for_revisions(revisions)
290
cur_deltas = dict(izip((r.revision_id for r in revisions),
292
for revision in revisions:
293
yield revision, cur_deltas.get(revision.revision_id)
294
revision_ids = revision_ids[num:]
295
num = min(int(num * 1.5), 200)
297
# now we just print all the revisions
299
for ((rev_id, revno, merge_depth), (rev, delta)) in \
300
izip(view_revisions, iter_revisions()):
303
if not searchRE.search(rev.message):
307
lr = LogRevision(rev, revno, merge_depth, delta,
308
rev_tag_dict.get(rev_id))
311
# support for legacy (pre-0.17) LogFormatters
314
lf.show(revno, rev, delta, rev_tag_dict.get(rev_id))
316
lf.show(revno, rev, delta)
318
if show_merge_revno is None:
319
lf.show_merge(rev, merge_depth)
322
lf.show_merge_revno(rev, merge_depth, revno,
323
rev_tag_dict.get(rev_id))
325
lf.show_merge_revno(rev, merge_depth, revno)
328
if log_count >= limit:
306
revision_ids = [r for (r, n, d) in cur_view_revisions]
307
revisions = repository.get_revisions(revision_ids)
309
deltas = repository.get_deltas_for_revisions(revisions)
310
cur_deltas = dict(izip((r.revision_id for r in revisions),
312
for view_data, revision in izip(cur_view_revisions, revisions):
313
yield view_data, revision, cur_deltas.get(revision.revision_id)
314
num = min(int(num * 1.5), 200)
332
317
def _get_mainline_revs(branch, start_revision, end_revision):
471
456
weave_modifed_revisions = set(file_weave.versions())
472
457
# build the ancestry of each revision in the graph
473
458
# - only listing the ancestors that change the specific file.
474
rev_graph = branch.repository.get_revision_graph(mainline_revisions[-1])
475
sorted_rev_list = tsort.topo_sort(rev_graph)
459
graph = branch.repository.get_graph()
460
# This asks for all mainline revisions, which means we only have to spider
461
# sideways, rather than depth history. That said, its still size-of-history
462
# and should be addressed.
463
parent_map = dict(((key, value) for key, value in
464
graph.iter_ancestry(mainline_revisions) if value is not None))
465
sorted_rev_list = tsort.topo_sort(parent_map.items())
477
467
for rev in sorted_rev_list:
478
parents = rev_graph[rev]
468
parents = parent_map[rev]
479
469
if rev not in weave_modifed_revisions and len(parents) == 1:
480
470
# We will not be adding anything new, so just use a reference to
481
471
# the parent ancestry.
517
507
for revision_id in revision_ids:
518
508
yield revision_id, str(rev_nos[revision_id]), 0
510
graph = branch.repository.get_graph()
511
# This asks for all mainline revisions, which means we only have to spider
512
# sideways, rather than depth history. That said, its still size-of-history
513
# and should be addressed.
514
parent_map = dict(((key, value) for key, value in
515
graph.iter_ancestry(mainline_revs) if value is not None))
516
# filter out ghosts; merge_sort errors on ghosts.
517
rev_graph = _strip_NULL_ghosts(parent_map)
520
518
merge_sorted_revisions = tsort.merge_sort(
521
branch.repository.get_revision_graph(mainline_revs[-1]),
522
520
mainline_revs[-1],
524
522
generate_revno=True)
636
630
supports_delta = True
637
631
supports_tags = True
639
@deprecated_method(zero_seventeen)
640
def show(self, revno, rev, delta, tags=None):
641
lr = LogRevision(rev, revno, 0, delta, tags)
642
return self.log_revision(lr)
644
@deprecated_method(zero_seventeen)
645
def show_merge_revno(self, rev, merge_depth, revno, tags=None):
646
"""Show a merged revision rev, with merge_depth and a revno."""
647
lr = LogRevision(rev, revno, merge_depth, tags=tags)
648
return self.log_revision(lr)
650
633
def log_revision(self, revision):
651
634
"""Log a revision, either merged or not."""
652
635
indent = ' ' * revision.merge_depth