112
110
for revision_id in branch.revision_history():
113
111
this_inv = branch.repository.get_inventory(revision_id)
114
if this_inv.has_id(file_id):
112
if file_id in this_inv:
115
113
this_ie = this_inv[file_id]
116
114
this_path = this_inv.id2path(file_id)
233
231
diff_type=None, _match_using_deltas=True,
234
232
exclude_common_ancestry=False,
237
234
"""Convenience function for making a logging request dictionary.
262
259
generate; 1 for just the mainline; 0 for all levels.
264
261
:param generate_tags: If True, include tags for matched revisions.
266
263
:param delta_type: Either 'full', 'partial' or None.
267
264
'full' means generate the complete delta - adds/deletes/modifies/etc;
268
265
'partial' means filter the delta using specific_fileids;
295
290
'delta_type': delta_type,
296
291
'diff_type': diff_type,
297
292
'exclude_common_ancestry': exclude_common_ancestry,
298
'signature': signature,
299
293
# Add 'private' attributes for features that may be deprecated
300
294
'_match_using_deltas': _match_using_deltas,
312
def format_signature_validity(rev_id, repo):
313
"""get the signature validity
315
:param rev_id: revision id to validate
316
:param repo: repository of revision
317
:return: human readable string to print to log
319
from bzrlib import gpg
321
gpg_strategy = gpg.GPGStrategy(None)
322
result = repo.verify_revision(rev_id, gpg_strategy)
323
if result[0] == gpg.SIGNATURE_VALID:
324
return "valid signature from {0}".format(result[1])
325
if result[0] == gpg.SIGNATURE_KEY_MISSING:
326
return "unknown key {0}".format(result[1])
327
if result[0] == gpg.SIGNATURE_NOT_VALID:
328
return "invalid signature!"
329
if result[0] == gpg.SIGNATURE_NOT_SIGNED:
330
return "no signature"
333
306
class LogGenerator(object):
334
307
"""A generator of log revisions."""
387
360
rqst['delta_type'] = None
388
361
if not getattr(lf, 'supports_diff', False):
389
362
rqst['diff_type'] = None
390
if not getattr(lf, 'supports_signatures', False):
391
rqst['signature'] = False
393
364
# Find and print the interesting revisions
394
365
generator = self._generator_factory(self.branch, rqst)
428
399
levels = rqst.get('levels')
429
400
limit = rqst.get('limit')
430
401
diff_type = rqst.get('diff_type')
431
show_signature = rqst.get('signature')
433
403
revision_iterator = self._create_log_revision_iterator()
434
404
for revs in revision_iterator:
442
412
diff = self._format_diff(rev, rev_id, diff_type)
444
signature = format_signature_validity(rev_id,
445
self.branch.repository)
448
413
yield LogRevision(rev, revno, merge_depth, delta,
449
self.rev_tag_dict.get(rev_id), diff, signature)
414
self.rev_tag_dict.get(rev_id), diff)
452
417
if log_count >= limit:
714
679
br_revno, br_rev_id = branch.last_revision_info()
715
680
repo = branch.repository
716
graph = repo.get_graph()
717
681
if start_rev_id is None and end_rev_id is None:
718
682
cur_revno = br_revno
719
for revision_id in graph.iter_lefthand_ancestry(br_rev_id,
720
(_mod_revision.NULL_REVISION,)):
683
for revision_id in repo.iter_reverse_revision_history(br_rev_id):
721
684
yield revision_id, str(cur_revno), 0
724
687
if end_rev_id is None:
725
688
end_rev_id = br_rev_id
726
689
found_start = start_rev_id is None
727
for revision_id in graph.iter_lefthand_ancestry(end_rev_id,
728
(_mod_revision.NULL_REVISION,)):
690
for revision_id in repo.iter_reverse_revision_history(end_rev_id):
729
691
revno_str = _compute_revno_str(branch, revision_id)
730
692
if not found_start and revision_id == start_rev_id:
731
693
if not exclude_common_ancestry:
865
827
if search is None:
866
828
return log_rev_iterator
867
searchRE = lazy_regex.lazy_compile(search, re.IGNORECASE)
829
searchRE = re.compile(search, re.IGNORECASE)
868
830
return _filter_message_re(searchRE, log_rev_iterator)
1124
1086
cur_revno = branch_revno
1126
1088
mainline_revs = []
1127
graph = branch.repository.get_graph()
1128
for revision_id in graph.iter_lefthand_ancestry(
1129
branch_last_revision, (_mod_revision.NULL_REVISION,)):
1089
for revision_id in branch.repository.iter_reverse_revision_history(
1090
branch_last_revision):
1130
1091
if cur_revno < start_revno:
1131
1092
# We have gone far enough, but we always add 1 more revision
1132
1093
rev_nos[revision_id] = cur_revno
1232
1192
# Lookup all possible text keys to determine which ones actually modified
1234
graph = branch.repository.get_file_graph()
1235
get_parent_map = graph.get_parent_map
1236
1194
text_keys = [(file_id, rev_id) for rev_id, revno, depth in view_revisions]
1237
1195
next_keys = None
1238
1196
# Looking up keys in batches of 1000 can cut the time in half, as well as
1242
1200
# indexing layer. We might consider passing in hints as to the known
1243
1201
# access pattern (sparse/clustered, high success rate/low success
1244
1202
# rate). This particular access is clustered with a low success rate.
1203
get_parent_map = branch.repository.texts.get_parent_map
1245
1204
modified_text_revisions = set()
1246
1205
chunk_size = 1000
1247
1206
for start in xrange(0, len(text_keys), chunk_size):
1357
1316
def __init__(self, rev=None, revno=None, merge_depth=0, delta=None,
1358
tags=None, diff=None, signature=None):
1317
tags=None, diff=None):
1360
1319
if revno is None:
1361
1320
self.revno = None
1380
1338
to indicate which LogRevision attributes it supports:
1382
1340
- supports_delta must be True if this log formatter supports delta.
1383
Otherwise the delta attribute may not be populated. The 'delta_format'
1384
attribute describes whether the 'short_status' format (1) or the long
1385
one (2) should be used.
1341
Otherwise the delta attribute may not be populated. The 'delta_format'
1342
attribute describes whether the 'short_status' format (1) or the long
1343
one (2) should be used.
1387
1345
- supports_merge_revisions must be True if this log formatter supports
1388
merge revisions. If not, then only mainline revisions will be passed
1346
merge revisions. If not, then only mainline revisions will be passed
1391
1349
- preferred_levels is the number of levels this formatter defaults to.
1392
The default value is zero meaning display all levels.
1393
This value is only relevant if supports_merge_revisions is True.
1350
The default value is zero meaning display all levels.
1351
This value is only relevant if supports_merge_revisions is True.
1395
1353
- supports_tags must be True if this log formatter supports tags.
1396
Otherwise the tags attribute may not be populated.
1354
Otherwise the tags attribute may not be populated.
1398
1356
- supports_diff must be True if this log formatter supports diffs.
1399
Otherwise the diff attribute may not be populated.
1401
- supports_signatures must be True if this log formatter supports GPG
1357
Otherwise the diff attribute may not be populated.
1404
1359
Plugins can register functions to show custom revision properties using
1405
1360
the properties_handler_registry. The registered function
1406
must respect the following interface description::
1361
must respect the following interface description:
1408
1362
def my_show_properties(properties_dict):
1409
1363
# code that returns a dict {'name':'value'} of the properties
1597
1551
supports_delta = True
1598
1552
supports_tags = True
1599
1553
supports_diff = True
1600
supports_signatures = True
1602
1555
def __init__(self, *args, **kwargs):
1603
1556
super(LongLogFormatter, self).__init__(*args, **kwargs)
1643
1596
lines.append('timestamp: %s' % (self.date_string(revision.rev),))
1645
if revision.signature is not None:
1646
lines.append('signature: ' + revision.signature)
1648
1598
lines.append('message:')
1649
1599
if not revision.rev.message:
1650
1600
lines.append(' (no message)')
1778
1728
def log_string(self, revno, rev, max_chars, tags=None, prefix=''):
1779
1729
"""Format log info into one string. Truncate tail of string
1781
:param revno: revision number or None.
1782
Revision numbers counts from 1.
1783
:param rev: revision object
1784
:param max_chars: maximum length of resulting string
1785
:param tags: list of tags or None
1786
:param prefix: string to prefix each line
1787
:return: formatted truncated string
1730
:param revno: revision number or None.
1731
Revision numbers counts from 1.
1732
:param rev: revision object
1733
:param max_chars: maximum length of resulting string
1734
:param tags: list of tags or None
1735
:param prefix: string to prefix each line
1736
:return: formatted truncated string
1791
1740
# show revno only when is not None
1792
1741
out.append("%s:" % revno)
1793
if max_chars is not None:
1794
out.append(self.truncate(self.short_author(rev), (max_chars+3)/4))
1796
out.append(self.short_author(rev))
1742
out.append(self.truncate(self.short_author(rev), 20))
1797
1743
out.append(self.date_string(rev))
1798
1744
if len(rev.parent_ids) > 1:
1799
1745
out.append('[merge]')
1992
1938
old_revisions = set()
1993
1939
new_history = []
1994
1940
new_revisions = set()
1995
graph = repository.get_graph()
1996
new_iter = graph.iter_lefthand_ancestry(new_revision_id)
1997
old_iter = graph.iter_lefthand_ancestry(old_revision_id)
1941
new_iter = repository.iter_reverse_revision_history(new_revision_id)
1942
old_iter = repository.iter_reverse_revision_history(old_revision_id)
1998
1943
stop_revision = None