14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
19
"""Code to show logs of changes.
19
21
Various flavors of log can be produced:
108
graph = branch.repository.get_graph()
109
history = list(graph.iter_lefthand_ancestry(branch.last_revision(),
110
[_mod_revision.NULL_REVISION]))
111
for revision_id in reversed(history):
108
for revision_id in branch.revision_history():
112
109
this_inv = branch.repository.get_inventory(revision_id)
113
110
if this_inv.has_id(file_id):
114
111
this_ie = this_inv[file_id]
227
233
diff_type=None, _match_using_deltas=True,
228
234
exclude_common_ancestry=False, match=None,
229
signature=False, omit_merges=False,
231
237
"""Convenience function for making a logging request dictionary.
332
334
from bzrlib import gpg
334
336
gpg_strategy = gpg.GPGStrategy(None)
335
result = repo.verify_revision_signature(rev_id, gpg_strategy)
337
result = repo.verify_revision(rev_id, gpg_strategy)
336
338
if result[0] == gpg.SIGNATURE_VALID:
337
return u"valid signature from {0}".format(result[1])
339
return "valid signature from {0}".format(result[1])
338
340
if result[0] == gpg.SIGNATURE_KEY_MISSING:
339
341
return "unknown key {0}".format(result[1])
340
342
if result[0] == gpg.SIGNATURE_NOT_VALID:
559
558
a list of the same tuples.
561
560
if (exclude_common_ancestry and start_rev_id == end_rev_id):
562
raise errors.BzrCommandError(gettext(
563
'--exclude-common-ancestry requires two different revisions'))
561
raise errors.BzrCommandError(
562
'--exclude-common-ancestry requires two different revisions')
564
563
if direction not in ('reverse', 'forward'):
565
raise ValueError(gettext('invalid direction %r') % direction)
564
raise ValueError('invalid direction %r' % direction)
566
565
br_revno, br_rev_id = branch.last_revision_info()
567
566
if br_revno == 0:
571
570
and (not generate_merge_revisions
572
571
or not _has_merges(branch, end_rev_id))):
573
572
# If a single revision is requested, check we can handle it
574
return _generate_one_revision(branch, end_rev_id, br_rev_id,
576
if not generate_merge_revisions:
578
# If we only want to see linear revisions, we can iterate ...
579
iter_revs = _linear_view_revisions(
580
branch, start_rev_id, end_rev_id,
581
exclude_common_ancestry=exclude_common_ancestry)
582
# If a start limit was given and it's not obviously an
583
# ancestor of the end limit, check it before outputting anything
584
if (direction == 'forward'
585
or (start_rev_id and not _is_obvious_ancestor(
586
branch, start_rev_id, end_rev_id))):
587
iter_revs = list(iter_revs)
588
if direction == 'forward':
589
iter_revs = reversed(iter_revs)
591
except _StartNotLinearAncestor:
592
# Switch to the slower implementation that may be able to find a
593
# non-obvious ancestor out of the left-hand history.
595
iter_revs = _generate_all_revisions(branch, start_rev_id, end_rev_id,
596
direction, delayed_graph_generation,
597
exclude_common_ancestry)
598
if direction == 'forward':
599
iter_revs = _rebase_merge_depth(reverse_by_depth(list(iter_revs)))
573
iter_revs = _generate_one_revision(branch, end_rev_id, br_rev_id,
575
elif not generate_merge_revisions:
576
# If we only want to see linear revisions, we can iterate ...
577
iter_revs = _generate_flat_revisions(branch, start_rev_id, end_rev_id,
578
direction, exclude_common_ancestry)
579
if direction == 'forward':
580
iter_revs = reversed(iter_revs)
582
iter_revs = _generate_all_revisions(branch, start_rev_id, end_rev_id,
583
direction, delayed_graph_generation,
584
exclude_common_ancestry)
585
if direction == 'forward':
586
iter_revs = _rebase_merge_depth(reverse_by_depth(list(iter_revs)))
609
596
return [(rev_id, revno_str, 0)]
599
def _generate_flat_revisions(branch, start_rev_id, end_rev_id, direction,
600
exclude_common_ancestry=False):
601
result = _linear_view_revisions(
602
branch, start_rev_id, end_rev_id,
603
exclude_common_ancestry=exclude_common_ancestry)
604
# If a start limit was given and it's not obviously an
605
# ancestor of the end limit, check it before outputting anything
606
if direction == 'forward' or (start_rev_id
607
and not _is_obvious_ancestor(branch, start_rev_id, end_rev_id)):
609
result = list(result)
610
except _StartNotLinearAncestor:
611
raise errors.BzrCommandError('Start revision not found in'
612
' left-hand history of end revision.')
612
616
def _generate_all_revisions(branch, start_rev_id, end_rev_id, direction,
613
617
delayed_graph_generation,
614
618
exclude_common_ancestry=False):
650
654
except _StartNotLinearAncestor:
651
655
# A merge was never detected so the lower revision limit can't
652
656
# be nested down somewhere
653
raise errors.BzrCommandError(gettext('Start revision not found in'
654
' history of end revision.'))
657
raise errors.BzrCommandError('Start revision not found in'
658
' history of end revision.')
656
660
# We exit the loop above because we encounter a revision with merges, from
657
661
# this revision, we need to switch to _graph_view_revisions.
1068
1072
if branch_revno != 0:
1069
1073
if (start_rev_id == _mod_revision.NULL_REVISION
1070
1074
or end_rev_id == _mod_revision.NULL_REVISION):
1071
raise errors.BzrCommandError(gettext('Logging revision 0 is invalid.'))
1075
raise errors.BzrCommandError('Logging revision 0 is invalid.')
1072
1076
if start_revno > end_revno:
1073
raise errors.BzrCommandError(gettext("Start revision must be "
1074
"older than the end revision."))
1077
raise errors.BzrCommandError("Start revision must be older than "
1078
"the end revision.")
1075
1079
return (start_rev_id, end_rev_id)
1127
1131
if ((start_rev_id == _mod_revision.NULL_REVISION)
1128
1132
or (end_rev_id == _mod_revision.NULL_REVISION)):
1129
raise errors.BzrCommandError(gettext('Logging revision 0 is invalid.'))
1133
raise errors.BzrCommandError('Logging revision 0 is invalid.')
1130
1134
if start_revno > end_revno:
1131
raise errors.BzrCommandError(gettext("Start revision must be older "
1132
"than the end revision."))
1135
raise errors.BzrCommandError("Start revision must be older than "
1136
"the end revision.")
1134
1138
if end_revno < start_revno:
1135
1139
return None, None, None, None
1785
1789
return self.get(name)(*args, **kwargs)
1787
1791
def get_default(self, branch):
1788
c = branch.get_config_stack()
1789
return self.get(c.get('log_format'))
1792
return self.get(branch.get_config().log_format())
1792
1795
log_formatter_registry = LogFormatterRegistry()
1795
1798
log_formatter_registry.register('short', ShortLogFormatter,
1796
'Moderately short log format.')
1799
'Moderately short log format')
1797
1800
log_formatter_registry.register('long', LongLogFormatter,
1798
'Detailed log format.')
1801
'Detailed log format')
1799
1802
log_formatter_registry.register('line', LineLogFormatter,
1800
'Log format with one line per revision.')
1803
'Log format with one line per revision')
1801
1804
log_formatter_registry.register('gnu-changelog', GnuChangelogLogFormatter,
1802
'Format used by GNU ChangeLog files.')
1805
'Format used by GNU ChangeLog files')
1805
1808
def register_formatter(name, formatter):
2014
2017
kind is one of values 'directory', 'file', 'symlink', 'tree-reference'.
2015
2018
branch will be read-locked.
2017
from bzrlib.builtins import _get_revision_range
2018
tree, b, path = controldir.ControlDir.open_containing_tree_or_branch(
2020
from builtins import _get_revision_range
2021
tree, b, path = bzrdir.BzrDir.open_containing_tree_or_branch(file_list[0])
2020
2022
add_cleanup(b.lock_read().unlock)
2021
2023
# XXX: It's damn messy converting a list of paths to relative paths when
2022
2024
# those paths might be deleted ones, they might be on a case-insensitive
2111
2113
len(row) > 1 and row[1] == 'fixed']
2113
2115
if fixed_bug_urls:
2114
return {ngettext('fixes bug', 'fixes bugs', len(fixed_bug_urls)):\
2115
' '.join(fixed_bug_urls)}
2116
return {'fixes bug(s)': ' '.join(fixed_bug_urls)}
2118
2119
properties_handler_registry.register('bugs_properties_handler',