~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/log.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2007-05-24 13:09:59 UTC
  • mfrom: (2490.1.4 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20070524130959-7zpl03vgx35bezhf
(Kent Gibson) Update the LogFormatter API to use a LogRevision object.

Show diffs side-by-side

added added

removed removed

Lines of Context:
54
54
from itertools import izip
55
55
import re
56
56
 
57
 
from bzrlib import(
 
57
from bzrlib import (
58
58
    registry,
59
59
    symbol_versioning,
60
60
    )
61
61
import bzrlib.errors as errors
62
 
from bzrlib.symbol_versioning import deprecated_method, zero_eleven
 
62
from bzrlib.symbol_versioning import (
 
63
    deprecated_method,
 
64
    zero_eleven,
 
65
    zero_seventeen,
 
66
    )
63
67
from bzrlib.trace import mutter
64
 
from bzrlib.tsort import(
 
68
from bzrlib.tsort import (
65
69
    merge_sort,
66
70
    topo_sort,
67
71
    )
153
157
    """
154
158
    branch.lock_read()
155
159
    try:
 
160
        if getattr(lf, 'begin_log', None):
 
161
            lf.begin_log()
 
162
 
156
163
        _show_log(branch, lf, specific_fileid, verbose, direction,
157
164
                  start_revision, end_revision, search)
 
165
 
 
166
        if getattr(lf, 'end_log', None):
 
167
            lf.end_log()
158
168
    finally:
159
169
        branch.unlock()
160
 
    
 
170
 
161
171
def _show_log(branch,
162
172
             lf,
163
173
             specific_fileid=None,
210
220
        mainline_revs.insert(0, None)
211
221
    else:
212
222
        mainline_revs.insert(0, which_revs[start_revision-2][1])
213
 
    # how should we show merged revisions ?
214
 
    # old api: show_merge. New api: show_merge_revno
215
 
    show_merge_revno = getattr(lf, 'show_merge_revno', None)
216
 
    show_merge = getattr(lf, 'show_merge', None)
217
 
    if show_merge is None and show_merge_revno is None:
218
 
        # no merged-revno support
219
 
        include_merges = False
220
 
    else:
221
 
        include_merges = True
222
 
    if show_merge is not None and show_merge_revno is None:
 
223
    legacy_lf = getattr(lf, 'log_revision', None) is None
 
224
    if legacy_lf:
 
225
        # pre-0.17 formatters use show for mainline revisions.
 
226
        # how should we show merged revisions ?
 
227
        #   pre-0.11 api: show_merge
 
228
        #   0.11-0.16 api: show_merge_revno
 
229
        show_merge_revno = getattr(lf, 'show_merge_revno', None)
 
230
        show_merge = getattr(lf, 'show_merge', None)
 
231
        if show_merge is None and show_merge_revno is None:
 
232
            # no merged-revno support
 
233
            generate_merge_revisions = False
 
234
        else:
 
235
            generate_merge_revisions = True
223
236
        # tell developers to update their code
224
 
        symbol_versioning.warn('LogFormatters should provide show_merge_revno '
225
 
            'instead of show_merge since bzr 0.11.',
 
237
        symbol_versioning.warn('LogFormatters should provide log_revision '
 
238
            'instead of show and show_merge_revno since bzr 0.17.',
226
239
            DeprecationWarning, stacklevel=3)
 
240
    else:
 
241
        generate_merge_revisions = getattr(lf, 'supports_merge_revisions', 
 
242
                                           False)
227
243
    view_revs_iter = get_view_revisions(mainline_revs, rev_nos, branch,
228
 
                          direction, include_merges=include_merges)
 
244
                          direction, include_merges=generate_merge_revisions)
229
245
    if specific_fileid:
230
246
        view_revisions = _get_revisions_touching_file_id(branch,
231
247
                                                         specific_fileid,
234
250
    else:
235
251
        view_revisions = list(view_revs_iter)
236
252
 
237
 
    use_tags = getattr(lf, 'supports_tags', False)
238
 
    if use_tags:
239
 
        rev_tag_dict = {}
 
253
    rev_tag_dict = {}
 
254
    generate_tags = getattr(lf, 'supports_tags', False)
 
255
    if generate_tags:
240
256
        if branch.supports_tags():
241
257
            rev_tag_dict = branch.tags.get_reverse_tag_dict()
242
258
 
 
259
    generate_delta = verbose and getattr(lf, 'supports_delta', False)
 
260
 
243
261
    def iter_revisions():
244
262
        # r = revision, n = revno, d = merge depth
245
263
        revision_ids = [r for r, n, d in view_revisions]
249
267
        while revision_ids:
250
268
            cur_deltas = {}
251
269
            revisions = repository.get_revisions(revision_ids[:num])
252
 
            if verbose:
 
270
            if generate_delta:
253
271
                delta_revisions = [r for r in revisions if
254
272
                                   r.revision_id in zeros]
255
273
                deltas = repository.get_deltas_for_revisions(delta_revisions)
262
280
                yield revision, cur_deltas.get(revision.revision_id)
263
281
            revision_ids  = revision_ids[num:]
264
282
            num = min(int(num * 1.5), 200)
265
 
            
 
283
 
266
284
    # now we just print all the revisions
267
285
    for ((rev_id, revno, merge_depth), (rev, delta)) in \
268
286
         izip(view_revisions, iter_revisions()):
271
289
            if not searchRE.search(rev.message):
272
290
                continue
273
291
 
274
 
        if merge_depth == 0:
275
 
            if use_tags:
276
 
                lf.show(revno, rev, delta, rev_tag_dict.get(rev_id))
277
 
            else:
278
 
                lf.show(revno, rev, delta)
 
292
        if not legacy_lf:
 
293
            lr = LogRevision(rev, revno, merge_depth, delta,
 
294
                             rev_tag_dict.get(rev_id))
 
295
            lf.log_revision(lr)
279
296
        else:
280
 
            if show_merge_revno is None:
281
 
                lf.show_merge(rev, merge_depth)
 
297
            # support for legacy (pre-0.17) LogFormatters
 
298
            if merge_depth == 0:
 
299
                if generate_tags:
 
300
                    lf.show(revno, rev, delta, rev_tag_dict.get(rev_id))
 
301
                else:
 
302
                    lf.show(revno, rev, delta)
282
303
            else:
283
 
                if use_tags:
284
 
                    lf.show_merge_revno(rev, merge_depth, revno,
285
 
                                        rev_tag_dict.get(rev_id))
 
304
                if show_merge_revno is None:
 
305
                    lf.show_merge(rev, merge_depth)
286
306
                else:
287
 
                    lf.show_merge_revno(rev, merge_depth, revno)
 
307
                    if generate_tags:
 
308
                        lf.show_merge_revno(rev, merge_depth, revno,
 
309
                                            rev_tag_dict.get(rev_id))
 
310
                    else:
 
311
                        lf.show_merge_revno(rev, merge_depth, revno)
288
312
 
289
313
 
290
314
def _get_revisions_touching_file_id(branch, file_id, mainline_revisions,
398
422
    return result
399
423
 
400
424
 
 
425
class LogRevision(object):
 
426
    """A revision to be logged (by LogFormatter.log_revision).
 
427
 
 
428
    A simple wrapper for the attributes of a revision to be logged.
 
429
    The attributes may or may not be populated, as determined by the 
 
430
    logging options and the log formatter capabilities.
 
431
    """
 
432
 
 
433
    def __init__(self, rev=None, revno=None, merge_depth=0, delta=None,
 
434
                 tags=None):
 
435
        self.rev = rev
 
436
        self.revno = revno
 
437
        self.merge_depth = merge_depth
 
438
        self.delta = delta
 
439
        self.tags = tags
 
440
 
 
441
 
401
442
class LogFormatter(object):
402
 
    """Abstract class to display log messages."""
 
443
    """Abstract class to display log messages.
 
444
 
 
445
    At a minimum, a derived class must implement the log_revision method.
 
446
 
 
447
    If the LogFormatter needs to be informed of the beginning or end of
 
448
    a log it should implement the begin_log and/or end_log hook methods.
 
449
 
 
450
    A LogFormatter should define the following supports_XXX flags 
 
451
    to indicate which LogRevision attributes it supports:
 
452
 
 
453
    - supports_delta must be True if this log formatter supports delta.
 
454
        Otherwise the delta attribute may not be populated.
 
455
    - supports_merge_revisions must be True if this log formatter supports 
 
456
        merge revisions.  If not, only revisions mainline revisions (those 
 
457
        with merge_depth == 0) will be passed to the formatter.
 
458
    - supports_tags must be True if this log formatter supports tags.
 
459
        Otherwise the tags attribute may not be populated.
 
460
    """
403
461
 
404
462
    def __init__(self, to_file, show_ids=False, show_timezone='original'):
405
463
        self.to_file = to_file
406
464
        self.show_ids = show_ids
407
465
        self.show_timezone = show_timezone
408
466
 
 
467
# TODO: uncomment this block after show() has been removed.
 
468
# Until then defining log_revision would prevent _show_log calling show() 
 
469
# in legacy formatters.
 
470
#    def log_revision(self, revision):
 
471
#        """Log a revision.
 
472
#
 
473
#        :param  revision:   The LogRevision to be logged.
 
474
#        """
 
475
#        raise NotImplementedError('not implemented in abstract base')
 
476
 
 
477
    @deprecated_method(zero_seventeen)
409
478
    def show(self, revno, rev, delta):
410
479
        raise NotImplementedError('not implemented in abstract base')
411
480
 
415
484
 
416
485
class LongLogFormatter(LogFormatter):
417
486
 
418
 
    supports_tags = True    # must exist and be True
419
 
                            # if this log formatter support tags.
420
 
                            # .show() and .show_merge_revno() must then accept
421
 
                            # the 'tags'-argument with list of tags
 
487
    supports_merge_revisions = True
 
488
    supports_delta = True
 
489
    supports_tags = True
422
490
 
 
491
    @deprecated_method(zero_seventeen)
423
492
    def show(self, revno, rev, delta, tags=None):
424
 
        return self._show_helper(revno=revno, rev=rev, delta=delta, tags=tags)
 
493
        lr = LogRevision(rev, revno, 0, delta, tags)
 
494
        return self.log_revision(lr)
425
495
 
426
496
    @deprecated_method(zero_eleven)
427
497
    def show_merge(self, rev, merge_depth):
428
 
        return self._show_helper(rev=rev, indent='    '*merge_depth,
429
 
                                 merged=True, delta=None)
 
498
        lr = LogRevision(rev, merge_depth=merge_depth)
 
499
        return self.log_revision(lr)
430
500
 
 
501
    @deprecated_method(zero_seventeen)
431
502
    def show_merge_revno(self, rev, merge_depth, revno, tags=None):
432
503
        """Show a merged revision rev, with merge_depth and a revno."""
433
 
        return self._show_helper(rev=rev, revno=revno,
434
 
            indent='    '*merge_depth, merged=True, delta=None, tags=tags)
 
504
        lr = LogRevision(rev, revno, merge_depth, tags=tags)
 
505
        return self.log_revision(lr)
435
506
 
436
 
    def _show_helper(self, rev=None, revno=None, indent='', merged=False,
437
 
                     delta=None, tags=None):
438
 
        """Show a revision, either merged or not."""
 
507
    def log_revision(self, revision):
 
508
        """Log a revision, either merged or not."""
439
509
        from bzrlib.osutils import format_date
 
510
        indent = '    '*revision.merge_depth
440
511
        to_file = self.to_file
441
512
        print >>to_file,  indent+'-' * 60
442
 
        if revno is not None:
443
 
            print >>to_file,  indent+'revno:', revno
444
 
        if tags:
445
 
            print >>to_file, indent+'tags: %s' % (', '.join(tags))
446
 
        if merged:
447
 
            print >>to_file,  indent+'merged:', rev.revision_id
448
 
        elif self.show_ids:
449
 
            print >>to_file,  indent+'revision-id:', rev.revision_id
 
513
        if revision.revno is not None:
 
514
            print >>to_file,  indent+'revno:', revision.revno
 
515
        if revision.tags:
 
516
            print >>to_file, indent+'tags: %s' % (', '.join(revision.tags))
450
517
        if self.show_ids:
451
 
            for parent_id in rev.parent_ids:
 
518
            print >>to_file, indent+'revision-id:', revision.rev.revision_id
 
519
            for parent_id in revision.rev.parent_ids:
452
520
                print >>to_file, indent+'parent:', parent_id
453
 
        print >>to_file,  indent+'committer:', rev.committer
 
521
        print >>to_file, indent+'committer:', revision.rev.committer
454
522
 
455
523
        try:
456
524
            print >>to_file, indent+'branch nick: %s' % \
457
 
                rev.properties['branch-nick']
 
525
                revision.rev.properties['branch-nick']
458
526
        except KeyError:
459
527
            pass
460
 
        date_str = format_date(rev.timestamp,
461
 
                               rev.timezone or 0,
 
528
        date_str = format_date(revision.rev.timestamp,
 
529
                               revision.rev.timezone or 0,
462
530
                               self.show_timezone)
463
531
        print >>to_file,  indent+'timestamp: %s' % date_str
464
532
 
465
533
        print >>to_file,  indent+'message:'
466
 
        if not rev.message:
 
534
        if not revision.rev.message:
467
535
            print >>to_file,  indent+'  (no message)'
468
536
        else:
469
 
            message = rev.message.rstrip('\r\n')
 
537
            message = revision.rev.message.rstrip('\r\n')
470
538
            for l in message.split('\n'):
471
539
                print >>to_file,  indent+'  ' + l
472
 
        if delta is not None:
473
 
            delta.show(to_file, self.show_ids)
 
540
        if revision.delta is not None:
 
541
            revision.delta.show(to_file, self.show_ids)
474
542
 
475
543
 
476
544
class ShortLogFormatter(LogFormatter):
 
545
 
 
546
    supports_delta = True
 
547
 
 
548
    @deprecated_method(zero_seventeen)
477
549
    def show(self, revno, rev, delta):
 
550
        lr = LogRevision(rev, revno, 0, delta)
 
551
        return self.log_revision(lr)
 
552
 
 
553
    def log_revision(self, revision):
478
554
        from bzrlib.osutils import format_date
479
555
 
480
556
        to_file = self.to_file
481
 
        date_str = format_date(rev.timestamp, rev.timezone or 0,
482
 
                            self.show_timezone)
483
 
        print >>to_file, "%5s %s\t%s" % (revno, self.short_committer(rev),
484
 
                format_date(rev.timestamp, rev.timezone or 0,
 
557
        date_str = format_date(revision.rev.timestamp, 
 
558
                               revision.rev.timezone or 0,
 
559
                               self.show_timezone)
 
560
        print >>to_file, "%5s %s\t%s" % (revision.revno, 
 
561
                self.short_committer(revision.rev),
 
562
                format_date(revision.rev.timestamp, 
 
563
                            revision.rev.timezone or 0,
485
564
                            self.show_timezone, date_fmt="%Y-%m-%d",
486
 
                           show_offset=False))
 
565
                            show_offset=False))
487
566
        if self.show_ids:
488
 
            print >>to_file,  '      revision-id:', rev.revision_id
489
 
        if not rev.message:
 
567
            print >>to_file,  '      revision-id:', revision.rev.revision_id
 
568
        if not revision.rev.message:
490
569
            print >>to_file,  '      (no message)'
491
570
        else:
492
 
            message = rev.message.rstrip('\r\n')
 
571
            message = revision.rev.message.rstrip('\r\n')
493
572
            for l in message.split('\n'):
494
573
                print >>to_file,  '      ' + l
495
574
 
496
575
        # TODO: Why not show the modified files in a shorter form as
497
576
        # well? rewrap them single lines of appropriate length
498
 
        if delta is not None:
499
 
            delta.show(to_file, self.show_ids)
 
577
        if revision.delta is not None:
 
578
            revision.delta.show(to_file, self.show_ids)
500
579
        print >>to_file, ''
501
580
 
502
581
 
503
582
class LineLogFormatter(LogFormatter):
 
583
 
 
584
    def __init__(self, *args, **kwargs):
 
585
        from bzrlib.osutils import terminal_width
 
586
        super(LineLogFormatter, self).__init__(*args, **kwargs)
 
587
        self._max_chars = terminal_width() - 1
 
588
 
504
589
    def truncate(self, str, max_len):
505
590
        if len(str) <= max_len:
506
591
            return str
518
603
        else:
519
604
            return rev.message
520
605
 
 
606
    @deprecated_method(zero_seventeen)
521
607
    def show(self, revno, rev, delta):
522
608
        from bzrlib.osutils import terminal_width
523
609
        print >> self.to_file, self.log_string(revno, rev, terminal_width()-1)
524
610
 
 
611
    def log_revision(self, revision):
 
612
        print >>self.to_file, self.log_string(revision.revno, revision.rev,
 
613
                                              self._max_chars)
 
614
 
525
615
    def log_string(self, revno, rev, max_chars):
526
616
        """Format log info into one string. Truncate tail of string
527
617
        :param  revno:      revision number (int) or None.
593
683
    lf = LongLogFormatter(to_file=to_file, show_timezone=show_timezone)
594
684
    lf.show(revno, rev, delta)
595
685
 
 
686
 
596
687
def show_changed_revisions(branch, old_rh, new_rh, to_file=None, log_format='long'):
597
688
    """Show the change in revision history comparing the old revision history to the new one.
598
689
 
633
724
        to_file.write('\nRemoved Revisions:\n')
634
725
        for i in range(base_idx, len(old_rh)):
635
726
            rev = branch.repository.get_revision(old_rh[i])
636
 
            lf.show(i+1, rev, None)
 
727
            lr = LogRevision(rev, i+1, 0, None)
 
728
            lf.log_revision(lr)
637
729
        to_file.write('*'*60)
638
730
        to_file.write('\n\n')
639
731
    if base_idx < len(new_rh):