~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: 2007-06-21 05:22:37 UTC
  • mfrom: (2490.2.33 graphwalker)
  • Revision ID: pqm@pqm.ubuntu.com-20070621052237-2phm1z5dg4arrwnk
Avoid topological sorting in Repository.get_ancestry where possible

Show diffs side-by-side

added added

removed removed

Lines of Context:
59
59
    symbol_versioning,
60
60
    )
61
61
import bzrlib.errors as errors
62
 
from bzrlib.revisionspec import(
63
 
    RevisionInfo
64
 
    )
65
62
from bzrlib.symbol_versioning import (
66
63
    deprecated_method,
67
64
    zero_eleven,
118
115
        revno += 1
119
116
 
120
117
 
 
118
 
121
119
def _enumerate_history(branch):
122
120
    rh = []
123
121
    revno = 1
204
202
    else:
205
203
        searchRE = None
206
204
 
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:
 
205
    which_revs = _enumerate_history(branch)
 
206
    
 
207
    if start_revision is None:
 
208
        start_revision = 1
 
209
    else:
 
210
        branch.check_real_revno(start_revision)
 
211
    
 
212
    if end_revision is None:
 
213
        end_revision = len(which_revs)
 
214
    else:
 
215
        branch.check_real_revno(end_revision)
 
216
 
 
217
    # list indexes are 0-based; revisions are 1-based
 
218
    cut_revs = which_revs[(start_revision-1):(end_revision)]
 
219
    if not cut_revs:
210
220
        return
211
221
 
212
 
    if direction == 'reverse':
213
 
        start_rev_id, end_rev_id = end_rev_id, start_rev_id
214
 
        
 
222
    # convert the revision history to a dictionary:
 
223
    rev_nos = dict((k, v) for v, k in cut_revs)
 
224
 
 
225
    # override the mainline to look like the revision history.
 
226
    mainline_revs = [revision_id for index, revision_id in cut_revs]
 
227
    if cut_revs[0][0] == 1:
 
228
        mainline_revs.insert(0, None)
 
229
    else:
 
230
        mainline_revs.insert(0, which_revs[start_revision-2][1])
215
231
    legacy_lf = getattr(lf, 'log_revision', None) is None
216
232
    if legacy_lf:
217
233
        # pre-0.17 formatters use show for mainline revisions.
234
250
                                           False)
235
251
    view_revs_iter = get_view_revisions(mainline_revs, rev_nos, branch,
236
252
                          direction, include_merges=generate_merge_revisions)
237
 
    view_revisions = _filter_revision_range(list(view_revs_iter),
238
 
                                            start_rev_id,
239
 
                                            end_rev_id)
240
253
    if specific_fileid:
241
 
        view_revisions = _filter_revisions_touching_file_id(branch,
 
254
        view_revisions = _get_revisions_touching_file_id(branch,
242
255
                                                         specific_fileid,
243
256
                                                         mainline_revs,
244
 
                                                         view_revisions)
 
257
                                                         view_revs_iter)
 
258
    else:
 
259
        view_revisions = list(view_revs_iter)
245
260
 
246
261
    rev_tag_dict = {}
247
262
    generate_tags = getattr(lf, 'supports_tags', False)
254
269
    def iter_revisions():
255
270
        # r = revision, n = revno, d = merge depth
256
271
        revision_ids = [r for r, n, d in view_revisions]
 
272
        zeros = set(r for r, n, d in view_revisions if d == 0)
257
273
        num = 9
258
274
        repository = branch.repository
259
275
        while revision_ids:
260
276
            cur_deltas = {}
261
277
            revisions = repository.get_revisions(revision_ids[:num])
262
278
            if generate_delta:
263
 
                deltas = repository.get_deltas_for_revisions(revisions)
264
 
                cur_deltas = dict(izip((r.revision_id for r in revisions),
265
 
                                       deltas))
 
279
                delta_revisions = [r for r in revisions if
 
280
                                   r.revision_id in zeros]
 
281
                deltas = repository.get_deltas_for_revisions(delta_revisions)
 
282
                cur_deltas = dict(izip((r.revision_id for r in 
 
283
                                        delta_revisions), deltas))
266
284
            for revision in revisions:
 
285
                # The delta value will be None unless
 
286
                # 1. verbose is specified, and
 
287
                # 2. the revision is a mainline revision
267
288
                yield revision, cur_deltas.get(revision.revision_id)
268
289
            revision_ids  = revision_ids[num:]
269
290
            num = min(int(num * 1.5), 200)
303
324
                break
304
325
 
305
326
 
306
 
def _get_mainline_revs(branch, start_revision, end_revision):
307
 
    """Get the mainline revisions from the branch.
308
 
    
309
 
    Generates the list of mainline revisions for the branch.
310
 
    
311
 
    :param  branch: The branch containing the revisions. 
312
 
 
313
 
    :param  start_revision: The first revision to be logged.
314
 
            For backwards compatibility this may be a mainline integer revno,
315
 
            but for merge revision support a RevisionInfo is expected.
316
 
 
317
 
    :param  end_revision: The last revision to be logged.
318
 
            For backwards compatibility this may be a mainline integer revno,
319
 
            but for merge revision support a RevisionInfo is expected.
320
 
 
321
 
    :return: A (mainline_revs, rev_nos, start_rev_id, end_rev_id) tuple.
322
 
    """
323
 
    which_revs = _enumerate_history(branch)
324
 
    if not which_revs:
325
 
        return None, None, None, None
326
 
 
327
 
    # For mainline generation, map start_revision and end_revision to 
328
 
    # mainline revnos. If the revision is not on the mainline choose the 
329
 
    # appropriate extreme of the mainline instead - the extra will be 
330
 
    # filtered later.
331
 
    # Also map the revisions to rev_ids, to be used in the later filtering
332
 
    # stage.
333
 
    start_rev_id = None 
334
 
    if start_revision is None:
335
 
        start_revno = 1
336
 
    else:
337
 
        if isinstance(start_revision,RevisionInfo):
338
 
            start_rev_id = start_revision.rev_id
339
 
            start_revno = start_revision.revno or 1
340
 
        else:
341
 
            branch.check_real_revno(start_revision)
342
 
            start_revno = start_revision
343
 
    
344
 
    end_rev_id = None
345
 
    if end_revision is None:
346
 
        end_revno = len(which_revs)
347
 
    else:
348
 
        if isinstance(end_revision,RevisionInfo):
349
 
            end_rev_id = end_revision.rev_id
350
 
            end_revno = end_revision.revno or len(which_revs)
351
 
        else:
352
 
            branch.check_real_revno(end_revision)
353
 
            end_revno = end_revision
354
 
 
355
 
    if start_revno > end_revno:
356
 
        from bzrlib.errors import BzrCommandError
357
 
        raise BzrCommandError("Start revision must be older than "
358
 
                              "the end revision.")
359
 
 
360
 
    # list indexes are 0-based; revisions are 1-based
361
 
    cut_revs = which_revs[(start_revno-1):(end_revno)]
362
 
    if not cut_revs:
363
 
        return None, None, None, None
364
 
 
365
 
    # convert the revision history to a dictionary:
366
 
    rev_nos = dict((k, v) for v, k in cut_revs)
367
 
 
368
 
    # override the mainline to look like the revision history.
369
 
    mainline_revs = [revision_id for index, revision_id in cut_revs]
370
 
    if cut_revs[0][0] == 1:
371
 
        mainline_revs.insert(0, None)
372
 
    else:
373
 
        mainline_revs.insert(0, which_revs[start_revno-2][1])
374
 
    return mainline_revs, rev_nos, start_rev_id, end_rev_id
375
 
 
376
 
 
377
 
def _filter_revision_range(view_revisions, start_rev_id, end_rev_id):
378
 
    """Filter view_revisions based on revision ranges.
379
 
 
380
 
    :param view_revisions: A list of (revision_id, dotted_revno, merge_depth) 
381
 
            tuples to be filtered.
382
 
 
383
 
    :param start_rev_id: If not NONE specifies the first revision to be logged.
384
 
            If NONE then all revisions up to the end_rev_id are logged.
385
 
 
386
 
    :param end_rev_id: If not NONE specifies the last revision to be logged.
387
 
            If NONE then all revisions up to the end of the log are logged.
388
 
 
389
 
    :return: The filtered view_revisions.
390
 
    """
391
 
    if start_rev_id or end_rev_id: 
392
 
        revision_ids = [r for r, n, d in view_revisions]
393
 
        if start_rev_id:
394
 
            start_index = revision_ids.index(start_rev_id)
395
 
        else:
396
 
            start_index = 0
397
 
        if start_rev_id == end_rev_id:
398
 
            end_index = start_index
399
 
        else:
400
 
            if end_rev_id:
401
 
                end_index = revision_ids.index(end_rev_id)
402
 
            else:
403
 
                end_index = len(view_revisions) - 1
404
 
        # To include the revisions merged into the last revision, 
405
 
        # extend end_rev_id down to, but not including, the next rev
406
 
        # with the same or lesser merge_depth
407
 
        end_merge_depth = view_revisions[end_index][2]
408
 
        try:
409
 
            for index in xrange(end_index+1, len(view_revisions)+1):
410
 
                if view_revisions[index][2] <= end_merge_depth:
411
 
                    end_index = index - 1
412
 
                    break
413
 
        except IndexError:
414
 
            # if the search falls off the end then log to the end as well
415
 
            end_index = len(view_revisions) - 1
416
 
        view_revisions = view_revisions[start_index:end_index+1]
417
 
    return view_revisions
418
 
 
419
 
 
420
 
def _filter_revisions_touching_file_id(branch, file_id, mainline_revisions,
421
 
                                       view_revs_iter):
 
327
def _get_revisions_touching_file_id(branch, file_id, mainline_revisions,
 
328
                                    view_revs_iter):
422
329
    """Return the list of revision ids which touch a given file id.
423
330
 
424
 
    The function filters view_revisions and returns a subset.
425
331
    This includes the revisions which directly change the file id,
426
332
    and the revisions which merge these changes. So if the
427
333
    revision graph is::
645
551
            for l in message.split('\n'):
646
552
                print >>to_file,  indent+'  ' + l
647
553
        if revision.delta is not None:
648
 
            revision.delta.show(to_file, self.show_ids, indent=indent)
 
554
            revision.delta.show(to_file, self.show_ids)
649
555
 
650
556
 
651
557
class ShortLogFormatter(LogFormatter):