~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/log.py

  • Committer: v.ladeuil+lp at free
  • Date: 2007-05-15 17:40:32 UTC
  • mto: (2485.8.44 bzr.connection.sharing)
  • mto: This revision was merged to the branch mainline in revision 2646.
  • Revision ID: v.ladeuil+lp@free.fr-20070515174032-qzdkangpv29l9e7g
Add a test that check that init connect only once. It fails.

* __init__.py:
(test_suite): Register the new test class.

* test_init.py: 
(InstrumentedTransport): A transport that can track connections.
(TransportHooks): Transport specific hooks.
(TestInit): Iniit command behavior tests.

* ftp.py:
(FtpTransport.__init__): Mark place that need fixing regarding
transport connection sharing

* builtins.py:
(cmd_init.run): Mark places that need fixing regarding transport
connection sharing.

Show diffs side-by-side

added added

removed removed

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