~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/log.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-20 12:19:29 UTC
  • mfrom: (6437.23.11 2.5)
  • mto: (6581.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6582.
  • Revision ID: jelmer@samba.org-20120220121929-7ni2psvjoatm1yp4
Merge bzr/2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
16
16
 
17
 
 
18
 
 
19
17
"""Code to show logs of changes.
20
18
 
21
19
Various flavors of log can be produced:
49
47
all the changes since the previous revision that touched hello.c.
50
48
"""
51
49
 
 
50
from __future__ import absolute_import
 
51
 
52
52
import codecs
53
53
from cStringIO import StringIO
54
54
from itertools import (
65
65
lazy_import(globals(), """
66
66
 
67
67
from bzrlib import (
68
 
    bzrdir,
69
68
    config,
 
69
    controldir,
70
70
    diff,
71
71
    errors,
72
72
    foreign,
74
74
    revision as _mod_revision,
75
75
    revisionspec,
76
76
    tsort,
77
 
    i18n,
78
77
    )
 
78
from bzrlib.i18n import gettext, ngettext
79
79
""")
80
80
 
81
81
from bzrlib import (
105
105
    last_ie = None
106
106
    last_path = None
107
107
    revno = 1
108
 
    for revision_id in branch.revision_history():
 
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):
109
112
        this_inv = branch.repository.get_inventory(revision_id)
110
113
        if this_inv.has_id(file_id):
111
114
            this_ie = this_inv[file_id]
215
218
    Logger(branch, rqst).show(lf)
216
219
 
217
220
 
218
 
# Note: This needs to be kept this in sync with the defaults in
 
221
# Note: This needs to be kept in sync with the defaults in
219
222
# make_log_request_dict() below
220
223
_DEFAULT_REQUEST_PARAMS = {
221
224
    'direction': 'reverse',
232
235
                          delta_type=None,
233
236
                          diff_type=None, _match_using_deltas=True,
234
237
                          exclude_common_ancestry=False, match=None,
235
 
                          signature=False,
 
238
                          signature=False, omit_merges=False,
236
239
                          ):
237
240
    """Convenience function for making a logging request dictionary.
238
241
 
288
291
      revisions. Keys can be 'message', 'author', 'committer', 'bugs' or
289
292
      the empty string to match any of the preceding properties.
290
293
 
 
294
    :param omit_merges: If True, commits with more than one parent are
 
295
      omitted.
 
296
 
291
297
    """
292
298
    # Take care of old style message_search parameter
293
299
    if message_search:
311
317
        'exclude_common_ancestry': exclude_common_ancestry,
312
318
        'signature': signature,
313
319
        'match': match,
 
320
        'omit_merges': omit_merges,
314
321
        # Add 'private' attributes for features that may be deprecated
315
322
        '_match_using_deltas': _match_using_deltas,
316
323
    }
334
341
    from bzrlib import gpg
335
342
 
336
343
    gpg_strategy = gpg.GPGStrategy(None)
337
 
    result = repo.verify_revision(rev_id, gpg_strategy)
 
344
    result = repo.verify_revision_signature(rev_id, gpg_strategy)
338
345
    if result[0] == gpg.SIGNATURE_VALID:
339
346
        return "valid signature from {0}".format(result[1])
340
347
    if result[0] == gpg.SIGNATURE_KEY_MISSING:
447
454
        limit = rqst.get('limit')
448
455
        diff_type = rqst.get('diff_type')
449
456
        show_signature = rqst.get('signature')
 
457
        omit_merges = rqst.get('omit_merges')
450
458
        log_count = 0
451
459
        revision_iterator = self._create_log_revision_iterator()
452
460
        for revs in revision_iterator:
454
462
                # 0 levels means show everything; merge_depth counts from 0
455
463
                if levels != 0 and merge_depth >= levels:
456
464
                    continue
 
465
                if omit_merges and len(rev.parent_ids) > 1:
 
466
                    continue
457
467
                if diff_type is None:
458
468
                    diff = None
459
469
                else:
558
568
             a list of the same tuples.
559
569
    """
560
570
    if (exclude_common_ancestry and start_rev_id == end_rev_id):
561
 
        raise errors.BzrCommandError(
562
 
            '--exclude-common-ancestry requires two different revisions')
 
571
        raise errors.BzrCommandError(gettext(
 
572
            '--exclude-common-ancestry requires two different revisions'))
563
573
    if direction not in ('reverse', 'forward'):
564
 
        raise ValueError('invalid direction %r' % direction)
 
574
        raise ValueError(gettext('invalid direction %r') % direction)
565
575
    br_revno, br_rev_id = branch.last_revision_info()
566
576
    if br_revno == 0:
567
577
        return []
570
580
        and (not generate_merge_revisions
571
581
             or not _has_merges(branch, end_rev_id))):
572
582
        # If a single revision is requested, check we can handle it
573
 
        iter_revs = _generate_one_revision(branch, end_rev_id, br_rev_id,
574
 
                                           br_revno)
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)
581
 
    else:
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)))
 
583
        return  _generate_one_revision(branch, end_rev_id, br_rev_id,
 
584
                                       br_revno)
 
585
    if not generate_merge_revisions:
 
586
        try:
 
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)
 
599
            return 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.
 
603
            pass
 
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)))
587
609
    return iter_revs
588
610
 
589
611
 
596
618
        return [(rev_id, revno_str, 0)]
597
619
 
598
620
 
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)):
608
 
        try:
609
 
            result = list(result)
610
 
        except _StartNotLinearAncestor:
611
 
            raise errors.BzrCommandError('Start revision not found in'
612
 
                ' left-hand history of end revision.')
613
 
    return result
614
 
 
615
 
 
616
621
def _generate_all_revisions(branch, start_rev_id, end_rev_id, direction,
617
622
                            delayed_graph_generation,
618
623
                            exclude_common_ancestry=False):
654
659
        except _StartNotLinearAncestor:
655
660
            # A merge was never detected so the lower revision limit can't
656
661
            # be nested down somewhere
657
 
            raise errors.BzrCommandError('Start revision not found in'
658
 
                ' history of end revision.')
 
662
            raise errors.BzrCommandError(gettext('Start revision not found in'
 
663
                ' history of end revision.'))
659
664
 
660
665
    # We exit the loop above because we encounter a revision with merges, from
661
666
    # this revision, we need to switch to _graph_view_revisions.
1072
1077
    if branch_revno != 0:
1073
1078
        if (start_rev_id == _mod_revision.NULL_REVISION
1074
1079
            or end_rev_id == _mod_revision.NULL_REVISION):
1075
 
            raise errors.BzrCommandError('Logging revision 0 is invalid.')
 
1080
            raise errors.BzrCommandError(gettext('Logging revision 0 is invalid.'))
1076
1081
        if start_revno > end_revno:
1077
 
            raise errors.BzrCommandError("Start revision must be older than "
1078
 
                                         "the end revision.")
 
1082
            raise errors.BzrCommandError(gettext("Start revision must be "
 
1083
                                         "older than the end revision."))
1079
1084
    return (start_rev_id, end_rev_id)
1080
1085
 
1081
1086
 
1130
1135
 
1131
1136
    if ((start_rev_id == _mod_revision.NULL_REVISION)
1132
1137
        or (end_rev_id == _mod_revision.NULL_REVISION)):
1133
 
        raise errors.BzrCommandError('Logging revision 0 is invalid.')
 
1138
        raise errors.BzrCommandError(gettext('Logging revision 0 is invalid.'))
1134
1139
    if start_revno > end_revno:
1135
 
        raise errors.BzrCommandError("Start revision must be older than "
1136
 
                                     "the end revision.")
 
1140
        raise errors.BzrCommandError(gettext("Start revision must be older "
 
1141
                                     "than the end revision."))
1137
1142
 
1138
1143
    if end_revno < start_revno:
1139
1144
        return None, None, None, None
1405
1410
            if advice_sep:
1406
1411
                self.to_file.write(advice_sep)
1407
1412
            self.to_file.write(
1408
 
                "Use --include-merges or -n0 to see merged revisions.\n")
 
1413
                "Use --include-merged or -n0 to see merged revisions.\n")
1409
1414
 
1410
1415
    def get_advice_separator(self):
1411
1416
        """Get the text separating the log from the closing advice."""
1789
1794
        return self.get(name)(*args, **kwargs)
1790
1795
 
1791
1796
    def get_default(self, branch):
1792
 
        return self.get(branch.get_config().log_format())
 
1797
        c = branch.get_config_stack()
 
1798
        return self.get(c.get('log_format'))
1793
1799
 
1794
1800
 
1795
1801
log_formatter_registry = LogFormatterRegistry()
1796
1802
 
1797
1803
 
1798
1804
log_formatter_registry.register('short', ShortLogFormatter,
1799
 
                                'Moderately short log format')
 
1805
                                'Moderately short log format.')
1800
1806
log_formatter_registry.register('long', LongLogFormatter,
1801
 
                                'Detailed log format')
 
1807
                                'Detailed log format.')
1802
1808
log_formatter_registry.register('line', LineLogFormatter,
1803
 
                                'Log format with one line per revision')
 
1809
                                'Log format with one line per revision.')
1804
1810
log_formatter_registry.register('gnu-changelog', GnuChangelogLogFormatter,
1805
 
                                'Format used by GNU ChangeLog files')
 
1811
                                'Format used by GNU ChangeLog files.')
1806
1812
 
1807
1813
 
1808
1814
def register_formatter(name, formatter):
1818
1824
    try:
1819
1825
        return log_formatter_registry.make_formatter(name, *args, **kwargs)
1820
1826
    except KeyError:
1821
 
        raise errors.BzrCommandError("unknown log formatter: %r" % name)
 
1827
        raise errors.BzrCommandError(gettext("unknown log formatter: %r") % name)
1822
1828
 
1823
1829
 
1824
1830
def author_list_all(rev):
2017
2023
      kind is one of values 'directory', 'file', 'symlink', 'tree-reference'.
2018
2024
      branch will be read-locked.
2019
2025
    """
2020
 
    from builtins import _get_revision_range
2021
 
    tree, b, path = bzrdir.BzrDir.open_containing_tree_or_branch(file_list[0])
 
2026
    from bzrlib.builtins import _get_revision_range
 
2027
    tree, b, path = controldir.ControlDir.open_containing_tree_or_branch(
 
2028
        file_list[0])
2022
2029
    add_cleanup(b.lock_read().unlock)
2023
2030
    # XXX: It's damn messy converting a list of paths to relative paths when
2024
2031
    # those paths might be deleted ones, they might be on a case-insensitive
2113
2120
                          len(row) > 1 and row[1] == 'fixed']
2114
2121
 
2115
2122
        if fixed_bug_urls:
2116
 
            return {'fixes bug(s)': ' '.join(fixed_bug_urls)}
 
2123
            return {ngettext('fixes bug', 'fixes bugs', len(fixed_bug_urls)):\
 
2124
                    ' '.join(fixed_bug_urls)}
2117
2125
    return {}
2118
2126
 
2119
2127
properties_handler_registry.register('bugs_properties_handler',