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]
236
233
diff_type=None, _match_using_deltas=True,
237
234
exclude_common_ancestry=False, match=None,
238
signature=False, omit_merges=False,
240
237
"""Convenience function for making a logging request dictionary.
341
334
from bzrlib import gpg
343
336
gpg_strategy = gpg.GPGStrategy(None)
344
result = repo.verify_revision_signature(rev_id, gpg_strategy)
337
result = repo.verify_revision(rev_id, gpg_strategy)
345
338
if result[0] == gpg.SIGNATURE_VALID:
346
339
return "valid signature from {0}".format(result[1])
347
340
if result[0] == gpg.SIGNATURE_KEY_MISSING:
568
558
a list of the same tuples.
570
560
if (exclude_common_ancestry and start_rev_id == end_rev_id):
571
raise errors.BzrCommandError(gettext(
572
'--exclude-common-ancestry requires two different revisions'))
561
raise errors.BzrCommandError(
562
'--exclude-common-ancestry requires two different revisions')
573
563
if direction not in ('reverse', 'forward'):
574
raise ValueError(gettext('invalid direction %r') % direction)
564
raise ValueError('invalid direction %r' % direction)
575
565
br_revno, br_rev_id = branch.last_revision_info()
576
566
if br_revno == 0:
580
570
and (not generate_merge_revisions
581
571
or not _has_merges(branch, end_rev_id))):
582
572
# If a single revision is requested, check we can handle it
583
return _generate_one_revision(branch, end_rev_id, br_rev_id,
585
if not generate_merge_revisions:
587
# If we only want to see linear revisions, we can iterate ...
588
iter_revs = _linear_view_revisions(
589
branch, start_rev_id, end_rev_id,
590
exclude_common_ancestry=exclude_common_ancestry)
591
# If a start limit was given and it's not obviously an
592
# ancestor of the end limit, check it before outputting anything
593
if (direction == 'forward'
594
or (start_rev_id and not _is_obvious_ancestor(
595
branch, start_rev_id, end_rev_id))):
596
iter_revs = list(iter_revs)
597
if direction == 'forward':
598
iter_revs = reversed(iter_revs)
600
except _StartNotLinearAncestor:
601
# Switch to the slower implementation that may be able to find a
602
# non-obvious ancestor out of the left-hand history.
604
iter_revs = _generate_all_revisions(branch, start_rev_id, end_rev_id,
605
direction, delayed_graph_generation,
606
exclude_common_ancestry)
607
if direction == 'forward':
608
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)))
618
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.')
621
616
def _generate_all_revisions(branch, start_rev_id, end_rev_id, direction,
622
617
delayed_graph_generation,
623
618
exclude_common_ancestry=False):
659
654
except _StartNotLinearAncestor:
660
655
# A merge was never detected so the lower revision limit can't
661
656
# be nested down somewhere
662
raise errors.BzrCommandError(gettext('Start revision not found in'
663
' history of end revision.'))
657
raise errors.BzrCommandError('Start revision not found in'
658
' history of end revision.')
665
660
# We exit the loop above because we encounter a revision with merges, from
666
661
# this revision, we need to switch to _graph_view_revisions.
1077
1072
if branch_revno != 0:
1078
1073
if (start_rev_id == _mod_revision.NULL_REVISION
1079
1074
or end_rev_id == _mod_revision.NULL_REVISION):
1080
raise errors.BzrCommandError(gettext('Logging revision 0 is invalid.'))
1075
raise errors.BzrCommandError('Logging revision 0 is invalid.')
1081
1076
if start_revno > end_revno:
1082
raise errors.BzrCommandError(gettext("Start revision must be "
1083
"older than the end revision."))
1077
raise errors.BzrCommandError("Start revision must be older than "
1078
"the end revision.")
1084
1079
return (start_rev_id, end_rev_id)
1136
1131
if ((start_rev_id == _mod_revision.NULL_REVISION)
1137
1132
or (end_rev_id == _mod_revision.NULL_REVISION)):
1138
raise errors.BzrCommandError(gettext('Logging revision 0 is invalid.'))
1133
raise errors.BzrCommandError('Logging revision 0 is invalid.')
1139
1134
if start_revno > end_revno:
1140
raise errors.BzrCommandError(gettext("Start revision must be older "
1141
"than the end revision."))
1135
raise errors.BzrCommandError("Start revision must be older than "
1136
"the end revision.")
1143
1138
if end_revno < start_revno:
1144
1139
return None, None, None, None
1794
1789
return self.get(name)(*args, **kwargs)
1796
1791
def get_default(self, branch):
1797
c = branch.get_config_stack()
1798
return self.get(c.get('log_format'))
1792
return self.get(branch.get_config().log_format())
1801
1795
log_formatter_registry = LogFormatterRegistry()
1804
1798
log_formatter_registry.register('short', ShortLogFormatter,
1805
'Moderately short log format.')
1799
'Moderately short log format')
1806
1800
log_formatter_registry.register('long', LongLogFormatter,
1807
'Detailed log format.')
1801
'Detailed log format')
1808
1802
log_formatter_registry.register('line', LineLogFormatter,
1809
'Log format with one line per revision.')
1803
'Log format with one line per revision')
1810
1804
log_formatter_registry.register('gnu-changelog', GnuChangelogLogFormatter,
1811
'Format used by GNU ChangeLog files.')
1805
'Format used by GNU ChangeLog files')
1814
1808
def register_formatter(name, formatter):
2023
2017
kind is one of values 'directory', 'file', 'symlink', 'tree-reference'.
2024
2018
branch will be read-locked.
2026
from bzrlib.builtins import _get_revision_range
2027
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])
2029
2022
add_cleanup(b.lock_read().unlock)
2030
2023
# XXX: It's damn messy converting a list of paths to relative paths when
2031
2024
# those paths might be deleted ones, they might be on a case-insensitive
2120
2113
len(row) > 1 and row[1] == 'fixed']
2122
2115
if fixed_bug_urls:
2123
return {ngettext('fixes bug', 'fixes bugs', len(fixed_bug_urls)):\
2124
' '.join(fixed_bug_urls)}
2116
return {'fixes bug(s)': ' '.join(fixed_bug_urls)}
2127
2119
properties_handler_registry.register('bugs_properties_handler',