/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/log.py

  • Committer: Jelmer Vernooij
  • Date: 2018-11-16 19:47:19 UTC
  • mfrom: (7178 work)
  • mto: This revision was merged to the branch mainline in revision 7179.
  • Revision ID: jelmer@jelmer.uk-20181116194719-m5ut2wfuze5x9s1p
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
65
65
    controldir,
66
66
    diff,
67
67
    foreign,
68
 
    repository as _mod_repository,
 
68
    lazy_regex,
69
69
    revision as _mod_revision,
70
 
    tsort,
71
70
    )
72
71
from breezy.i18n import gettext, ngettext
73
72
""")
74
73
 
75
74
from . import (
76
75
    errors,
77
 
    lazy_regex,
78
76
    registry,
79
77
    revisionspec,
80
78
    )
215
213
 
216
214
    # Build the request and execute it
217
215
    rqst = make_log_request_dict(direction=direction, specific_fileids=file_ids,
218
 
        start_revision=start_revision, end_revision=end_revision,
219
 
        limit=limit, message_search=search,
220
 
        delta_type=delta_type, diff_type=diff_type)
 
216
                                 start_revision=start_revision, end_revision=end_revision,
 
217
                                 limit=limit, message_search=search,
 
218
                                 delta_type=delta_type, diff_type=diff_type)
221
219
    Logger(branch, rqst).show(lf)
222
220
 
223
221
 
306
304
            else:
307
305
                match['message'] = [message_search]
308
306
        else:
309
 
            match= {'message': [message_search]}
 
307
            match = {'message': [message_search]}
310
308
    return {
311
309
        'direction': direction,
312
310
        'specific_fileids': specific_fileids,
422
420
                lf.log_revision(lr)
423
421
        except errors.GhostRevisionUnusableHere:
424
422
            raise errors.BzrCommandError(
425
 
                    gettext('Further revision history missing.'))
 
423
                gettext('Further revision history missing.'))
426
424
        lf.show_advice()
427
425
 
428
426
    def _generator_factory(self, branch, rqst):
464
462
        for revs in revision_iterator:
465
463
            for (rev_id, revno, merge_depth), rev, delta in revs:
466
464
                # 0 levels means show everything; merge_depth counts from 0
467
 
                if levels != 0 and merge_depth is not None and merge_depth >= levels:
 
465
                if (levels != 0 and merge_depth is not None and
 
466
                        merge_depth >= levels):
468
467
                    continue
469
468
                if omit_merges and len(rev.parent_ids) > 1:
470
469
                    continue
478
477
                    signature = format_signature_validity(rev_id, self.branch)
479
478
                else:
480
479
                    signature = None
481
 
                yield LogRevision(rev, revno, merge_depth, delta,
 
480
                yield LogRevision(
 
481
                    rev, revno, merge_depth, delta,
482
482
                    self.rev_tag_dict.get(rev_id), diff, signature)
483
483
                if limit:
484
484
                    log_count += 1
501
501
        s = BytesIO()
502
502
        path_encoding = get_diff_header_encoding()
503
503
        diff.show_diff_trees(tree_1, tree_2, s, specific_files, old_label='',
504
 
            new_label='', path_encoding=path_encoding)
 
504
                             new_label='', path_encoding=path_encoding)
505
505
        return s.getvalue()
506
506
 
507
507
    def _create_log_revision_iterator(self):
521
521
            # not a directory
522
522
            file_count = len(self.rqst.get('specific_fileids'))
523
523
            if file_count != 1:
524
 
                raise BzrError("illegal LogRequest: must match-using-deltas "
 
524
                raise errors.BzrError(
 
525
                    "illegal LogRequest: must match-using-deltas "
525
526
                    "when logging %d files" % file_count)
526
527
            return self._log_revision_iterator_using_per_file_graph()
527
528
 
530
531
        rqst = self.rqst
531
532
        generate_merge_revisions = rqst.get('levels') != 1
532
533
        delayed_graph_generation = not rqst.get('specific_fileids') and (
533
 
                rqst.get('limit') or self.start_rev_id or self.end_rev_id)
 
534
            rqst.get('limit') or self.start_rev_id or self.end_rev_id)
534
535
        view_revisions = _calc_view_revisions(
535
536
            self.branch, self.start_rev_id, self.end_rev_id,
536
537
            rqst.get('direction'),
540
541
 
541
542
        # Apply the other filters
542
543
        return make_log_rev_iterator(self.branch, view_revisions,
543
 
            rqst.get('delta_type'), rqst.get('match'),
544
 
            file_ids=rqst.get('specific_fileids'),
545
 
            direction=rqst.get('direction'))
 
544
                                     rqst.get('delta_type'), rqst.get('match'),
 
545
                                     file_ids=rqst.get('specific_fileids'),
 
546
                                     direction=rqst.get('direction'))
546
547
 
547
548
    def _log_revision_iterator_using_per_file_graph(self):
548
549
        # Get the base revisions, filtering by the revision range.
556
557
        if not isinstance(view_revisions, list):
557
558
            view_revisions = list(view_revisions)
558
559
        view_revisions = _filter_revisions_touching_file_id(self.branch,
559
 
            rqst.get('specific_fileids')[0], view_revisions,
560
 
            include_merges=rqst.get('levels') != 1)
 
560
                                                            rqst.get('specific_fileids')[
 
561
                                                                0], view_revisions,
 
562
                                                            include_merges=rqst.get('levels') != 1)
561
563
        return make_log_rev_iterator(self.branch, view_revisions,
562
 
            rqst.get('delta_type'), rqst.get('match'))
 
564
                                     rqst.get('delta_type'), rqst.get('match'))
563
565
 
564
566
 
565
567
def _calc_view_revisions(branch, start_rev_id, end_rev_id, direction,
585
587
        and (not generate_merge_revisions
586
588
             or not _has_merges(branch, end_rev_id))):
587
589
        # If a single revision is requested, check we can handle it
588
 
        return  _generate_one_revision(branch, end_rev_id, br_rev_id,
589
 
                                       branch.revno())
 
590
        return _generate_one_revision(branch, end_rev_id, br_rev_id,
 
591
                                      branch.revno())
590
592
    if not generate_merge_revisions:
591
593
        try:
592
594
            # If we only want to see linear revisions, we can iterate ...
597
599
            # ancestor of the end limit, check it before outputting anything
598
600
            if (direction == 'forward'
599
601
                or (start_rev_id and not _is_obvious_ancestor(
600
 
                        branch, start_rev_id, end_rev_id))):
601
 
                    iter_revs = list(iter_revs)
 
602
                    branch, start_rev_id, end_rev_id))):
 
603
                iter_revs = list(iter_revs)
602
604
            if direction == 'forward':
603
605
                iter_revs = reversed(iter_revs)
604
606
            return iter_revs
636
638
    initial_revisions = []
637
639
    if delayed_graph_generation:
638
640
        try:
639
 
            for rev_id, revno, depth in  _linear_view_revisions(
640
 
                branch, start_rev_id, end_rev_id, exclude_common_ancestry):
 
641
            for rev_id, revno, depth in _linear_view_revisions(
 
642
                    branch, start_rev_id, end_rev_id, exclude_common_ancestry):
641
643
                if _has_merges(branch, rev_id):
642
644
                    # The end_rev_id can be nested down somewhere. We need an
643
645
                    # explicit ancestry check. There is an ambiguity here as we
650
652
                    # -- vila 20100319
651
653
                    graph = branch.repository.get_graph()
652
654
                    if (start_rev_id is not None
653
 
                        and not graph.is_ancestor(start_rev_id, end_rev_id)):
 
655
                            and not graph.is_ancestor(start_rev_id, end_rev_id)):
654
656
                        raise _StartNotLinearAncestor()
655
657
                    # Since we collected the revisions so far, we need to
656
658
                    # adjust end_rev_id.
665
667
            # A merge was never detected so the lower revision limit can't
666
668
            # be nested down somewhere
667
669
            raise errors.BzrCommandError(gettext('Start revision not found in'
668
 
                ' history of end revision.'))
 
670
                                                 ' history of end revision.'))
669
671
 
670
672
    # We exit the loop above because we encounter a revision with merges, from
671
673
    # this revision, we need to switch to _graph_view_revisions.
676
678
    # make forward the exact opposite display, but showing the merge revisions
677
679
    # indented at the end seems slightly nicer in that case.
678
680
    view_revisions = itertools.chain(iter(initial_revisions),
679
 
        _graph_view_revisions(branch, start_rev_id, end_rev_id,
680
 
                              rebase_initial_depths=(direction == 'reverse'),
681
 
                              exclude_common_ancestry=exclude_common_ancestry))
 
681
                                     _graph_view_revisions(branch, start_rev_id, end_rev_id,
 
682
                                                           rebase_initial_depths=(
 
683
                                                               direction == 'reverse'),
 
684
                                                           exclude_common_ancestry=exclude_common_ancestry))
682
685
    return view_revisions
683
686
 
684
687
 
716
719
            # both on mainline
717
720
            return start_dotted[0] <= end_dotted[0]
718
721
        elif (len(start_dotted) == 3 and len(end_dotted) == 3 and
719
 
            start_dotted[0:1] == end_dotted[0:1]):
 
722
              start_dotted[0:1] == end_dotted[0:1]):
720
723
            # both on same development line
721
724
            return start_dotted[2] <= end_dotted[2]
722
725
        else:
751
754
        else:
752
755
            cur_revno = br_revno
753
756
        graph_iter = graph.iter_lefthand_ancestry(br_rev_id,
754
 
            (_mod_revision.NULL_REVISION,))
 
757
                                                  (_mod_revision.NULL_REVISION,))
755
758
        while True:
756
759
            try:
757
760
                revision_id = next(graph_iter)
771
774
            end_rev_id = br_rev_id
772
775
        found_start = start_rev_id is None
773
776
        graph_iter = graph.iter_lefthand_ancestry(end_rev_id,
774
 
            (_mod_revision.NULL_REVISION,))
 
777
                                                  (_mod_revision.NULL_REVISION,))
775
778
        while True:
776
779
            try:
777
780
                revision_id = next(graph_iter)
844
847
    if view_revisions and view_revisions[0][2] and view_revisions[-1][2]:
845
848
        min_depth = min([d for r, n, d in view_revisions])
846
849
        if min_depth != 0:
847
 
            view_revisions = [(r, n, d-min_depth) for r, n, d in view_revisions]
 
850
            view_revisions = [(r, n, d - min_depth)
 
851
                              for r, n, d in view_revisions]
848
852
    return view_revisions
849
853
 
850
854
 
851
855
def make_log_rev_iterator(branch, view_revisions, generate_delta, search,
852
 
        file_ids=None, direction='reverse'):
 
856
                          file_ids=None, direction='reverse'):
853
857
    """Create a revision iterator for log.
854
858
 
855
859
    :param branch: The branch being logged.
879
883
        # It would be nicer if log adapters were first class objects
880
884
        # with custom parameters. This will do for now. IGC 20090127
881
885
        if adapter == _make_delta_filter:
882
 
            log_rev_iterator = adapter(branch, generate_delta,
883
 
                search, log_rev_iterator, file_ids, direction)
 
886
            log_rev_iterator = adapter(
 
887
                branch, generate_delta, search, log_rev_iterator, file_ids,
 
888
                direction)
884
889
        else:
885
 
            log_rev_iterator = adapter(branch, generate_delta,
886
 
                search, log_rev_iterator)
 
890
            log_rev_iterator = adapter(
 
891
                branch, generate_delta, search, log_rev_iterator)
887
892
    return log_rev_iterator
888
893
 
889
894
 
903
908
    """
904
909
    if not match:
905
910
        return log_rev_iterator
906
 
    searchRE = [(k, [re.compile(x, re.IGNORECASE) for x in v])
 
911
    # Use lazy_compile so mapping to InvalidPattern error occurs.
 
912
    searchRE = [(k, [lazy_regex.lazy_compile(x, re.IGNORECASE) for x in v])
907
913
                for k, v in match.items()]
908
914
    return _filter_re(searchRE, log_rev_iterator)
909
915
 
914
920
        if new_revs:
915
921
            yield new_revs
916
922
 
 
923
 
917
924
def _match_filter(searchRE, rev):
918
925
    strings = {
919
 
               'message': (rev.message,),
920
 
               'committer': (rev.committer,),
921
 
               'author': (rev.get_apparent_authors()),
922
 
               'bugs': list(rev.iter_bugs())
923
 
               }
 
926
        'message': (rev.message,),
 
927
        'committer': (rev.committer,),
 
928
        'author': (rev.get_apparent_authors()),
 
929
        'bugs': list(rev.iter_bugs())
 
930
        }
924
931
    strings[''] = [item for inner_list in strings.values()
925
932
                   for item in inner_list]
926
 
    for (k, v) in searchRE:
 
933
    for k, v in searchRE:
927
934
        if k in strings and not _match_any_filter(strings[k], v):
928
935
            return False
929
936
    return True
930
937
 
 
938
 
931
939
def _match_any_filter(strings, res):
932
 
    return any(re.search(s) for re in res for s in strings)
 
940
    return any(r.search(s) for r in res for s in strings)
 
941
 
933
942
 
934
943
def _make_delta_filter(branch, generate_delta, search, log_rev_iterator,
935
 
    fileids=None, direction='reverse'):
 
944
                       fileids=None, direction='reverse'):
936
945
    """Add revision deltas to a log iterator if needed.
937
946
 
938
947
    :param branch: The branch being logged.
950
959
    if not generate_delta and not fileids:
951
960
        return log_rev_iterator
952
961
    return _generate_deltas(branch.repository, log_rev_iterator,
953
 
        generate_delta, fileids, direction)
 
962
                            generate_delta, fileids, direction)
954
963
 
955
964
 
956
965
def _generate_deltas(repository, log_rev_iterator, delta_type, fileids,
957
 
    direction):
 
966
                     direction):
958
967
    """Create deltas for each batch of revisions in log_rev_iterator.
959
968
 
960
969
    If we're only generating deltas for the sake of filtering against
1103
1112
 
1104
1113
    if branch.last_revision() != _mod_revision.NULL_REVISION:
1105
1114
        if (start_rev_id == _mod_revision.NULL_REVISION
1106
 
            or end_rev_id == _mod_revision.NULL_REVISION):
1107
 
            raise errors.BzrCommandError(gettext('Logging revision 0 is invalid.'))
 
1115
                or end_rev_id == _mod_revision.NULL_REVISION):
 
1116
            raise errors.BzrCommandError(
 
1117
                gettext('Logging revision 0 is invalid.'))
1108
1118
        if end_revno is not None and start_revno > end_revno:
1109
 
            raise errors.BzrCommandError(gettext("Start revision must be "
1110
 
                                         "older than the end revision."))
 
1119
            raise errors.BzrCommandError(
 
1120
                gettext("Start revision must be older than the end revision."))
1111
1121
    return (start_rev_id, end_rev_id)
1112
1122
 
1113
1123
 
1161
1171
            end_revno = end_revision
1162
1172
 
1163
1173
    if ((start_rev_id == _mod_revision.NULL_REVISION)
1164
 
        or (end_rev_id == _mod_revision.NULL_REVISION)):
 
1174
            or (end_rev_id == _mod_revision.NULL_REVISION)):
1165
1175
        raise errors.BzrCommandError(gettext('Logging revision 0 is invalid.'))
1166
1176
    if start_revno > end_revno:
1167
1177
        raise errors.BzrCommandError(gettext("Start revision must be older "
1168
 
                                     "than the end revision."))
 
1178
                                             "than the end revision."))
1169
1179
 
1170
1180
    if end_revno < start_revno:
1171
1181
        return None, None, None, None
1195
1205
 
1196
1206
 
1197
1207
def _filter_revisions_touching_file_id(branch, file_id, view_revisions,
1198
 
    include_merges=True):
 
1208
                                       include_merges=True):
1199
1209
    r"""Return the list of revision ids which touch a given file id.
1200
1210
 
1201
1211
    The function filters view_revisions and returns a subset.
1282
1292
    """Reverse revisions by depth.
1283
1293
 
1284
1294
    Revisions with a different depth are sorted as a group with the previous
1285
 
    revision of that depth.  There may be no topological justification for this,
 
1295
    revision of that depth.  There may be no topological justification for this
1286
1296
    but it looks much nicer.
1287
1297
    """
1288
1298
    # Add a fake revision at start so that we can always attach sub revisions
1395
1405
        """
1396
1406
        self.to_file = to_file
1397
1407
        # 'exact' stream used to show diff, it should print content 'as is'
1398
 
        # and should not try to decode/encode it to unicode to avoid bug #328007
 
1408
        # and should not try to decode/encode it to unicode to avoid bug
 
1409
        # #328007
1399
1410
        if to_exact_file is not None:
1400
1411
            self.to_exact_file = to_exact_file
1401
1412
        else:
1402
 
            # XXX: somewhat hacky; this assumes it's a codec writer; it's better
1403
 
            # for code that expects to get diffs to pass in the exact file
1404
 
            # stream
 
1413
            # XXX: somewhat hacky; this assumes it's a codec writer; it's
 
1414
            # better for code that expects to get diffs to pass in the exact
 
1415
            # file stream
1405
1416
            self.to_exact_file = getattr(to_file, 'stream', to_file)
1406
1417
        self.show_ids = show_ids
1407
1418
        self.show_timezone = show_timezone
1408
1419
        if delta_format is None:
1409
1420
            # Ensures backward compatibility
1410
 
            delta_format = 2 # long format
 
1421
            delta_format = 2  # long format
1411
1422
        self.delta_format = delta_format
1412
1423
        self.levels = levels
1413
1424
        self._show_advice = show_advice
1525
1536
                rev.mapping.vcs.show_foreign_revid(rev.foreign_revid))
1526
1537
 
1527
1538
        # Imported foreign revision revision ids always contain :
1528
 
        if not b":" in rev.revision_id:
 
1539
        if b":" not in rev.revision_id:
1529
1540
            return []
1530
1541
 
1531
1542
        # Revision was once imported from a foreign repository
1576
1587
 
1577
1588
    def _date_string_original_timezone(self, rev):
1578
1589
        return format_date_with_offset_in_original_timezone(rev.timestamp,
1579
 
            rev.timezone or 0)
 
1590
                                                            rev.timezone or 0)
1580
1591
 
1581
1592
    def log_revision(self, revision):
1582
1593
        """Log a revision, either merged or not."""
1584
1595
        lines = [_LONG_SEP]
1585
1596
        if revision.revno is not None:
1586
1597
            lines.append('revno: %s%s' % (revision.revno,
1587
 
                self.merge_marker(revision)))
 
1598
                                          self.merge_marker(revision)))
1588
1599
        if revision.tags:
1589
1600
            lines.append('tags: %s' % (', '.join(sorted(revision.tags))))
1590
1601
        if self.show_ids or revision.revno is None:
1591
 
            lines.append('revision-id: %s' % (revision.rev.revision_id.decode('utf-8'),))
 
1602
            lines.append('revision-id: %s' %
 
1603
                         (revision.rev.revision_id.decode('utf-8'),))
1592
1604
        if self.show_ids:
1593
1605
            for parent_id in revision.rev.parent_ids:
1594
1606
                lines.append('parent: %s' % (parent_id.decode('utf-8'),))
1675
1687
        if revision.tags:
1676
1688
            tags = ' {%s}' % (', '.join(sorted(revision.tags)))
1677
1689
        to_file.write(indent + "%*s %s\t%s%s%s\n" % (revno_width,
1678
 
                revision.revno or "", self.short_author(revision.rev),
1679
 
                format_date(revision.rev.timestamp,
1680
 
                            revision.rev.timezone or 0,
1681
 
                            self.show_timezone, date_fmt="%Y-%m-%d",
1682
 
                            show_offset=False),
1683
 
                tags, self.merge_marker(revision)))
1684
 
        self.show_properties(revision.rev, indent+offset)
 
1690
                                                     revision.revno or "", self.short_author(
 
1691
                                                         revision.rev),
 
1692
                                                     format_date(revision.rev.timestamp,
 
1693
                                                                 revision.rev.timezone or 0,
 
1694
                                                                 self.show_timezone, date_fmt="%Y-%m-%d",
 
1695
                                                                 show_offset=False),
 
1696
                                                     tags, self.merge_marker(revision)))
 
1697
        self.show_properties(revision.rev, indent + offset)
1685
1698
        if self.show_ids or revision.revno is None:
1686
1699
            to_file.write(indent + offset + 'revision-id:%s\n'
1687
1700
                          % (revision.rev.revision_id.decode('utf-8'),))
1696
1709
            # Use the standard status output to display changes
1697
1710
            from breezy.delta import report_delta
1698
1711
            report_delta(to_file, revision.delta,
1699
 
                         short_status=self.delta_format==1,
 
1712
                         short_status=self.delta_format == 1,
1700
1713
                         show_ids=self.show_ids, indent=indent + offset)
1701
1714
        if revision.diff is not None:
1702
1715
            self.show_diff(self.to_exact_file, revision.diff, '      ')
1720
1733
    def truncate(self, str, max_len):
1721
1734
        if max_len is None or len(str) <= max_len:
1722
1735
            return str
1723
 
        return str[:max_len-3] + '...'
 
1736
        return str[:max_len - 3] + '...'
1724
1737
 
1725
1738
    def date_string(self, rev):
1726
1739
        return format_date(rev.timestamp, rev.timezone or 0,
1736
1749
    def log_revision(self, revision):
1737
1750
        indent = '  ' * revision.merge_depth
1738
1751
        self.to_file.write(self.log_string(revision.revno, revision.rev,
1739
 
            self._max_chars, revision.tags, indent))
 
1752
                                           self._max_chars, revision.tags, indent))
1740
1753
        self.to_file.write('\n')
1741
1754
 
1742
1755
    def log_string(self, revno, rev, max_chars, tags=None, prefix=''):
1755
1768
            # show revno only when is not None
1756
1769
            out.append("%s:" % revno)
1757
1770
        if max_chars is not None:
1758
 
            out.append(self.truncate(self.short_author(rev), (max_chars+3)//4))
 
1771
            out.append(self.truncate(
 
1772
                self.short_author(rev), (max_chars + 3) // 4))
1759
1773
        else:
1760
1774
            out.append(self.short_author(rev))
1761
1775
        out.append(self.date_string(rev))
1852
1866
    try:
1853
1867
        return log_formatter_registry.make_formatter(name, *args, **kwargs)
1854
1868
    except KeyError:
1855
 
        raise errors.BzrCommandError(gettext("unknown log formatter: %r") % name)
 
1869
        raise errors.BzrCommandError(
 
1870
            gettext("unknown log formatter: %r") % name)
1856
1871
 
1857
1872
 
1858
1873
def author_list_all(rev):
1894
1909
    """
1895
1910
    if to_file is None:
1896
1911
        to_file = codecs.getwriter(get_terminal_encoding())(sys.stdout,
1897
 
            errors='replace')
 
1912
                                                            errors='replace')
1898
1913
    lf = log_formatter(log_format,
1899
1914
                       show_ids=False,
1900
1915
                       to_file=to_file,
1906
1921
    for i in range(max(len(new_rh), len(old_rh))):
1907
1922
        if (len(new_rh) <= i
1908
1923
            or len(old_rh) <= i
1909
 
            or new_rh[i] != old_rh[i]):
 
1924
                or new_rh[i] != old_rh[i]):
1910
1925
            base_idx = i
1911
1926
            break
1912
1927
 
1913
1928
    if base_idx is None:
1914
1929
        to_file.write('Nothing seems to have changed\n')
1915
1930
        return
1916
 
    ## TODO: It might be nice to do something like show_log
1917
 
    ##       and show the merged entries. But since this is the
1918
 
    ##       removed revisions, it shouldn't be as important
 
1931
    # TODO: It might be nice to do something like show_log
 
1932
    # and show the merged entries. But since this is the
 
1933
    # removed revisions, it shouldn't be as important
1919
1934
    if base_idx < len(old_rh):
1920
 
        to_file.write('*'*60)
 
1935
        to_file.write('*' * 60)
1921
1936
        to_file.write('\nRemoved Revisions:\n')
1922
1937
        for i in range(base_idx, len(old_rh)):
1923
1938
            rev = branch.repository.get_revision(old_rh[i])
1924
 
            lr = LogRevision(rev, i+1, 0, None)
 
1939
            lr = LogRevision(rev, i + 1, 0, None)
1925
1940
            lf.log_revision(lr)
1926
 
        to_file.write('*'*60)
 
1941
        to_file.write('*' * 60)
1927
1942
        to_file.write('\n\n')
1928
1943
    if base_idx < len(new_rh):
1929
1944
        to_file.write('Added Revisions:\n')
1932
1947
                 None,
1933
1948
                 verbose=False,
1934
1949
                 direction='forward',
1935
 
                 start_revision=base_idx+1,
 
1950
                 start_revision=base_idx + 1,
1936
1951
                 end_revision=len(new_rh),
1937
1952
                 search=None)
1938
1953
 
2006
2021
    log_format = log_formatter_registry.get_default(branch)
2007
2022
    lf = log_format(show_ids=False, to_file=output, show_timezone='original')
2008
2023
    if old_history != []:
2009
 
        output.write('*'*60)
 
2024
        output.write('*' * 60)
2010
2025
        output.write('\nRemoved Revisions:\n')
2011
2026
        show_flat_log(branch.repository, old_history, old_revno, lf)
2012
 
        output.write('*'*60)
 
2027
        output.write('*' * 60)
2013
2028
        output.write('\n\n')
2014
2029
    if new_history != []:
2015
2030
        output.write('Added Revisions:\n')
2026
2041
    :param last_revno: The revno of the last revision_id in the history.
2027
2042
    :param lf: The log formatter to use.
2028
2043
    """
2029
 
    start_revno = last_revno - len(history) + 1
2030
2044
    revisions = repository.get_revisions(history)
2031
2045
    for i, rev in enumerate(revisions):
2032
2046
        lr = LogRevision(rev, i + last_revno, 0, None)
2068
2082
        relpaths = [path] + file_list[1:]
2069
2083
    info_list = []
2070
2084
    start_rev_info, end_rev_info = _get_revision_range(revisionspec_list, b,
2071
 
        "log")
 
2085
                                                       "log")
2072
2086
    if relpaths in ([], [u'']):
2073
2087
        return b, [], start_rev_info, end_rev_info
2074
2088
    if start_rev_info is None and end_rev_info is None:
2131
2145
def _get_kind_for_file_id(tree, path, file_id):
2132
2146
    """Return the kind of a file-id or None if it doesn't exist."""
2133
2147
    if file_id is not None:
2134
 
        return tree.kind(path, file_id)
 
2148
        return tree.kind(path)
2135
2149
    else:
2136
2150
        return None
2137
2151
 
2139
2153
properties_handler_registry = registry.Registry()
2140
2154
 
2141
2155
# Use the properties handlers to print out bug information if available
 
2156
 
 
2157
 
2142
2158
def _bugs_properties_handler(revision):
 
2159
    ret = {}
2143
2160
    if 'bugs' in revision.properties:
2144
2161
        bug_lines = revision.properties['bugs'].split('\n')
2145
2162
        bug_rows = [line.split(' ', 1) for line in bug_lines]
2146
2163
        fixed_bug_urls = [row[0] for row in bug_rows if
2147
2164
                          len(row) > 1 and row[1] == 'fixed']
2148
 
 
 
2165
        related_bug_urls = [row[0] for row in bug_rows if
 
2166
                            len(row) > 1 and row[1] == 'related']
2149
2167
        if fixed_bug_urls:
2150
 
            return {ngettext('fixes bug', 'fixes bugs', len(fixed_bug_urls)):\
2151
 
                    ' '.join(fixed_bug_urls)}
2152
 
    return {}
 
2168
            text = ngettext('fixes bug', 'fixes bugs', len(fixed_bug_urls))
 
2169
            ret[text] = ' '.join(fixed_bug_urls)
 
2170
        if related_bug_urls:
 
2171
            text = ngettext('related bug', 'related bugs',
 
2172
                            len(related_bug_urls))
 
2173
            ret[text] = ' '.join(related_bug_urls)
 
2174
    return ret
 
2175
 
2153
2176
 
2154
2177
properties_handler_registry.register('bugs_properties_handler',
2155
2178
                                     _bugs_properties_handler)