~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/log.py

  • Committer: Martin Pool
  • Date: 2005-08-19 21:34:32 UTC
  • Revision ID: mbp@sourcefrog.net-20050819213432-4fa923a97c45d845
- add schema and example for new inventory form

Show diffs side-by-side

added added

removed removed

Lines of Context:
50
50
"""
51
51
 
52
52
 
53
 
# TODO: option to show delta summaries for merged-in revisions
54
 
 
55
 
import bzrlib.errors as errors
56
53
from bzrlib.tree import EmptyTree
57
54
from bzrlib.delta import compare_trees
58
55
from bzrlib.trace import mutter
59
 
import re
 
56
from bzrlib.errors import InvalidRevisionNumber
60
57
 
61
58
 
62
59
def find_touching_revisions(branch, file_id):
113
110
    return rh
114
111
 
115
112
 
116
 
def _get_revision_delta(branch, revno):
117
 
    """Return the delta for a mainline revision.
118
 
    
119
 
    This is used to show summaries in verbose logs, and also for finding 
120
 
    revisions which touch a given file."""
121
 
    # XXX: What are we supposed to do when showing a summary for something 
122
 
    # other than a mainline revision.  The delta to it's first parent, or
123
 
    # (more useful) the delta to a nominated other revision.
124
 
    return branch.get_revision_delta(revno)
125
 
 
126
 
 
127
113
def show_log(branch,
128
114
             lf,
129
115
             specific_fileid=None,
154
140
    end_revision
155
141
        If not None, only show revisions <= end_revision
156
142
    """
157
 
    branch.lock_read()
158
 
    try:
159
 
        _show_log(branch, lf, specific_fileid, verbose, direction,
160
 
                  start_revision, end_revision, search)
161
 
    finally:
162
 
        branch.unlock()
163
 
    
164
 
def _show_log(branch,
165
 
             lf,
166
 
             specific_fileid=None,
167
 
             verbose=False,
168
 
             direction='reverse',
169
 
             start_revision=None,
170
 
             end_revision=None,
171
 
             search=None):
172
 
    """Worker function for show_log - see show_log."""
173
143
    from bzrlib.osutils import format_date
174
144
    from bzrlib.errors import BzrCheckError
175
145
    from bzrlib.textui import show_status
180
150
        warn("not a LogFormatter instance: %r" % lf)
181
151
 
182
152
    if specific_fileid:
183
 
        mutter('get log for file_id %r', specific_fileid)
 
153
        mutter('get log for file_id %r' % specific_fileid)
184
154
 
185
155
    if search is not None:
186
156
        import re
192
162
    
193
163
    if start_revision is None:
194
164
        start_revision = 1
195
 
    else:
196
 
        branch.check_real_revno(start_revision)
 
165
    elif start_revision < 1 or start_revision >= len(which_revs):
 
166
        raise InvalidRevisionNumber(start_revision)
197
167
    
198
168
    if end_revision is None:
199
169
        end_revision = len(which_revs)
200
 
    else:
201
 
        branch.check_real_revno(end_revision)
 
170
    elif end_revision < 1 or end_revision >= len(which_revs):
 
171
        raise InvalidRevisionNumber(end_revision)
202
172
 
203
173
    # list indexes are 0-based; revisions are 1-based
204
174
    cut_revs = which_revs[(start_revision-1):(end_revision)]
210
180
    else:
211
181
        raise ValueError('invalid direction %r' % direction)
212
182
 
213
 
    revision_history = branch.revision_history()
214
183
    for revno, rev_id in cut_revs:
215
184
        if verbose or specific_fileid:
216
 
            delta = _get_revision_delta(branch, revno)
 
185
            delta = branch.get_revision_delta(revno)
217
186
            
218
187
        if specific_fileid:
219
188
            if not delta.touches_file_id(specific_fileid):
230
199
                continue
231
200
 
232
201
        lf.show(revno, rev, delta)
233
 
        if hasattr(lf, 'show_merge'):
234
 
            if revno == 1:
235
 
                excludes = set()
236
 
            else:
237
 
                # revno is 1 based, so -2 to get back 1 less.
238
 
                excludes = set(branch.get_ancestry(revision_history[revno - 2]))
239
 
            pending = list(rev.parent_ids)
240
 
            while pending:
241
 
                rev_id = pending.pop()
242
 
                if rev_id in excludes:
243
 
                    continue
244
 
                # prevent showing merged revs twice if they multi-path.
245
 
                excludes.add(rev_id)
246
 
                try:
247
 
                    rev = branch.get_revision(rev_id)
248
 
                except errors.NoSuchRevision:
249
 
                    continue
250
 
                pending.extend(rev.parent_ids)
251
 
                lf.show_merge(rev)
 
202
 
252
203
 
253
204
 
254
205
def deltas_for_log_dummy(branch, which_revs):
343
294
 
344
295
    def show(self, revno, rev, delta):
345
296
        raise NotImplementedError('not implemented in abstract base')
346
 
 
347
 
    def short_committer(self, rev):
348
 
        return re.sub('<.*@.*>', '', rev.committer).strip(' ')
349
 
    
350
 
    
 
297
        
 
298
 
 
299
 
 
300
 
 
301
 
 
302
 
351
303
class LongLogFormatter(LogFormatter):
352
304
    def show(self, revno, rev, delta):
353
 
        return self._show_helper(revno=revno, rev=rev, delta=delta)
354
 
 
355
 
    def show_merge(self, rev):
356
 
        return self._show_helper(rev=rev, indent='    ', merged=True, delta=None)
357
 
 
358
 
    def _show_helper(self, rev=None, revno=None, indent='', merged=False, delta=None):
359
 
        """Show a revision, either merged or not."""
360
 
        from bzrlib.osutils import format_date
 
305
        from osutils import format_date
 
306
 
361
307
        to_file = self.to_file
362
 
        print >>to_file,  indent+'-' * 60
363
 
        if revno is not None:
364
 
            print >>to_file,  'revno:', revno
365
 
        if merged:
366
 
            print >>to_file,  indent+'merged:', rev.revision_id
367
 
        elif self.show_ids:
368
 
            print >>to_file,  indent+'revision-id:', rev.revision_id
 
308
 
 
309
        print >>to_file,  '-' * 60
 
310
        print >>to_file,  'revno:', revno
369
311
        if self.show_ids:
370
 
            for parent_id in rev.parent_ids:
371
 
                print >>to_file, indent+'parent:', parent_id
372
 
        print >>to_file,  indent+'committer:', rev.committer
373
 
        try:
374
 
            print >>to_file, indent+'branch nick: %s' % \
375
 
                rev.properties['branch-nick']
376
 
        except KeyError:
377
 
            pass
 
312
            print >>to_file,  'revision-id:', rev.revision_id
 
313
        print >>to_file,  'committer:', rev.committer
 
314
 
378
315
        date_str = format_date(rev.timestamp,
379
316
                               rev.timezone or 0,
380
317
                               self.show_timezone)
381
 
        print >>to_file,  indent+'timestamp: %s' % date_str
 
318
        print >>to_file,  'timestamp: %s' % date_str
382
319
 
383
 
        print >>to_file,  indent+'message:'
 
320
        print >>to_file,  'message:'
384
321
        if not rev.message:
385
 
            print >>to_file,  indent+'  (no message)'
 
322
            print >>to_file,  '  (no message)'
386
323
        else:
387
 
            message = rev.message.rstrip('\r\n')
388
 
            for l in message.split('\n'):
389
 
                print >>to_file,  indent+'  ' + l
 
324
            for l in rev.message.split('\n'):
 
325
                print >>to_file,  '  ' + l
 
326
 
390
327
        if delta != None:
391
328
            delta.show(to_file, self.show_ids)
392
329
 
393
330
 
 
331
 
394
332
class ShortLogFormatter(LogFormatter):
395
333
    def show(self, revno, rev, delta):
396
334
        from bzrlib.osutils import format_date
397
335
 
398
336
        to_file = self.to_file
399
 
        date_str = format_date(rev.timestamp, rev.timezone or 0,
400
 
                            self.show_timezone)
401
 
        print >>to_file, "%5d %s\t%s" % (revno, self.short_committer(rev),
 
337
 
 
338
        print >>to_file, "%5d %s\t%s" % (revno, rev.committer,
402
339
                format_date(rev.timestamp, rev.timezone or 0,
403
 
                            self.show_timezone, date_fmt="%Y-%m-%d",
404
 
                           show_offset=False))
 
340
                            self.show_timezone))
405
341
        if self.show_ids:
406
342
            print >>to_file,  '      revision-id:', rev.revision_id
407
343
        if not rev.message:
408
344
            print >>to_file,  '      (no message)'
409
345
        else:
410
 
            message = rev.message.rstrip('\r\n')
411
 
            for l in message.split('\n'):
 
346
            for l in rev.message.split('\n'):
412
347
                print >>to_file,  '      ' + l
413
348
 
414
349
        # TODO: Why not show the modified files in a shorter form as
415
350
        # well? rewrap them single lines of appropriate length
416
351
        if delta != None:
417
352
            delta.show(to_file, self.show_ids)
418
 
        print >>to_file, ''
419
 
 
420
 
class LineLogFormatter(LogFormatter):
421
 
    def truncate(self, str, max_len):
422
 
        if len(str) <= max_len:
423
 
            return str
424
 
        return str[:max_len-3]+'...'
425
 
 
426
 
    def date_string(self, rev):
427
 
        from bzrlib.osutils import format_date
428
 
        return format_date(rev.timestamp, rev.timezone or 0, 
429
 
                           self.show_timezone, date_fmt="%Y-%m-%d",
430
 
                           show_offset=False)
431
 
 
432
 
    def message(self, rev):
433
 
        if not rev.message:
434
 
            return '(no message)'
435
 
        else:
436
 
            return rev.message
437
 
 
438
 
    def show(self, revno, rev, delta):
439
 
        print >> self.to_file, self.log_string(rev, 79) 
440
 
 
441
 
    def log_string(self, rev, max_chars):
442
 
        out = [self.truncate(self.short_committer(rev), 20)]
443
 
        out.append(self.date_string(rev))
444
 
        out.append(self.message(rev).replace('\n', ' '))
445
 
        return self.truncate(" ".join(out).rstrip('\n'), max_chars)
446
 
 
447
 
def line_log(rev, max_chars):
448
 
    lf = LineLogFormatter(None)
449
 
    return lf.log_string(rev, max_chars)
 
353
        print
 
354
 
 
355
 
450
356
 
451
357
FORMATTERS = {'long': LongLogFormatter,
452
358
              'short': ShortLogFormatter,
453
 
              'line': LineLogFormatter,
454
359
              }
455
360
 
456
361
 
457
362
def log_formatter(name, *args, **kwargs):
458
 
    """Construct a formatter from arguments.
459
 
 
460
 
    name -- Name of the formatter to construct; currently 'long', 'short' and
461
 
        'line' are supported.
462
 
    """
463
363
    from bzrlib.errors import BzrCommandError
 
364
    
464
365
    try:
465
366
        return FORMATTERS[name](*args, **kwargs)
466
367
    except IndexError:
470
371
    # deprecated; for compatability
471
372
    lf = LongLogFormatter(to_file=to_file, show_timezone=show_timezone)
472
373
    lf.show(revno, rev, delta)
473
 
 
474
 
def show_changed_revisions(branch, old_rh, new_rh, to_file=None, log_format='long'):
475
 
    """Show the change in revision history comparing the old revision history to the new one.
476
 
 
477
 
    :param branch: The branch where the revisions exist
478
 
    :param old_rh: The old revision history
479
 
    :param new_rh: The new revision history
480
 
    :param to_file: A file to write the results to. If None, stdout will be used
481
 
    """
482
 
    if to_file is None:
483
 
        import sys
484
 
        import codecs
485
 
        import bzrlib
486
 
        to_file = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
487
 
    lf = log_formatter(log_format,
488
 
                       show_ids=False,
489
 
                       to_file=to_file,
490
 
                       show_timezone='original')
491
 
 
492
 
    # This is the first index which is different between
493
 
    # old and new
494
 
    base_idx = None
495
 
    for i in xrange(max(len(new_rh),
496
 
                        len(old_rh))):
497
 
        if (len(new_rh) <= i
498
 
            or len(old_rh) <= i
499
 
            or new_rh[i] != old_rh[i]):
500
 
            base_idx = i
501
 
            break
502
 
 
503
 
    if base_idx is None:
504
 
        to_file.write('Nothing seems to have changed\n')
505
 
        return
506
 
    ## TODO: It might be nice to do something like show_log
507
 
    ##       and show the merged entries. But since this is the
508
 
    ##       removed revisions, it shouldn't be as important
509
 
    if base_idx < len(old_rh):
510
 
        to_file.write('*'*60)
511
 
        to_file.write('\nRemoved Revisions:\n')
512
 
        for i in range(base_idx, len(old_rh)):
513
 
            rev = branch.get_revision(old_rh[i])
514
 
            lf.show(i+1, rev, None)
515
 
        to_file.write('*'*60)
516
 
        to_file.write('\n\n')
517
 
    if base_idx < len(new_rh):
518
 
        to_file.write('Added Revisions:\n')
519
 
        show_log(branch,
520
 
                 lf,
521
 
                 None,
522
 
                 verbose=True,
523
 
                 direction='forward',
524
 
                 start_revision=base_idx+1,
525
 
                 end_revision=len(new_rh),
526
 
                 search=None)
527