~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: 2006-02-21 17:41:02 UTC
  • mfrom: (1185.50.85 bzr-jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060221174102-aa6bd4464296c614
Mac OSX raises EPERM when you try to unlink a directory

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
 
53
55
import bzrlib.errors as errors
54
56
from bzrlib.tree import EmptyTree
55
57
from bzrlib.delta import compare_trees
56
58
from bzrlib.trace import mutter
 
59
import re
57
60
 
58
61
 
59
62
def find_touching_revisions(branch, file_id):
71
74
    last_path = None
72
75
    revno = 1
73
76
    for revision_id in branch.revision_history():
74
 
        this_inv = branch.get_revision_inventory(revision_id)
 
77
        this_inv = branch.repository.get_revision_inventory(revision_id)
75
78
        if file_id in this_inv:
76
79
            this_ie = this_inv[file_id]
77
80
            this_path = this_inv.id2path(file_id)
177
180
        warn("not a LogFormatter instance: %r" % lf)
178
181
 
179
182
    if specific_fileid:
180
 
        mutter('get log for file_id %r' % specific_fileid)
 
183
        mutter('get log for file_id %r', specific_fileid)
181
184
 
182
185
    if search is not None:
183
186
        import re
220
223
            # although we calculated it, throw it away without display
221
224
            delta = None
222
225
 
223
 
        rev = branch.get_revision(rev_id)
 
226
        rev = branch.repository.get_revision(rev_id)
224
227
 
225
228
        if searchRE:
226
229
            if not searchRE.search(rev.message):
227
230
                continue
228
231
 
229
232
        lf.show(revno, rev, delta)
230
 
        if revno == 1:
231
 
            excludes = set()
232
 
        else:
233
 
            # revno is 1 based, so -2 to get back 1 less.
234
 
            excludes = set(branch.get_ancestry(revision_history[revno - 2]))
235
 
        pending = list(rev.parent_ids)
236
 
        while pending:
237
 
            rev_id = pending.pop()
238
 
            if rev_id in excludes:
239
 
                continue
240
 
            # prevent showing merged revs twice if they multi-path.
241
 
            excludes.add(rev_id)
242
 
            try:
243
 
                rev = branch.get_revision(rev_id)
244
 
            except errors.NoSuchRevision:
245
 
                continue
246
 
            pending.extend(rev.parent_ids)
247
 
            lf.show_merge(rev)
 
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
                repository = branch.repository
 
239
                excludes = repository.get_ancestry(revision_history[revno - 2])
 
240
                excludes = set(excludes)
 
241
            pending = list(rev.parent_ids)
 
242
            while pending:
 
243
                rev_id = pending.pop()
 
244
                if rev_id in excludes:
 
245
                    continue
 
246
                # prevent showing merged revs twice if they multi-path.
 
247
                excludes.add(rev_id)
 
248
                try:
 
249
                    rev = branch.repository.get_revision(rev_id)
 
250
                except errors.NoSuchRevision:
 
251
                    continue
 
252
                pending.extend(rev.parent_ids)
 
253
                lf.show_merge(rev)
248
254
 
249
255
 
250
256
def deltas_for_log_dummy(branch, which_revs):
340
346
    def show(self, revno, rev, delta):
341
347
        raise NotImplementedError('not implemented in abstract base')
342
348
 
343
 
    def show_merge(self, rev):
344
 
        pass
345
 
 
 
349
    def short_committer(self, rev):
 
350
        return re.sub('<.*@.*>', '', rev.committer).strip(' ')
 
351
    
346
352
    
347
353
class LongLogFormatter(LogFormatter):
348
354
    def show(self, revno, rev, delta):
349
 
        from osutils import format_date
350
 
 
351
 
        to_file = self.to_file
352
 
 
353
 
        print >>to_file,  '-' * 60
354
 
        print >>to_file,  'revno:', revno
355
 
        if self.show_ids:
356
 
            print >>to_file,  'revision-id:', rev.revision_id
357
 
 
358
 
            for parent_id in rev.parent_ids:
359
 
                print >>to_file, 'parent:', parent_id
360
 
            
361
 
        print >>to_file,  'committer:', rev.committer
362
 
 
363
 
        date_str = format_date(rev.timestamp,
364
 
                               rev.timezone or 0,
365
 
                               self.show_timezone)
366
 
        print >>to_file,  'timestamp: %s' % date_str
367
 
 
368
 
        print >>to_file,  'message:'
369
 
        if not rev.message:
370
 
            print >>to_file,  '  (no message)'
371
 
        else:
372
 
            for l in rev.message.split('\n'):
373
 
                print >>to_file,  '  ' + l
374
 
 
375
 
        if delta != None:
376
 
            delta.show(to_file, self.show_ids)
 
355
        return self._show_helper(revno=revno, rev=rev, delta=delta)
377
356
 
378
357
    def show_merge(self, rev):
379
 
        from osutils import format_date
 
358
        return self._show_helper(rev=rev, indent='    ', merged=True, delta=None)
380
359
 
 
360
    def _show_helper(self, rev=None, revno=None, indent='', merged=False, delta=None):
 
361
        """Show a revision, either merged or not."""
 
362
        from bzrlib.osutils import format_date
381
363
        to_file = self.to_file
382
 
 
383
 
        indent = '    '
384
 
 
385
364
        print >>to_file,  indent+'-' * 60
386
 
        print >>to_file,  indent+'merged:', rev.revision_id
 
365
        if revno is not None:
 
366
            print >>to_file,  'revno:', revno
 
367
        if merged:
 
368
            print >>to_file,  indent+'merged:', rev.revision_id
 
369
        elif self.show_ids:
 
370
            print >>to_file,  indent+'revision-id:', rev.revision_id
387
371
        if self.show_ids:
388
372
            for parent_id in rev.parent_ids:
389
373
                print >>to_file, indent+'parent:', parent_id
390
 
            
391
374
        print >>to_file,  indent+'committer:', rev.committer
392
 
 
 
375
        try:
 
376
            print >>to_file, indent+'branch nick: %s' % \
 
377
                rev.properties['branch-nick']
 
378
        except KeyError:
 
379
            pass
393
380
        date_str = format_date(rev.timestamp,
394
381
                               rev.timezone or 0,
395
382
                               self.show_timezone)
399
386
        if not rev.message:
400
387
            print >>to_file,  indent+'  (no message)'
401
388
        else:
402
 
            for l in rev.message.split('\n'):
 
389
            message = rev.message.rstrip('\r\n')
 
390
            for l in message.split('\n'):
403
391
                print >>to_file,  indent+'  ' + l
 
392
        if delta != None:
 
393
            delta.show(to_file, self.show_ids)
404
394
 
405
395
 
406
396
class ShortLogFormatter(LogFormatter):
408
398
        from bzrlib.osutils import format_date
409
399
 
410
400
        to_file = self.to_file
411
 
 
412
 
        print >>to_file, "%5d %s\t%s" % (revno, rev.committer,
 
401
        date_str = format_date(rev.timestamp, rev.timezone or 0,
 
402
                            self.show_timezone)
 
403
        print >>to_file, "%5d %s\t%s" % (revno, self.short_committer(rev),
413
404
                format_date(rev.timestamp, rev.timezone or 0,
414
 
                            self.show_timezone))
 
405
                            self.show_timezone, date_fmt="%Y-%m-%d",
 
406
                           show_offset=False))
415
407
        if self.show_ids:
416
408
            print >>to_file,  '      revision-id:', rev.revision_id
417
409
        if not rev.message:
418
410
            print >>to_file,  '      (no message)'
419
411
        else:
420
 
            for l in rev.message.split('\n'):
 
412
            message = rev.message.rstrip('\r\n')
 
413
            for l in message.split('\n'):
421
414
                print >>to_file,  '      ' + l
422
415
 
423
416
        # TODO: Why not show the modified files in a shorter form as
424
417
        # well? rewrap them single lines of appropriate length
425
418
        if delta != None:
426
419
            delta.show(to_file, self.show_ids)
427
 
        print
428
 
 
429
 
 
430
 
 
431
 
FORMATTERS = {'long': LongLogFormatter,
 
420
        print >>to_file, ''
 
421
 
 
422
class LineLogFormatter(LogFormatter):
 
423
    def truncate(self, str, max_len):
 
424
        if len(str) <= max_len:
 
425
            return str
 
426
        return str[:max_len-3]+'...'
 
427
 
 
428
    def date_string(self, rev):
 
429
        from bzrlib.osutils import format_date
 
430
        return format_date(rev.timestamp, rev.timezone or 0, 
 
431
                           self.show_timezone, date_fmt="%Y-%m-%d",
 
432
                           show_offset=False)
 
433
 
 
434
    def message(self, rev):
 
435
        if not rev.message:
 
436
            return '(no message)'
 
437
        else:
 
438
            return rev.message
 
439
 
 
440
    def show(self, revno, rev, delta):
 
441
        print >> self.to_file, self.log_string(rev, 79) 
 
442
 
 
443
    def log_string(self, rev, max_chars):
 
444
        out = [self.truncate(self.short_committer(rev), 20)]
 
445
        out.append(self.date_string(rev))
 
446
        out.append(self.message(rev).replace('\n', ' '))
 
447
        return self.truncate(" ".join(out).rstrip('\n'), max_chars)
 
448
 
 
449
def line_log(rev, max_chars):
 
450
    lf = LineLogFormatter(None)
 
451
    return lf.log_string(rev, max_chars)
 
452
 
 
453
FORMATTERS = {
 
454
              'long': LongLogFormatter,
432
455
              'short': ShortLogFormatter,
 
456
              'line': LineLogFormatter,
433
457
              }
434
458
 
 
459
def register_formatter(name, formatter):
 
460
    FORMATTERS[name] = formatter
435
461
 
436
462
def log_formatter(name, *args, **kwargs):
437
463
    """Construct a formatter from arguments.
438
464
 
439
 
    name -- Name of the formatter to construct; currently 'long' and
440
 
        'short' are supported.
 
465
    name -- Name of the formatter to construct; currently 'long', 'short' and
 
466
        'line' are supported.
441
467
    """
442
468
    from bzrlib.errors import BzrCommandError
443
469
    try:
444
470
        return FORMATTERS[name](*args, **kwargs)
445
 
    except IndexError:
 
471
    except KeyError:
446
472
        raise BzrCommandError("unknown log formatter: %r" % name)
447
473
 
448
474
def show_one_log(revno, rev, delta, verbose, to_file, show_timezone):
449
475
    # deprecated; for compatability
450
476
    lf = LongLogFormatter(to_file=to_file, show_timezone=show_timezone)
451
477
    lf.show(revno, rev, delta)
 
478
 
 
479
def show_changed_revisions(branch, old_rh, new_rh, to_file=None, log_format='long'):
 
480
    """Show the change in revision history comparing the old revision history to the new one.
 
481
 
 
482
    :param branch: The branch where the revisions exist
 
483
    :param old_rh: The old revision history
 
484
    :param new_rh: The new revision history
 
485
    :param to_file: A file to write the results to. If None, stdout will be used
 
486
    """
 
487
    if to_file is None:
 
488
        import sys
 
489
        import codecs
 
490
        import bzrlib
 
491
        to_file = codecs.getwriter(bzrlib.user_encoding)(sys.stdout, errors='replace')
 
492
    lf = log_formatter(log_format,
 
493
                       show_ids=False,
 
494
                       to_file=to_file,
 
495
                       show_timezone='original')
 
496
 
 
497
    # This is the first index which is different between
 
498
    # old and new
 
499
    base_idx = None
 
500
    for i in xrange(max(len(new_rh),
 
501
                        len(old_rh))):
 
502
        if (len(new_rh) <= i
 
503
            or len(old_rh) <= i
 
504
            or new_rh[i] != old_rh[i]):
 
505
            base_idx = i
 
506
            break
 
507
 
 
508
    if base_idx is None:
 
509
        to_file.write('Nothing seems to have changed\n')
 
510
        return
 
511
    ## TODO: It might be nice to do something like show_log
 
512
    ##       and show the merged entries. But since this is the
 
513
    ##       removed revisions, it shouldn't be as important
 
514
    if base_idx < len(old_rh):
 
515
        to_file.write('*'*60)
 
516
        to_file.write('\nRemoved Revisions:\n')
 
517
        for i in range(base_idx, len(old_rh)):
 
518
            rev = branch.repository.get_revision(old_rh[i])
 
519
            lf.show(i+1, rev, None)
 
520
        to_file.write('*'*60)
 
521
        to_file.write('\n\n')
 
522
    if base_idx < len(new_rh):
 
523
        to_file.write('Added Revisions:\n')
 
524
        show_log(branch,
 
525
                 lf,
 
526
                 None,
 
527
                 verbose=True,
 
528
                 direction='forward',
 
529
                 start_revision=base_idx+1,
 
530
                 end_revision=len(new_rh),
 
531
                 search=None)
 
532