~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: 2008-08-28 02:30:29 UTC
  • mfrom: (3642.1.8 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20080828023029-r2qwgt7zu9udtla3
(robertc) Permit filtering of log output by plugins. (Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
210
210
                                              specific_fileid,
211
211
                                              generate_merge_revisions,
212
212
                                              allow_single_merge_revision)
213
 
    if search is not None:
214
 
        searchRE = re.compile(search, re.IGNORECASE)
215
 
    else:
216
 
        searchRE = None
217
 
 
218
213
    rev_tag_dict = {}
219
214
    generate_tags = getattr(lf, 'supports_tags', False)
220
215
    if generate_tags:
225
220
 
226
221
    # now we just print all the revisions
227
222
    log_count = 0
228
 
    for (rev_id, revno, merge_depth), rev, delta in _iter_revisions(
229
 
        branch.repository, view_revisions, generate_delta):
230
 
        if searchRE:
231
 
            if not searchRE.search(rev.message):
232
 
                continue
233
 
 
234
 
        lr = LogRevision(rev, revno, merge_depth, delta,
235
 
                         rev_tag_dict.get(rev_id))
236
 
        lf.log_revision(lr)
237
 
        if limit:
238
 
            log_count += 1
239
 
            if log_count >= limit:
240
 
                break
 
223
    revision_iterator = make_log_rev_iterator(branch, view_revisions,
 
224
        generate_delta, search)
 
225
    for revs in revision_iterator:
 
226
        for (rev_id, revno, merge_depth), rev, delta in revs:
 
227
            lr = LogRevision(rev, revno, merge_depth, delta,
 
228
                             rev_tag_dict.get(rev_id))
 
229
            lf.log_revision(lr)
 
230
            if limit:
 
231
                log_count += 1
 
232
                if log_count >= limit:
 
233
                    break
241
234
 
242
235
 
243
236
def calculate_view_revisions(branch, start_revision, end_revision, direction,
295
288
        yield revision_id, str(start_revno - num), 0
296
289
 
297
290
 
298
 
def _iter_revisions(repository, view_revisions, generate_delta):
 
291
def make_log_rev_iterator(branch, view_revisions, generate_delta, search):
 
292
    """Create a revision iterator for log.
 
293
 
 
294
    :param branch: The branch being logged.
 
295
    :param view_revisions: The revisions being viewed.
 
296
    :param generate_delta: Whether to generate a delta for each revision.
 
297
    :param search: A user text search string.
 
298
    :return: An iterator over lists of ((rev_id, revno, merge_depth), rev,
 
299
        delta).
 
300
    """
 
301
    # Convert view_revisions into (view, None, None) groups to fit with
 
302
    # the standard interface here.
 
303
    if type(view_revisions) == list:
 
304
        # A single batch conversion is faster than many incremental ones.
 
305
        # As we have all the data, do a batch conversion.
 
306
        nones = [None] * len(view_revisions)
 
307
        log_rev_iterator = iter([zip(view_revisions, nones, nones)])
 
308
    else:
 
309
        def _convert():
 
310
            for view in view_revisions:
 
311
                yield (view, None, None)
 
312
        log_rev_iterator = iter([_convert()])
 
313
    for adapter in log_adapters:
 
314
        log_rev_iterator = adapter(branch, generate_delta, search,
 
315
            log_rev_iterator)
 
316
    return log_rev_iterator
 
317
 
 
318
 
 
319
def _make_search_filter(branch, generate_delta, search, log_rev_iterator):
 
320
    """Create a filtered iterator of log_rev_iterator matching on a regex.
 
321
 
 
322
    :param branch: The branch being logged.
 
323
    :param generate_delta: Whether to generate a delta for each revision.
 
324
    :param search: A user text search string.
 
325
    :param log_rev_iterator: An input iterator containing all revisions that
 
326
        could be displayed, in lists.
 
327
    :return: An iterator over lists of ((rev_id, revno, merge_depth), rev,
 
328
        delta).
 
329
    """
 
330
    if search is None:
 
331
        return log_rev_iterator
 
332
    # Compile the search now to get early errors.
 
333
    searchRE = re.compile(search, re.IGNORECASE)
 
334
    return _filter_message_re(searchRE, log_rev_iterator)
 
335
 
 
336
 
 
337
def _filter_message_re(searchRE, log_rev_iterator):
 
338
    for revs in log_rev_iterator:
 
339
        new_revs = []
 
340
        for (rev_id, revno, merge_depth), rev, delta in revs:
 
341
            if searchRE.search(rev.message):
 
342
                new_revs.append(((rev_id, revno, merge_depth), rev, delta))
 
343
        yield new_revs
 
344
 
 
345
 
 
346
def _make_delta_filter(branch, generate_delta, search, log_rev_iterator):
 
347
    """Add revision deltas to a log iterator if needed.
 
348
 
 
349
    :param branch: The branch being logged.
 
350
    :param generate_delta: Whether to generate a delta for each revision.
 
351
    :param search: A user text search string.
 
352
    :param log_rev_iterator: An input iterator containing all revisions that
 
353
        could be displayed, in lists.
 
354
    :return: An iterator over lists of ((rev_id, revno, merge_depth), rev,
 
355
        delta).
 
356
    """
 
357
    if not generate_delta:
 
358
        return log_rev_iterator
 
359
    return _generate_deltas(branch.repository, log_rev_iterator)
 
360
 
 
361
 
 
362
def _generate_deltas(repository, log_rev_iterator):
 
363
    """Create deltas for each batch of revisions in log_rev_iterator."""
 
364
    for revs in log_rev_iterator:
 
365
        revisions = [rev[1] for rev in revs]
 
366
        deltas = repository.get_deltas_for_revisions(revisions)
 
367
        revs = [(rev[0], rev[1], delta) for rev, delta in izip(revs, deltas)]
 
368
        yield revs
 
369
 
 
370
 
 
371
def _make_revision_objects(branch, generate_delta, search, log_rev_iterator):
 
372
    """Extract revision objects from the repository
 
373
 
 
374
    :param branch: The branch being logged.
 
375
    :param generate_delta: Whether to generate a delta for each revision.
 
376
    :param search: A user text search string.
 
377
    :param log_rev_iterator: An input iterator containing all revisions that
 
378
        could be displayed, in lists.
 
379
    :return: An iterator over lists of ((rev_id, revno, merge_depth), rev,
 
380
        delta).
 
381
    """
 
382
    repository = branch.repository
 
383
    for revs in log_rev_iterator:
 
384
        # r = revision_id, n = revno, d = merge depth
 
385
        revision_ids = [view[0] for view, _, _ in revs]
 
386
        revisions = repository.get_revisions(revision_ids)
 
387
        revs = [(rev[0], revision, rev[2]) for rev, revision in
 
388
            izip(revs, revisions)]
 
389
        yield revs
 
390
 
 
391
 
 
392
def _make_batch_filter(branch, generate_delta, search, log_rev_iterator):
 
393
    """Group up a single large batch into smaller ones.
 
394
 
 
395
    :param branch: The branch being logged.
 
396
    :param generate_delta: Whether to generate a delta for each revision.
 
397
    :param search: A user text search string.
 
398
    :param log_rev_iterator: An input iterator containing all revisions that
 
399
        could be displayed, in lists.
 
400
    :return: An iterator over lists of ((rev_id, revno, merge_depth), rev, delta).
 
401
    """
 
402
    repository = branch.repository
299
403
    num = 9
300
 
    view_revisions = iter(view_revisions)
301
 
    while True:
302
 
        cur_view_revisions = [d for x, d in zip(range(num), view_revisions)]
303
 
        if len(cur_view_revisions) == 0:
304
 
            break
305
 
        cur_deltas = {}
306
 
        # r = revision, n = revno, d = merge depth
307
 
        revision_ids = [r for (r, n, d) in cur_view_revisions]
308
 
        revisions = repository.get_revisions(revision_ids)
309
 
        if generate_delta:
310
 
            deltas = repository.get_deltas_for_revisions(revisions)
311
 
            cur_deltas = dict(izip((r.revision_id for r in revisions),
312
 
                                   deltas))
313
 
        for view_data, revision in izip(cur_view_revisions, revisions):
314
 
            yield view_data, revision, cur_deltas.get(revision.revision_id)
315
 
        num = min(int(num * 1.5), 200)
 
404
    for batch in log_rev_iterator:
 
405
        batch = iter(batch)
 
406
        while True:
 
407
            step = [detail for _, detail in zip(range(num), batch)]
 
408
            if len(step) == 0:
 
409
                break
 
410
            yield step
 
411
            num = min(int(num * 1.5), 200)
316
412
 
317
413
 
318
414
def _get_mainline_revs(branch, start_revision, end_revision):
894
990
 
895
991
 
896
992
properties_handler_registry = registry.Registry()
 
993
 
 
994
# adapters which revision ids to log are filtered. When log is called, the
 
995
# log_rev_iterator is adapted through each of these factory methods.
 
996
# Plugins are welcome to mutate this list in any way they like - as long
 
997
# as the overall behaviour is preserved. At this point there is no extensible
 
998
# mechanism for getting parameters to each factory method, and until there is
 
999
# this won't be considered a stable api.
 
1000
log_adapters = [
 
1001
    # core log logic
 
1002
    _make_batch_filter,
 
1003
    # read revision objects
 
1004
    _make_revision_objects,
 
1005
    # filter on log messages
 
1006
    _make_search_filter,
 
1007
    # generate deltas for things we will show
 
1008
    _make_delta_filter
 
1009
    ]