~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/branch.py

  • Committer: Ian Clatworthy
  • Date: 2009-02-09 23:33:58 UTC
  • mfrom: (3955.3.10 open-in-launchpad)
  • mto: This revision was merged to the branch mainline in revision 3992.
  • Revision ID: ian.clatworthy@canonical.com-20090209233358-87e0072zgnkomb6v
Command for opening Launchpad pages (Jonathan Lange)

Show diffs side-by-side

added added

removed removed

Lines of Context:
91
91
        self._revision_id_to_revno_cache = None
92
92
        self._partial_revision_id_to_revno_cache = {}
93
93
        self._last_revision_info_cache = None
 
94
        self._merge_sorted_revisions_cache = None
94
95
        self._open_hook()
95
96
        hooks = Branch.hooks['open']
96
97
        for hook in hooks:
283
284
 
284
285
        :return: A dictionary mapping revision_id => dotted revno.
285
286
        """
286
 
        last_revision = self.last_revision()
287
 
        revision_graph = repository._old_get_graph(self.repository,
288
 
            last_revision)
289
 
        merge_sorted_revisions = tsort.merge_sort(
290
 
            revision_graph,
291
 
            last_revision,
292
 
            None,
293
 
            generate_revno=True)
294
287
        revision_id_to_revno = dict((rev_id, revno)
295
 
                                    for seq_num, rev_id, depth, revno, end_of_merge
296
 
                                     in merge_sorted_revisions)
 
288
            for rev_id, depth, revno, end_of_merge
 
289
             in self.iter_merge_sorted_revisions())
297
290
        return revision_id_to_revno
298
291
 
 
292
    @needs_read_lock
 
293
    def iter_merge_sorted_revisions(self, start_revision_id=None,
 
294
            stop_revision_id=None, stop_rule='exclude', direction='reverse'):
 
295
        """Walk the revisions for a branch in merge sorted order.
 
296
 
 
297
        Merge sorted order is the output from a merge-aware,
 
298
        topological sort, i.e. all parents come before their
 
299
        children going forward; the opposite for reverse.
 
300
 
 
301
        :param start_revision_id: the revision_id to begin walking from.
 
302
            If None, the branch tip is used.
 
303
        :param stop_revision_id: the revision_id to terminate the walk
 
304
            after. If None, the rest of history is included.
 
305
        :param stop_rule: if stop_revision_id is not None, the precise rule
 
306
            to use for termination:
 
307
            * 'exclude' - leave the stop revision out of the result (default)
 
308
            * 'include' - the stop revision is the last item in the result
 
309
            * 'with-merges' - include the stop revision and all of its
 
310
              merged revisions in the result
 
311
        :param direction: either 'reverse' or 'forward':
 
312
            * reverse means return the start_revision_id first, i.e.
 
313
              start at the most recent revision and go backwards in history
 
314
            * forward returns tuples in the opposite order to reverse.
 
315
              Note in particular that forward does *not* do any intelligent
 
316
              ordering w.r.t. depth as some clients of this API may like.
 
317
              (If required, that ought to be done at higher layers.)
 
318
 
 
319
        :return: an iterator over (revision_id, depth, revno, end_of_merge)
 
320
            tuples where:
 
321
 
 
322
            * revision_id: the unique id of the revision
 
323
            * depth: How many levels of merging deep this node has been
 
324
              found.
 
325
            * revno_sequence: This field provides a sequence of
 
326
              revision numbers for all revisions. The format is:
 
327
              (REVNO, BRANCHNUM, BRANCHREVNO). BRANCHNUM is the number of the
 
328
              branch that the revno is on. From left to right the REVNO numbers
 
329
              are the sequence numbers within that branch of the revision.
 
330
            * end_of_merge: When True the next node (earlier in history) is
 
331
              part of a different merge.
 
332
        """
 
333
        # Note: depth and revno values are in the context of the branch so
 
334
        # we need the full graph to get stable numbers, regardless of the
 
335
        # start_revision_id.
 
336
        if self._merge_sorted_revisions_cache is None:
 
337
            last_revision = self.last_revision()
 
338
            graph = self.repository.get_graph()
 
339
            parent_map = dict(((key, value) for key, value in
 
340
                     graph.iter_ancestry([last_revision]) if value is not None))
 
341
            revision_graph = repository._strip_NULL_ghosts(parent_map)
 
342
            revs = tsort.merge_sort(revision_graph, last_revision, None,
 
343
                generate_revno=True)
 
344
            # Drop the sequence # before caching
 
345
            self._merge_sorted_revisions_cache = [r[1:] for r in revs]
 
346
 
 
347
        filtered = self._filter_merge_sorted_revisions(
 
348
            self._merge_sorted_revisions_cache, start_revision_id,
 
349
            stop_revision_id, stop_rule)
 
350
        if direction == 'reverse':
 
351
            return filtered
 
352
        if direction == 'forward':
 
353
            return reversed(list(filtered))
 
354
        else:
 
355
            raise ValueError('invalid direction %r' % direction)
 
356
 
 
357
    def _filter_merge_sorted_revisions(self, merge_sorted_revisions,
 
358
        start_revision_id, stop_revision_id, stop_rule):
 
359
        """Iterate over an inclusive range of sorted revisions."""
 
360
        rev_iter = iter(merge_sorted_revisions)
 
361
        if start_revision_id is not None:
 
362
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
363
                if rev_id != start_revision_id:
 
364
                    continue
 
365
                else:
 
366
                    # The decision to include the start or not
 
367
                    # depends on the stop_rule if a stop is provided
 
368
                    rev_iter = chain(
 
369
                        iter([(rev_id, depth, revno, end_of_merge)]),
 
370
                        rev_iter)
 
371
                    break
 
372
        if stop_revision_id is None:
 
373
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
374
                yield rev_id, depth, revno, end_of_merge
 
375
        elif stop_rule == 'exclude':
 
376
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
377
                if rev_id == stop_revision_id:
 
378
                    return
 
379
                yield rev_id, depth, revno, end_of_merge
 
380
        elif stop_rule == 'include':
 
381
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
382
                yield rev_id, depth, revno, end_of_merge
 
383
                if rev_id == stop_revision_id:
 
384
                    return
 
385
        elif stop_rule == 'with-merges':
 
386
            stop_rev = self.repository.get_revision(stop_revision_id)
 
387
            if stop_rev.parent_ids:
 
388
                left_parent = stop_rev.parent_ids[0]
 
389
            else:
 
390
                left_parent = _mod_revision.NULL_REVISION
 
391
            for rev_id, depth, revno, end_of_merge in rev_iter:
 
392
                if rev_id == left_parent:
 
393
                    return
 
394
                yield rev_id, depth, revno, end_of_merge
 
395
        else:
 
396
            raise ValueError('invalid stop_rule %r' % stop_rule)
 
397
 
299
398
    def leave_lock_in_place(self):
300
399
        """Tell this branch object not to release the physical lock when this
301
400
        object is unlocked.
462
561
        self._revision_history_cache = None
463
562
        self._revision_id_to_revno_cache = None
464
563
        self._last_revision_info_cache = None
 
564
        self._merge_sorted_revisions_cache = None
465
565
 
466
566
    def _gen_revision_history(self):
467
567
        """Return sequence of revision hashes on to this branch.