~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/log.py

  • Committer: John Arbash Meinel
  • Date: 2007-04-28 15:04:17 UTC
  • mfrom: (2466 +trunk)
  • mto: This revision was merged to the branch mainline in revision 2566.
  • Revision ID: john@arbash-meinel.com-20070428150417-trp3pi0pzd411pu4
[merge] bzr.dev 2466

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
61
61
import bzrlib.errors as errors
62
62
from bzrlib.symbol_versioning import deprecated_method, zero_eleven
63
63
from bzrlib.trace import mutter
64
 
from bzrlib.tsort import merge_sort
 
64
from bzrlib.tsort import(
 
65
    merge_sort,
 
66
    topo_sort,
 
67
    )
65
68
 
66
69
 
67
70
def find_touching_revisions(branch, file_id):
221
224
        symbol_versioning.warn('LogFormatters should provide show_merge_revno '
222
225
            'instead of show_merge since bzr 0.11.',
223
226
            DeprecationWarning, stacklevel=3)
224
 
    view_revisions = list(get_view_revisions(mainline_revs, rev_nos, branch,
225
 
                          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()
226
242
 
227
243
    def iter_revisions():
228
244
        # r = revision, n = revno, d = merge depth
233
249
        while revision_ids:
234
250
            cur_deltas = {}
235
251
            revisions = repository.get_revisions(revision_ids[:num])
236
 
            if verbose or specific_fileid:
 
252
            if verbose:
237
253
                delta_revisions = [r for r in revisions if
238
254
                                   r.revision_id in zeros]
239
255
                deltas = repository.get_deltas_for_revisions(delta_revisions)
241
257
                                        delta_revisions), deltas))
242
258
            for revision in revisions:
243
259
                # The delta value will be None unless
244
 
                # 1. verbose or specific_fileid is specified, and
 
260
                # 1. verbose is specified, and
245
261
                # 2. the revision is a mainline revision
246
262
                yield revision, cur_deltas.get(revision.revision_id)
247
263
            revision_ids  = revision_ids[num:]
248
 
            num = int(num * 1.5)
 
264
            num = min(int(num * 1.5), 200)
249
265
            
250
266
    # now we just print all the revisions
251
267
    for ((rev_id, revno, merge_depth), (rev, delta)) in \
256
272
                continue
257
273
 
258
274
        if merge_depth == 0:
259
 
            # a mainline revision.
260
 
                
261
 
            if specific_fileid:
262
 
                if not delta.touches_file_id(specific_fileid):
263
 
                    continue
264
 
    
265
 
            if not verbose:
266
 
                # although we calculated it, throw it away without display
267
 
                delta = None
268
 
 
269
 
            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)
270
279
        else:
271
280
            if show_merge_revno is None:
272
281
                lf.show_merge(rev, merge_depth)
273
282
            else:
274
 
                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)]
275
346
 
276
347
 
277
348
def get_view_revisions(mainline_revs, rev_nos, branch, direction,
340
411
 
341
412
    def short_committer(self, rev):
342
413
        return re.sub('<.*@.*>', '', rev.committer).strip(' ')
343
 
    
344
 
    
 
414
 
 
415
 
345
416
class LongLogFormatter(LogFormatter):
346
 
    def show(self, revno, rev, delta):
347
 
        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)
348
425
 
349
426
    @deprecated_method(zero_eleven)
350
427
    def show_merge(self, rev, merge_depth):
351
 
        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)
352
430
 
353
 
    def show_merge_revno(self, rev, merge_depth, revno):
 
431
    def show_merge_revno(self, rev, merge_depth, revno, tags=None):
354
432
        """Show a merged revision rev, with merge_depth and a revno."""
355
433
        return self._show_helper(rev=rev, revno=revno,
356
 
            indent='    '*merge_depth, merged=True, delta=None)
 
434
            indent='    '*merge_depth, merged=True, delta=None, tags=tags)
357
435
 
358
 
    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):
359
438
        """Show a revision, either merged or not."""
360
439
        from bzrlib.osutils import format_date
361
440
        to_file = self.to_file
362
441
        print >>to_file,  indent+'-' * 60
363
442
        if revno is not None:
364
443
            print >>to_file,  indent+'revno:', revno
 
444
        if tags:
 
445
            print >>to_file, indent+'tags: %s' % (', '.join(tags))
365
446
        if merged:
366
447
            print >>to_file,  indent+'merged:', rev.revision_id
367
448
        elif self.show_ids:
370
451
            for parent_id in rev.parent_ids:
371
452
                print >>to_file, indent+'parent:', parent_id
372
453
        print >>to_file,  indent+'committer:', rev.committer
 
454
 
373
455
        try:
374
456
            print >>to_file, indent+'branch nick: %s' % \
375
457
                rev.properties['branch-nick']