/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

  • Committer: John Arbash Meinel
  • Date: 2007-07-11 23:45:20 UTC
  • mfrom: (2601 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2643.
  • Revision ID: john@arbash-meinel.com-20070711234520-do3h7zw8skbathpz
[merge] bzr.dev 2601

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.revisionspec import(
 
63
    RevisionInfo
 
64
    )
 
65
from bzrlib.symbol_versioning import (
 
66
    deprecated_method,
 
67
    zero_eleven,
 
68
    zero_seventeen,
 
69
    )
63
70
from bzrlib.trace import mutter
64
 
from bzrlib.tsort import(
 
71
from bzrlib.tsort import (
65
72
    merge_sort,
66
73
    topo_sort,
67
74
    )
111
118
        revno += 1
112
119
 
113
120
 
114
 
 
115
121
def _enumerate_history(branch):
116
122
    rh = []
117
123
    revno = 1
128
134
             direction='reverse',
129
135
             start_revision=None,
130
136
             end_revision=None,
131
 
             search=None):
 
137
             search=None,
 
138
             limit=None):
132
139
    """Write out human-readable log of commits to this branch.
133
140
 
134
141
    lf
150
157
 
151
158
    end_revision
152
159
        If not None, only show revisions <= end_revision
 
160
 
 
161
    search
 
162
        If not None, only show revisions with matching commit messages
 
163
 
 
164
    limit
 
165
        If not None or 0, only show limit revisions
153
166
    """
154
167
    branch.lock_read()
155
168
    try:
 
169
        if getattr(lf, 'begin_log', None):
 
170
            lf.begin_log()
 
171
 
156
172
        _show_log(branch, lf, specific_fileid, verbose, direction,
157
 
                  start_revision, end_revision, search)
 
173
                  start_revision, end_revision, search, limit)
 
174
 
 
175
        if getattr(lf, 'end_log', None):
 
176
            lf.end_log()
158
177
    finally:
159
178
        branch.unlock()
160
 
    
 
179
 
161
180
def _show_log(branch,
162
181
             lf,
163
182
             specific_fileid=None,
165
184
             direction='reverse',
166
185
             start_revision=None,
167
186
             end_revision=None,
168
 
             search=None):
 
187
             search=None,
 
188
             limit=None):
169
189
    """Worker function for show_log - see show_log."""
170
190
    from bzrlib.osutils import format_date
171
191
    from bzrlib.errors import BzrCheckError
184
204
    else:
185
205
        searchRE = None
186
206
 
187
 
    which_revs = _enumerate_history(branch)
188
 
    
189
 
    if start_revision is None:
190
 
        start_revision = 1
191
 
    else:
192
 
        branch.check_real_revno(start_revision)
193
 
    
194
 
    if end_revision is None:
195
 
        end_revision = len(which_revs)
196
 
    else:
197
 
        branch.check_real_revno(end_revision)
198
 
 
199
 
    # list indexes are 0-based; revisions are 1-based
200
 
    cut_revs = which_revs[(start_revision-1):(end_revision)]
201
 
    if not cut_revs:
 
207
    mainline_revs, rev_nos, start_rev_id, end_rev_id = \
 
208
        _get_mainline_revs(branch, start_revision, end_revision)
 
209
    if not mainline_revs:
202
210
        return
203
211
 
204
 
    # convert the revision history to a dictionary:
205
 
    rev_nos = dict((k, v) for v, k in cut_revs)
206
 
 
207
 
    # override the mainline to look like the revision history.
208
 
    mainline_revs = [revision_id for index, revision_id in cut_revs]
209
 
    if cut_revs[0][0] == 1:
210
 
        mainline_revs.insert(0, None)
211
 
    else:
212
 
        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:
 
212
    if direction == 'reverse':
 
213
        start_rev_id, end_rev_id = end_rev_id, start_rev_id
 
214
        
 
215
    legacy_lf = getattr(lf, 'log_revision', None) is None
 
216
    if legacy_lf:
 
217
        # pre-0.17 formatters use show for mainline revisions.
 
218
        # how should we show merged revisions ?
 
219
        #   pre-0.11 api: show_merge
 
220
        #   0.11-0.16 api: show_merge_revno
 
221
        show_merge_revno = getattr(lf, 'show_merge_revno', None)
 
222
        show_merge = getattr(lf, 'show_merge', None)
 
223
        if show_merge is None and show_merge_revno is None:
 
224
            # no merged-revno support
 
225
            generate_merge_revisions = False
 
226
        else:
 
227
            generate_merge_revisions = True
223
228
        # 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.',
 
229
        symbol_versioning.warn('LogFormatters should provide log_revision '
 
230
            'instead of show and show_merge_revno since bzr 0.17.',
226
231
            DeprecationWarning, stacklevel=3)
 
232
    else:
 
233
        generate_merge_revisions = getattr(lf, 'supports_merge_revisions', 
 
234
                                           False)
227
235
    view_revs_iter = get_view_revisions(mainline_revs, rev_nos, branch,
228
 
                          direction, include_merges=include_merges)
 
236
                          direction, include_merges=generate_merge_revisions)
 
237
    view_revisions = _filter_revision_range(list(view_revs_iter),
 
238
                                            start_rev_id,
 
239
                                            end_rev_id)
229
240
    if specific_fileid:
230
 
        view_revisions = _get_revisions_touching_file_id(branch,
 
241
        view_revisions = _filter_revisions_touching_file_id(branch,
231
242
                                                         specific_fileid,
232
243
                                                         mainline_revs,
233
 
                                                         view_revs_iter)
234
 
    else:
235
 
        view_revisions = list(view_revs_iter)
 
244
                                                         view_revisions)
236
245
 
237
 
    use_tags = getattr(lf, 'supports_tags', False)
238
 
    if use_tags:
239
 
        rev_tag_dict = {}
 
246
    rev_tag_dict = {}
 
247
    generate_tags = getattr(lf, 'supports_tags', False)
 
248
    if generate_tags:
240
249
        if branch.supports_tags():
241
250
            rev_tag_dict = branch.tags.get_reverse_tag_dict()
242
251
 
 
252
    generate_delta = verbose and getattr(lf, 'supports_delta', False)
 
253
 
243
254
    def iter_revisions():
244
255
        # r = revision, n = revno, d = merge depth
245
256
        revision_ids = [r for r, n, d in view_revisions]
246
 
        zeros = set(r for r, n, d in view_revisions if d == 0)
247
257
        num = 9
248
258
        repository = branch.repository
249
259
        while revision_ids:
250
260
            cur_deltas = {}
251
261
            revisions = repository.get_revisions(revision_ids[:num])
252
 
            if verbose:
253
 
                delta_revisions = [r for r in revisions if
254
 
                                   r.revision_id in zeros]
255
 
                deltas = repository.get_deltas_for_revisions(delta_revisions)
256
 
                cur_deltas = dict(izip((r.revision_id for r in 
257
 
                                        delta_revisions), deltas))
 
262
            if generate_delta:
 
263
                deltas = repository.get_deltas_for_revisions(revisions)
 
264
                cur_deltas = dict(izip((r.revision_id for r in revisions),
 
265
                                       deltas))
258
266
            for revision in revisions:
259
 
                # The delta value will be None unless
260
 
                # 1. verbose is specified, and
261
 
                # 2. the revision is a mainline revision
262
267
                yield revision, cur_deltas.get(revision.revision_id)
263
268
            revision_ids  = revision_ids[num:]
264
269
            num = min(int(num * 1.5), 200)
265
 
            
 
270
 
266
271
    # now we just print all the revisions
 
272
    log_count = 0
267
273
    for ((rev_id, revno, merge_depth), (rev, delta)) in \
268
274
         izip(view_revisions, iter_revisions()):
269
275
 
271
277
            if not searchRE.search(rev.message):
272
278
                continue
273
279
 
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)
279
 
        else:
280
 
            if show_merge_revno is None:
281
 
                lf.show_merge(rev, merge_depth)
282
 
            else:
283
 
                if use_tags:
284
 
                    lf.show_merge_revno(rev, merge_depth, revno,
285
 
                                        rev_tag_dict.get(rev_id))
286
 
                else:
287
 
                    lf.show_merge_revno(rev, merge_depth, revno)
288
 
 
289
 
 
290
 
def _get_revisions_touching_file_id(branch, file_id, mainline_revisions,
291
 
                                    view_revs_iter):
 
280
        if not legacy_lf:
 
281
            lr = LogRevision(rev, revno, merge_depth, delta,
 
282
                             rev_tag_dict.get(rev_id))
 
283
            lf.log_revision(lr)
 
284
        else:
 
285
            # support for legacy (pre-0.17) LogFormatters
 
286
            if merge_depth == 0:
 
287
                if generate_tags:
 
288
                    lf.show(revno, rev, delta, rev_tag_dict.get(rev_id))
 
289
                else:
 
290
                    lf.show(revno, rev, delta)
 
291
            else:
 
292
                if show_merge_revno is None:
 
293
                    lf.show_merge(rev, merge_depth)
 
294
                else:
 
295
                    if generate_tags:
 
296
                        lf.show_merge_revno(rev, merge_depth, revno,
 
297
                                            rev_tag_dict.get(rev_id))
 
298
                    else:
 
299
                        lf.show_merge_revno(rev, merge_depth, revno)
 
300
        if limit:
 
301
            log_count += 1
 
302
            if log_count >= limit:
 
303
                break
 
304
 
 
305
 
 
306
def _get_mainline_revs(branch, start_revision, end_revision):
 
307
    """Get the mainline revisions from the branch.
 
308
    
 
309
    Generates the list of mainline revisions for the branch.
 
310
    
 
311
    :param  branch: The branch containing the revisions. 
 
312
 
 
313
    :param  start_revision: The first revision to be logged.
 
314
            For backwards compatibility this may be a mainline integer revno,
 
315
            but for merge revision support a RevisionInfo is expected.
 
316
 
 
317
    :param  end_revision: The last revision to be logged.
 
318
            For backwards compatibility this may be a mainline integer revno,
 
319
            but for merge revision support a RevisionInfo is expected.
 
320
 
 
321
    :return: A (mainline_revs, rev_nos, start_rev_id, end_rev_id) tuple.
 
322
    """
 
323
    which_revs = _enumerate_history(branch)
 
324
    if not which_revs:
 
325
        return None, None, None, None
 
326
 
 
327
    # For mainline generation, map start_revision and end_revision to 
 
328
    # mainline revnos. If the revision is not on the mainline choose the 
 
329
    # appropriate extreme of the mainline instead - the extra will be 
 
330
    # filtered later.
 
331
    # Also map the revisions to rev_ids, to be used in the later filtering
 
332
    # stage.
 
333
    start_rev_id = None 
 
334
    if start_revision is None:
 
335
        start_revno = 1
 
336
    else:
 
337
        if isinstance(start_revision,RevisionInfo):
 
338
            start_rev_id = start_revision.rev_id
 
339
            start_revno = start_revision.revno or 1
 
340
        else:
 
341
            branch.check_real_revno(start_revision)
 
342
            start_revno = start_revision
 
343
    
 
344
    end_rev_id = None
 
345
    if end_revision is None:
 
346
        end_revno = len(which_revs)
 
347
    else:
 
348
        if isinstance(end_revision,RevisionInfo):
 
349
            end_rev_id = end_revision.rev_id
 
350
            end_revno = end_revision.revno or len(which_revs)
 
351
        else:
 
352
            branch.check_real_revno(end_revision)
 
353
            end_revno = end_revision
 
354
 
 
355
    if start_revno > end_revno:
 
356
        from bzrlib.errors import BzrCommandError
 
357
        raise BzrCommandError("Start revision must be older than "
 
358
                              "the end revision.")
 
359
 
 
360
    # list indexes are 0-based; revisions are 1-based
 
361
    cut_revs = which_revs[(start_revno-1):(end_revno)]
 
362
    if not cut_revs:
 
363
        return None, None, None, None
 
364
 
 
365
    # convert the revision history to a dictionary:
 
366
    rev_nos = dict((k, v) for v, k in cut_revs)
 
367
 
 
368
    # override the mainline to look like the revision history.
 
369
    mainline_revs = [revision_id for index, revision_id in cut_revs]
 
370
    if cut_revs[0][0] == 1:
 
371
        mainline_revs.insert(0, None)
 
372
    else:
 
373
        mainline_revs.insert(0, which_revs[start_revno-2][1])
 
374
    return mainline_revs, rev_nos, start_rev_id, end_rev_id
 
375
 
 
376
 
 
377
def _filter_revision_range(view_revisions, start_rev_id, end_rev_id):
 
378
    """Filter view_revisions based on revision ranges.
 
379
 
 
380
    :param view_revisions: A list of (revision_id, dotted_revno, merge_depth) 
 
381
            tuples to be filtered.
 
382
 
 
383
    :param start_rev_id: If not NONE specifies the first revision to be logged.
 
384
            If NONE then all revisions up to the end_rev_id are logged.
 
385
 
 
386
    :param end_rev_id: If not NONE specifies the last revision to be logged.
 
387
            If NONE then all revisions up to the end of the log are logged.
 
388
 
 
389
    :return: The filtered view_revisions.
 
390
    """
 
391
    if start_rev_id or end_rev_id: 
 
392
        revision_ids = [r for r, n, d in view_revisions]
 
393
        if start_rev_id:
 
394
            start_index = revision_ids.index(start_rev_id)
 
395
        else:
 
396
            start_index = 0
 
397
        if start_rev_id == end_rev_id:
 
398
            end_index = start_index
 
399
        else:
 
400
            if end_rev_id:
 
401
                end_index = revision_ids.index(end_rev_id)
 
402
            else:
 
403
                end_index = len(view_revisions) - 1
 
404
        # To include the revisions merged into the last revision, 
 
405
        # extend end_rev_id down to, but not including, the next rev
 
406
        # with the same or lesser merge_depth
 
407
        end_merge_depth = view_revisions[end_index][2]
 
408
        try:
 
409
            for index in xrange(end_index+1, len(view_revisions)+1):
 
410
                if view_revisions[index][2] <= end_merge_depth:
 
411
                    end_index = index - 1
 
412
                    break
 
413
        except IndexError:
 
414
            # if the search falls off the end then log to the end as well
 
415
            end_index = len(view_revisions) - 1
 
416
        view_revisions = view_revisions[start_index:end_index+1]
 
417
    return view_revisions
 
418
 
 
419
 
 
420
def _filter_revisions_touching_file_id(branch, file_id, mainline_revisions,
 
421
                                       view_revs_iter):
292
422
    """Return the list of revision ids which touch a given file id.
293
423
 
 
424
    The function filters view_revisions and returns a subset.
294
425
    This includes the revisions which directly change the file id,
295
426
    and the revisions which merge these changes. So if the
296
427
    revision graph is::
398
529
    return result
399
530
 
400
531
 
 
532
class LogRevision(object):
 
533
    """A revision to be logged (by LogFormatter.log_revision).
 
534
 
 
535
    A simple wrapper for the attributes of a revision to be logged.
 
536
    The attributes may or may not be populated, as determined by the 
 
537
    logging options and the log formatter capabilities.
 
538
    """
 
539
 
 
540
    def __init__(self, rev=None, revno=None, merge_depth=0, delta=None,
 
541
                 tags=None):
 
542
        self.rev = rev
 
543
        self.revno = revno
 
544
        self.merge_depth = merge_depth
 
545
        self.delta = delta
 
546
        self.tags = tags
 
547
 
 
548
 
401
549
class LogFormatter(object):
402
 
    """Abstract class to display log messages."""
 
550
    """Abstract class to display log messages.
 
551
 
 
552
    At a minimum, a derived class must implement the log_revision method.
 
553
 
 
554
    If the LogFormatter needs to be informed of the beginning or end of
 
555
    a log it should implement the begin_log and/or end_log hook methods.
 
556
 
 
557
    A LogFormatter should define the following supports_XXX flags 
 
558
    to indicate which LogRevision attributes it supports:
 
559
 
 
560
    - supports_delta must be True if this log formatter supports delta.
 
561
        Otherwise the delta attribute may not be populated.
 
562
    - supports_merge_revisions must be True if this log formatter supports 
 
563
        merge revisions.  If not, only revisions mainline revisions (those 
 
564
        with merge_depth == 0) will be passed to the formatter.
 
565
    - supports_tags must be True if this log formatter supports tags.
 
566
        Otherwise the tags attribute may not be populated.
 
567
    """
403
568
 
404
569
    def __init__(self, to_file, show_ids=False, show_timezone='original'):
405
570
        self.to_file = to_file
406
571
        self.show_ids = show_ids
407
572
        self.show_timezone = show_timezone
408
573
 
 
574
# TODO: uncomment this block after show() has been removed.
 
575
# Until then defining log_revision would prevent _show_log calling show() 
 
576
# in legacy formatters.
 
577
#    def log_revision(self, revision):
 
578
#        """Log a revision.
 
579
#
 
580
#        :param  revision:   The LogRevision to be logged.
 
581
#        """
 
582
#        raise NotImplementedError('not implemented in abstract base')
 
583
 
 
584
    @deprecated_method(zero_seventeen)
409
585
    def show(self, revno, rev, delta):
410
586
        raise NotImplementedError('not implemented in abstract base')
411
587
 
415
591
 
416
592
class LongLogFormatter(LogFormatter):
417
593
 
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
 
594
    supports_merge_revisions = True
 
595
    supports_delta = True
 
596
    supports_tags = True
422
597
 
 
598
    @deprecated_method(zero_seventeen)
423
599
    def show(self, revno, rev, delta, tags=None):
424
 
        return self._show_helper(revno=revno, rev=rev, delta=delta, tags=tags)
 
600
        lr = LogRevision(rev, revno, 0, delta, tags)
 
601
        return self.log_revision(lr)
425
602
 
426
603
    @deprecated_method(zero_eleven)
427
604
    def show_merge(self, rev, merge_depth):
428
 
        return self._show_helper(rev=rev, indent='    '*merge_depth,
429
 
                                 merged=True, delta=None)
 
605
        lr = LogRevision(rev, merge_depth=merge_depth)
 
606
        return self.log_revision(lr)
430
607
 
 
608
    @deprecated_method(zero_seventeen)
431
609
    def show_merge_revno(self, rev, merge_depth, revno, tags=None):
432
610
        """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)
 
611
        lr = LogRevision(rev, revno, merge_depth, tags=tags)
 
612
        return self.log_revision(lr)
435
613
 
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."""
 
614
    def log_revision(self, revision):
 
615
        """Log a revision, either merged or not."""
439
616
        from bzrlib.osutils import format_date
 
617
        indent = '    '*revision.merge_depth
440
618
        to_file = self.to_file
441
619
        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
 
620
        if revision.revno is not None:
 
621
            print >>to_file,  indent+'revno:', revision.revno
 
622
        if revision.tags:
 
623
            print >>to_file, indent+'tags: %s' % (', '.join(revision.tags))
450
624
        if self.show_ids:
451
 
            for parent_id in rev.parent_ids:
 
625
            print >>to_file, indent+'revision-id:', revision.rev.revision_id
 
626
            for parent_id in revision.rev.parent_ids:
452
627
                print >>to_file, indent+'parent:', parent_id
453
 
        print >>to_file,  indent+'committer:', rev.committer
 
628
        print >>to_file, indent+'committer:', revision.rev.committer
454
629
 
455
630
        try:
456
631
            print >>to_file, indent+'branch nick: %s' % \
457
 
                rev.properties['branch-nick']
 
632
                revision.rev.properties['branch-nick']
458
633
        except KeyError:
459
634
            pass
460
 
        date_str = format_date(rev.timestamp,
461
 
                               rev.timezone or 0,
 
635
        date_str = format_date(revision.rev.timestamp,
 
636
                               revision.rev.timezone or 0,
462
637
                               self.show_timezone)
463
638
        print >>to_file,  indent+'timestamp: %s' % date_str
464
639
 
465
640
        print >>to_file,  indent+'message:'
466
 
        if not rev.message:
 
641
        if not revision.rev.message:
467
642
            print >>to_file,  indent+'  (no message)'
468
643
        else:
469
 
            message = rev.message.rstrip('\r\n')
 
644
            message = revision.rev.message.rstrip('\r\n')
470
645
            for l in message.split('\n'):
471
646
                print >>to_file,  indent+'  ' + l
472
 
        if delta is not None:
473
 
            delta.show(to_file, self.show_ids)
 
647
        if revision.delta is not None:
 
648
            revision.delta.show(to_file, self.show_ids, indent=indent)
474
649
 
475
650
 
476
651
class ShortLogFormatter(LogFormatter):
 
652
 
 
653
    supports_delta = True
 
654
 
 
655
    @deprecated_method(zero_seventeen)
477
656
    def show(self, revno, rev, delta):
 
657
        lr = LogRevision(rev, revno, 0, delta)
 
658
        return self.log_revision(lr)
 
659
 
 
660
    def log_revision(self, revision):
478
661
        from bzrlib.osutils import format_date
479
662
 
480
663
        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,
 
664
        date_str = format_date(revision.rev.timestamp,
 
665
                               revision.rev.timezone or 0,
 
666
                               self.show_timezone)
 
667
        is_merge = ''
 
668
        if len(revision.rev.parent_ids) > 1:
 
669
            is_merge = ' [merge]'
 
670
        print >>to_file, "%5s %s\t%s%s" % (revision.revno,
 
671
                self.short_committer(revision.rev),
 
672
                format_date(revision.rev.timestamp,
 
673
                            revision.rev.timezone or 0,
485
674
                            self.show_timezone, date_fmt="%Y-%m-%d",
486
 
                           show_offset=False))
 
675
                            show_offset=False),
 
676
                is_merge)
487
677
        if self.show_ids:
488
 
            print >>to_file,  '      revision-id:', rev.revision_id
489
 
        if not rev.message:
 
678
            print >>to_file,  '      revision-id:', revision.rev.revision_id
 
679
        if not revision.rev.message:
490
680
            print >>to_file,  '      (no message)'
491
681
        else:
492
 
            message = rev.message.rstrip('\r\n')
 
682
            message = revision.rev.message.rstrip('\r\n')
493
683
            for l in message.split('\n'):
494
684
                print >>to_file,  '      ' + l
495
685
 
496
686
        # TODO: Why not show the modified files in a shorter form as
497
687
        # well? rewrap them single lines of appropriate length
498
 
        if delta is not None:
499
 
            delta.show(to_file, self.show_ids)
 
688
        if revision.delta is not None:
 
689
            revision.delta.show(to_file, self.show_ids)
500
690
        print >>to_file, ''
501
691
 
502
692
 
503
693
class LineLogFormatter(LogFormatter):
 
694
 
 
695
    def __init__(self, *args, **kwargs):
 
696
        from bzrlib.osutils import terminal_width
 
697
        super(LineLogFormatter, self).__init__(*args, **kwargs)
 
698
        self._max_chars = terminal_width() - 1
 
699
 
504
700
    def truncate(self, str, max_len):
505
701
        if len(str) <= max_len:
506
702
            return str
518
714
        else:
519
715
            return rev.message
520
716
 
 
717
    @deprecated_method(zero_seventeen)
521
718
    def show(self, revno, rev, delta):
522
719
        from bzrlib.osutils import terminal_width
523
720
        print >> self.to_file, self.log_string(revno, rev, terminal_width()-1)
524
721
 
 
722
    def log_revision(self, revision):
 
723
        print >>self.to_file, self.log_string(revision.revno, revision.rev,
 
724
                                              self._max_chars)
 
725
 
525
726
    def log_string(self, revno, rev, max_chars):
526
727
        """Format log info into one string. Truncate tail of string
527
728
        :param  revno:      revision number (int) or None.
593
794
    lf = LongLogFormatter(to_file=to_file, show_timezone=show_timezone)
594
795
    lf.show(revno, rev, delta)
595
796
 
 
797
 
596
798
def show_changed_revisions(branch, old_rh, new_rh, to_file=None, log_format='long'):
597
799
    """Show the change in revision history comparing the old revision history to the new one.
598
800
 
633
835
        to_file.write('\nRemoved Revisions:\n')
634
836
        for i in range(base_idx, len(old_rh)):
635
837
            rev = branch.repository.get_revision(old_rh[i])
636
 
            lf.show(i+1, rev, None)
 
838
            lr = LogRevision(rev, i+1, 0, None)
 
839
            lf.log_revision(lr)
637
840
        to_file.write('*'*60)
638
841
        to_file.write('\n\n')
639
842
    if base_idx < len(new_rh):