/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 bzrlib/log.py

Reworked LogFormatter API to simplify extending the attributes of the revision being logged. Added support for begin_log() and end_log() hooks in LogFormatters.
Fixed minor inconsistency between display of revids in mainline and merge revisions in long log format.  Both now labelled "revision-id:" and are only displayed when --show-ids is specified.

Show diffs side-by-side

added added

removed removed

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