~ubuntu-branches/ubuntu/karmic/bzr/karmic-proposed

« back to all changes in this revision

Viewing changes to bzrlib/log.py

  • Committer: Bazaar Package Importer
  • Author(s): Jelmer Vernooij
  • Date: 2008-08-25 19:06:49 UTC
  • mfrom: (1.1.44 upstream)
  • Revision ID: james.westby@ubuntu.com-20080825190649-pq87jonr4uvs7s0y
Tags: 1.6-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
59
59
    warn,
60
60
    )
61
61
 
 
62
from bzrlib.lazy_import import lazy_import
 
63
lazy_import(globals(), """
 
64
 
62
65
from bzrlib import (
63
66
    config,
64
 
    lazy_regex,
 
67
    errors,
 
68
    repository as _mod_repository,
 
69
    revision as _mod_revision,
 
70
    revisionspec,
 
71
    trace,
 
72
    tsort,
 
73
    )
 
74
""")
 
75
 
 
76
from bzrlib import (
65
77
    registry,
66
78
    )
67
 
from bzrlib.errors import (
68
 
    BzrCommandError,
69
 
    )
70
79
from bzrlib.osutils import (
71
80
    format_date,
72
81
    get_terminal_encoding,
73
82
    terminal_width,
74
83
    )
75
 
from bzrlib.repository import _strip_NULL_ghosts
76
 
from bzrlib.revision import (
77
 
    NULL_REVISION,
78
 
    )
79
 
from bzrlib.revisionspec import (
80
 
    RevisionInfo,
81
 
    )
82
 
from bzrlib.trace import mutter
83
 
from bzrlib.tsort import (
84
 
    merge_sort,
85
 
    topo_sort,
86
 
    )
87
84
 
88
85
 
89
86
def find_touching_revisions(branch, file_id):
204
201
        warn("not a LogFormatter instance: %r" % lf)
205
202
 
206
203
    if specific_fileid:
207
 
        mutter('get log for file_id %r', specific_fileid)
 
204
        trace.mutter('get log for file_id %r', specific_fileid)
208
205
    generate_merge_revisions = getattr(lf, 'supports_merge_revisions', False)
209
206
    allow_single_merge_revision = getattr(lf,
210
207
        'supports_single_merge_revision', False)
265
262
        generate_single_revision = ((start_rev_id == end_rev_id)
266
263
            and allow_single_merge_revision)
267
264
        if not generate_single_revision:
268
 
            raise BzrCommandError('Selected log formatter only supports '
269
 
                'mainline revisions.')
 
265
            raise errors.BzrCommandError('Selected log formatter only supports'
 
266
                ' mainline revisions.')
270
267
        generate_merge_revisions = generate_single_revision
271
268
    view_revs_iter = get_view_revisions(mainline_revs, rev_nos, branch,
272
269
                          direction, include_merges=generate_merge_revisions)
335
332
 
336
333
    :return: A (mainline_revs, rev_nos, start_rev_id, end_rev_id) tuple.
337
334
    """
338
 
    which_revs = _enumerate_history(branch)
339
 
    if not which_revs:
 
335
    branch_revno, branch_last_revision = branch.last_revision_info()
 
336
    if branch_revno == 0:
340
337
        return None, None, None, None
341
338
 
342
339
    # For mainline generation, map start_revision and end_revision to 
349
346
    if start_revision is None:
350
347
        start_revno = 1
351
348
    else:
352
 
        if isinstance(start_revision,RevisionInfo):
 
349
        if isinstance(start_revision, revisionspec.RevisionInfo):
353
350
            start_rev_id = start_revision.rev_id
354
351
            start_revno = start_revision.revno or 1
355
352
        else:
358
355
    
359
356
    end_rev_id = None
360
357
    if end_revision is None:
361
 
        end_revno = len(which_revs)
 
358
        end_revno = branch_revno
362
359
    else:
363
 
        if isinstance(end_revision,RevisionInfo):
 
360
        if isinstance(end_revision, revisionspec.RevisionInfo):
364
361
            end_rev_id = end_revision.rev_id
365
 
            end_revno = end_revision.revno or len(which_revs)
 
362
            end_revno = end_revision.revno or branch_revno
366
363
        else:
367
364
            branch.check_real_revno(end_revision)
368
365
            end_revno = end_revision
369
366
 
370
 
    if ((start_rev_id == NULL_REVISION)
371
 
        or (end_rev_id == NULL_REVISION)):
372
 
        raise BzrCommandError('Logging revision 0 is invalid.')
 
367
    if ((start_rev_id == _mod_revision.NULL_REVISION)
 
368
        or (end_rev_id == _mod_revision.NULL_REVISION)):
 
369
        raise errors.BzrCommandError('Logging revision 0 is invalid.')
373
370
    if start_revno > end_revno:
374
 
        raise BzrCommandError("Start revision must be older than "
375
 
                              "the end revision.")
 
371
        raise errors.BzrCommandError("Start revision must be older than "
 
372
                                     "the end revision.")
376
373
 
377
 
    # list indexes are 0-based; revisions are 1-based
378
 
    cut_revs = which_revs[(start_revno-1):(end_revno)]
379
 
    if not cut_revs:
 
374
    if end_revno < start_revno:
380
375
        return None, None, None, None
 
376
    cur_revno = branch_revno
 
377
    rev_nos = {}
 
378
    mainline_revs = []
 
379
    for revision_id in branch.repository.iter_reverse_revision_history(
 
380
                        branch_last_revision):
 
381
        if cur_revno < start_revno:
 
382
            # We have gone far enough, but we always add 1 more revision
 
383
            rev_nos[revision_id] = cur_revno
 
384
            mainline_revs.append(revision_id)
 
385
            break
 
386
        if cur_revno <= end_revno:
 
387
            rev_nos[revision_id] = cur_revno
 
388
            mainline_revs.append(revision_id)
 
389
        cur_revno -= 1
 
390
    else:
 
391
        # We walked off the edge of all revisions, so we add a 'None' marker
 
392
        mainline_revs.append(None)
381
393
 
382
 
    # convert the revision history to a dictionary:
383
 
    rev_nos = dict((k, v) for v, k in cut_revs)
 
394
    mainline_revs.reverse()
384
395
 
385
396
    # override the mainline to look like the revision history.
386
 
    mainline_revs = [revision_id for index, revision_id in cut_revs]
387
 
    if cut_revs[0][0] == 1:
388
 
        mainline_revs.insert(0, None)
389
 
    else:
390
 
        mainline_revs.insert(0, which_revs[start_revno-2][1])
391
397
    return mainline_revs, rev_nos, start_rev_id, end_rev_id
392
398
 
393
399
 
455
461
    :return: A list of (revision_id, dotted_revno, merge_depth) tuples.
456
462
    """
457
463
    # find all the revisions that change the specific file
458
 
    file_weave = branch.repository.weave_store.get_weave(file_id,
459
 
                branch.repository.get_transaction())
460
 
    weave_modifed_revisions = set(file_weave.versions())
461
464
    # build the ancestry of each revision in the graph
462
465
    # - only listing the ancestors that change the specific file.
463
466
    graph = branch.repository.get_graph()
468
471
    # don't request it.
469
472
    parent_map = dict(((key, value) for key, value in
470
473
        graph.iter_ancestry(mainline_revisions[1:]) if value is not None))
471
 
    sorted_rev_list = topo_sort(parent_map.items())
 
474
    sorted_rev_list = tsort.topo_sort(parent_map.items())
 
475
    text_keys = [(file_id, rev_id) for rev_id in sorted_rev_list]
 
476
    modified_text_versions = branch.repository.texts.get_parent_map(text_keys)
472
477
    ancestry = {}
473
478
    for rev in sorted_rev_list:
 
479
        text_key = (file_id, rev)
474
480
        parents = parent_map[rev]
475
 
        if rev not in weave_modifed_revisions and len(parents) == 1:
 
481
        if text_key not in modified_text_versions and len(parents) == 1:
476
482
            # We will not be adding anything new, so just use a reference to
477
483
            # the parent ancestry.
478
484
            rev_ancestry = ancestry[parents[0]]
479
485
        else:
480
486
            rev_ancestry = set()
481
 
            if rev in weave_modifed_revisions:
 
487
            if text_key in modified_text_versions:
482
488
                rev_ancestry.add(rev)
483
489
            for parent in parents:
484
490
                if parent not in ancestry:
502
508
    # filter from the view the revisions that did not change or merge 
503
509
    # the specific file
504
510
    return [(r, n, d) for r, n, d in view_revs_iter
505
 
            if r in weave_modifed_revisions or is_merging_rev(r)]
 
511
            if (file_id, r) in modified_text_versions or is_merging_rev(r)]
506
512
 
507
513
 
508
514
def get_view_revisions(mainline_revs, rev_nos, branch, direction,
522
528
    # This asks for all mainline revisions, which means we only have to spider
523
529
    # sideways, rather than depth history. That said, its still size-of-history
524
530
    # and should be addressed.
 
531
    # mainline_revisions always includes an extra revision at the beginning, so
 
532
    # don't request it.
525
533
    parent_map = dict(((key, value) for key, value in
526
 
        graph.iter_ancestry(mainline_revs) if value is not None))
 
534
        graph.iter_ancestry(mainline_revs[1:]) if value is not None))
527
535
    # filter out ghosts; merge_sort errors on ghosts.
528
 
    rev_graph = _strip_NULL_ghosts(parent_map)
529
 
    merge_sorted_revisions = merge_sort(
 
536
    rev_graph = _mod_repository._strip_NULL_ghosts(parent_map)
 
537
    merge_sorted_revisions = tsort.merge_sort(
530
538
        rev_graph,
531
539
        mainline_revs[-1],
532
540
        mainline_revs,
604
612
        only relevant if supports_merge_revisions is not True.
605
613
    - supports_tags must be True if this log formatter supports tags.
606
614
        Otherwise the tags attribute may not be populated.
 
615
 
 
616
    Plugins can register functions to show custom revision properties using
 
617
    the properties_handler_registry. The registered function
 
618
    must respect the following interface description:
 
619
        def my_show_properties(properties_dict):
 
620
            # code that returns a dict {'name':'value'} of the properties 
 
621
            # to be shown
607
622
    """
608
623
 
609
624
    def __init__(self, to_file, show_ids=False, show_timezone='original'):
633
648
            return name
634
649
        return address
635
650
 
 
651
    def show_properties(self, revision, indent):
 
652
        """Displays the custom properties returned by each registered handler.
 
653
        
 
654
        If a registered handler raises an error it is propagated.
 
655
        """
 
656
        for key, handler in properties_handler_registry.iteritems():
 
657
            for key, value in handler(revision).items():
 
658
                self.to_file.write(indent + key + ': ' + value + '\n')
 
659
 
636
660
 
637
661
class LongLogFormatter(LogFormatter):
638
662
 
654
678
            to_file.write('\n')
655
679
            for parent_id in revision.rev.parent_ids:
656
680
                to_file.write(indent + 'parent: %s\n' % (parent_id,))
 
681
        self.show_properties(revision.rev, indent)
657
682
 
658
683
        author = revision.rev.properties.get('author', None)
659
684
        if author is not None:
687
712
 
688
713
    def log_revision(self, revision):
689
714
        to_file = self.to_file
690
 
        date_str = format_date(revision.rev.timestamp,
691
 
                               revision.rev.timezone or 0,
692
 
                               self.show_timezone)
693
715
        is_merge = ''
694
716
        if len(revision.rev.parent_ids) > 1:
695
717
            is_merge = ' [merge]'
807
829
    try:
808
830
        return log_formatter_registry.make_formatter(name, *args, **kwargs)
809
831
    except KeyError:
810
 
        raise BzrCommandError("unknown log formatter: %r" % name)
 
832
        raise errors.BzrCommandError("unknown log formatter: %r" % name)
811
833
 
812
834
 
813
835
def show_one_log(revno, rev, delta, verbose, to_file, show_timezone):
870
892
                 end_revision=len(new_rh),
871
893
                 search=None)
872
894
 
 
895
 
 
896
properties_handler_registry = registry.Registry()