/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

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
54
54
from itertools import izip
55
55
import re
56
56
 
57
 
from bzrlib import symbol_versioning
 
57
from bzrlib import(
 
58
    registry,
 
59
    symbol_versioning,
 
60
    )
58
61
import bzrlib.errors as errors
59
62
from bzrlib.symbol_versioning import deprecated_method, zero_eleven
60
63
from bzrlib.trace import mutter
61
 
from bzrlib.tsort import merge_sort
 
64
from bzrlib.tsort import(
 
65
    merge_sort,
 
66
    topo_sort,
 
67
    )
62
68
 
63
69
 
64
70
def find_touching_revisions(branch, file_id):
218
224
        symbol_versioning.warn('LogFormatters should provide show_merge_revno '
219
225
            'instead of show_merge since bzr 0.11.',
220
226
            DeprecationWarning, stacklevel=3)
221
 
    view_revisions = list(get_view_revisions(mainline_revs, rev_nos, branch,
222
 
                          direction, include_merges=include_merges))
 
227
    view_revs_iter = get_view_revisions(mainline_revs, rev_nos, branch,
 
228
                          direction, include_merges=include_merges)
 
229
    if specific_fileid:
 
230
        view_revisions = _get_revisions_touching_file_id(branch,
 
231
                                                         specific_fileid,
 
232
                                                         mainline_revs,
 
233
                                                         view_revs_iter)
 
234
    else:
 
235
        view_revisions = list(view_revs_iter)
 
236
 
 
237
    use_tags = getattr(lf, 'supports_tags', False)
 
238
    if use_tags:
 
239
        rev_tag_dict = {}
 
240
        if branch.supports_tags():
 
241
            rev_tag_dict = branch.tags.get_reverse_tag_dict()
223
242
 
224
243
    def iter_revisions():
225
244
        # r = revision, n = revno, d = merge depth
230
249
        while revision_ids:
231
250
            cur_deltas = {}
232
251
            revisions = repository.get_revisions(revision_ids[:num])
233
 
            if verbose or specific_fileid:
 
252
            if verbose:
234
253
                delta_revisions = [r for r in revisions if
235
254
                                   r.revision_id in zeros]
236
255
                deltas = repository.get_deltas_for_revisions(delta_revisions)
238
257
                                        delta_revisions), deltas))
239
258
            for revision in revisions:
240
259
                # The delta value will be None unless
241
 
                # 1. verbose or specific_fileid is specified, and
 
260
                # 1. verbose is specified, and
242
261
                # 2. the revision is a mainline revision
243
262
                yield revision, cur_deltas.get(revision.revision_id)
244
263
            revision_ids  = revision_ids[num:]
245
 
            num = int(num * 1.5)
 
264
            num = min(int(num * 1.5), 200)
246
265
            
247
266
    # now we just print all the revisions
248
267
    for ((rev_id, revno, merge_depth), (rev, delta)) in \
253
272
                continue
254
273
 
255
274
        if merge_depth == 0:
256
 
            # a mainline revision.
257
 
                
258
 
            if specific_fileid:
259
 
                if not delta.touches_file_id(specific_fileid):
260
 
                    continue
261
 
    
262
 
            if not verbose:
263
 
                # although we calculated it, throw it away without display
264
 
                delta = None
265
 
 
266
 
            lf.show(revno, rev, delta)
 
275
            if use_tags:
 
276
                lf.show(revno, rev, delta, rev_tag_dict.get(rev_id))
 
277
            else:
 
278
                lf.show(revno, rev, delta)
267
279
        else:
268
280
            if show_merge_revno is None:
269
281
                lf.show_merge(rev, merge_depth)
270
282
            else:
271
 
                lf.show_merge_revno(rev, merge_depth, revno)
 
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):
 
292
    """Return the list of revision ids which touch a given file id.
 
293
 
 
294
    This includes the revisions which directly change the file id,
 
295
    and the revisions which merge these changes. So if the
 
296
    revision graph is::
 
297
        A
 
298
        |\
 
299
        B C
 
300
        |/
 
301
        D
 
302
 
 
303
    And 'C' changes a file, then both C and D will be returned.
 
304
 
 
305
    This will also can be restricted based on a subset of the mainline.
 
306
 
 
307
    :return: A list of (revision_id, dotted_revno, merge_depth) tuples.
 
308
    """
 
309
    # find all the revisions that change the specific file
 
310
    file_weave = branch.repository.weave_store.get_weave(file_id,
 
311
                branch.repository.get_transaction())
 
312
    weave_modifed_revisions = set(file_weave.versions())
 
313
    # build the ancestry of each revision in the graph
 
314
    # - only listing the ancestors that change the specific file.
 
315
    rev_graph = branch.repository.get_revision_graph(mainline_revisions[-1])
 
316
    sorted_rev_list = topo_sort(rev_graph)
 
317
    ancestry = {}
 
318
    for rev in sorted_rev_list:
 
319
        parents = rev_graph[rev]
 
320
        if rev not in weave_modifed_revisions and len(parents) == 1:
 
321
            # We will not be adding anything new, so just use a reference to
 
322
            # the parent ancestry.
 
323
            rev_ancestry = ancestry[parents[0]]
 
324
        else:
 
325
            rev_ancestry = set()
 
326
            if rev in weave_modifed_revisions:
 
327
                rev_ancestry.add(rev)
 
328
            for parent in parents:
 
329
                rev_ancestry = rev_ancestry.union(ancestry[parent])
 
330
        ancestry[rev] = rev_ancestry
 
331
 
 
332
    def is_merging_rev(r):
 
333
        parents = rev_graph[r]
 
334
        if len(parents) > 1:
 
335
            leftparent = parents[0]
 
336
            for rightparent in parents[1:]:
 
337
                if not ancestry[leftparent].issuperset(
 
338
                        ancestry[rightparent]):
 
339
                    return True
 
340
        return False
 
341
 
 
342
    # filter from the view the revisions that did not change or merge 
 
343
    # the specific file
 
344
    return [(r, n, d) for r, n, d in view_revs_iter
 
345
            if r in weave_modifed_revisions or is_merging_rev(r)]
272
346
 
273
347
 
274
348
def get_view_revisions(mainline_revs, rev_nos, branch, direction,
296
370
    elif direction != 'reverse':
297
371
        raise ValueError('invalid direction %r' % direction)
298
372
 
299
 
    revision_history = branch.revision_history()
300
 
 
301
373
    for sequence, rev_id, merge_depth, revno, end_of_merge in merge_sorted_revisions:
302
374
        yield rev_id, '.'.join(map(str, revno)), merge_depth
303
375
 
339
411
 
340
412
    def short_committer(self, rev):
341
413
        return re.sub('<.*@.*>', '', rev.committer).strip(' ')
342
 
    
343
 
    
 
414
 
 
415
 
344
416
class LongLogFormatter(LogFormatter):
345
 
    def show(self, revno, rev, delta):
346
 
        return self._show_helper(revno=revno, rev=rev, delta=delta)
 
417
 
 
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
 
422
 
 
423
    def show(self, revno, rev, delta, tags=None):
 
424
        return self._show_helper(revno=revno, rev=rev, delta=delta, tags=tags)
347
425
 
348
426
    @deprecated_method(zero_eleven)
349
427
    def show_merge(self, rev, merge_depth):
350
 
        return self._show_helper(rev=rev, indent='    '*merge_depth, merged=True, delta=None)
 
428
        return self._show_helper(rev=rev, indent='    '*merge_depth,
 
429
                                 merged=True, delta=None)
351
430
 
352
 
    def show_merge_revno(self, rev, merge_depth, revno):
 
431
    def show_merge_revno(self, rev, merge_depth, revno, tags=None):
353
432
        """Show a merged revision rev, with merge_depth and a revno."""
354
433
        return self._show_helper(rev=rev, revno=revno,
355
 
            indent='    '*merge_depth, merged=True, delta=None)
 
434
            indent='    '*merge_depth, merged=True, delta=None, tags=tags)
356
435
 
357
 
    def _show_helper(self, rev=None, revno=None, indent='', merged=False, delta=None):
 
436
    def _show_helper(self, rev=None, revno=None, indent='', merged=False,
 
437
                     delta=None, tags=None):
358
438
        """Show a revision, either merged or not."""
359
439
        from bzrlib.osutils import format_date
360
440
        to_file = self.to_file
361
441
        print >>to_file,  indent+'-' * 60
362
442
        if revno is not None:
363
443
            print >>to_file,  indent+'revno:', revno
 
444
        if tags:
 
445
            print >>to_file, indent+'tags: %s' % (', '.join(tags))
364
446
        if merged:
365
447
            print >>to_file,  indent+'merged:', rev.revision_id
366
448
        elif self.show_ids:
369
451
            for parent_id in rev.parent_ids:
370
452
                print >>to_file, indent+'parent:', parent_id
371
453
        print >>to_file,  indent+'committer:', rev.committer
 
454
 
372
455
        try:
373
456
            print >>to_file, indent+'branch nick: %s' % \
374
457
                rev.properties['branch-nick']
461
544
    lf = LineLogFormatter(None)
462
545
    return lf.log_string(None, rev, max_chars)
463
546
 
464
 
FORMATTERS = {
465
 
              'long': LongLogFormatter,
466
 
              'short': ShortLogFormatter,
467
 
              'line': LineLogFormatter,
468
 
              }
 
547
 
 
548
class LogFormatterRegistry(registry.Registry):
 
549
    """Registry for log formatters"""
 
550
 
 
551
    def make_formatter(self, name, *args, **kwargs):
 
552
        """Construct a formatter from arguments.
 
553
 
 
554
        :param name: Name of the formatter to construct.  'short', 'long' and
 
555
            'line' are built-in.
 
556
        """
 
557
        return self.get(name)(*args, **kwargs)
 
558
 
 
559
    def get_default(self, branch):
 
560
        return self.get(branch.get_config().log_format())
 
561
 
 
562
 
 
563
log_formatter_registry = LogFormatterRegistry()
 
564
 
 
565
 
 
566
log_formatter_registry.register('short', ShortLogFormatter,
 
567
                                'Moderately short log format')
 
568
log_formatter_registry.register('long', LongLogFormatter,
 
569
                                'Detailed log format')
 
570
log_formatter_registry.register('line', LineLogFormatter,
 
571
                                'Log format with one line per revision')
 
572
 
469
573
 
470
574
def register_formatter(name, formatter):
471
 
    FORMATTERS[name] = formatter
 
575
    log_formatter_registry.register(name, formatter)
 
576
 
472
577
 
473
578
def log_formatter(name, *args, **kwargs):
474
579
    """Construct a formatter from arguments.
478
583
    """
479
584
    from bzrlib.errors import BzrCommandError
480
585
    try:
481
 
        return FORMATTERS[name](*args, **kwargs)
 
586
        return log_formatter_registry.make_formatter(name, *args, **kwargs)
482
587
    except KeyError:
483
588
        raise BzrCommandError("unknown log formatter: %r" % name)
484
589
 
 
590
 
485
591
def show_one_log(revno, rev, delta, verbose, to_file, show_timezone):
486
592
    # deprecated; for compatibility
487
593
    lf = LongLogFormatter(to_file=to_file, show_timezone=show_timezone)