~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/repository.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2011-01-14 17:18:23 UTC
  • mfrom: (5536.2.9 fetch-dev-docs)
  • Revision ID: pqm@pqm.ubuntu.com-20110114171823-5gx64sero62ag6r4
(jelmer) Add a developer doc on the topic of fetch. (Andrew Bennetts)

Show diffs side-by-side

added added

removed removed

Lines of Context:
42
42
    pyutils,
43
43
    revision as _mod_revision,
44
44
    static_tuple,
45
 
    symbol_versioning,
46
45
    trace,
47
46
    tsort,
48
47
    versionedfile,
57
56
from bzrlib import (
58
57
    errors,
59
58
    registry,
 
59
    symbol_versioning,
60
60
    ui,
61
61
    )
62
62
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
1597
1597
        return ret
1598
1598
 
1599
1599
    @needs_read_lock
1600
 
    def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
 
1600
    def search_missing_revision_ids(self, other,
 
1601
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
 
1602
            find_ghosts=True, revision_ids=None, if_present_ids=None):
1601
1603
        """Return the revision ids that other has that this does not.
1602
1604
 
1603
1605
        These are returned in topological order.
1604
1606
 
1605
1607
        revision_id: only return revision ids included by revision_id.
1606
1608
        """
 
1609
        if symbol_versioning.deprecated_passed(revision_id):
 
1610
            symbol_versioning.warn(
 
1611
                'search_missing_revision_ids(revision_id=...) was '
 
1612
                'deprecated in 2.3.  Use revision_ids=[...] instead.',
 
1613
                DeprecationWarning, stacklevel=3)
 
1614
            if revision_ids is not None:
 
1615
                raise AssertionError(
 
1616
                    'revision_ids is mutually exclusive with revision_id')
 
1617
            if revision_id is not None:
 
1618
                revision_ids = [revision_id]
1607
1619
        return InterRepository.get(other, self).search_missing_revision_ids(
1608
 
            revision_id, find_ghosts)
 
1620
            find_ghosts=find_ghosts, revision_ids=revision_ids,
 
1621
            if_present_ids=if_present_ids)
1609
1622
 
1610
1623
    @staticmethod
1611
1624
    def open(base):
3436
3449
                               fetch_spec=fetch_spec,
3437
3450
                               find_ghosts=find_ghosts)
3438
3451
 
3439
 
    def _walk_to_common_revisions(self, revision_ids):
 
3452
    def _walk_to_common_revisions(self, revision_ids, if_present_ids=None):
3440
3453
        """Walk out from revision_ids in source to revisions target has.
3441
3454
 
3442
3455
        :param revision_ids: The start point for the search.
3444
3457
        """
3445
3458
        target_graph = self.target.get_graph()
3446
3459
        revision_ids = frozenset(revision_ids)
 
3460
        if if_present_ids:
 
3461
            all_wanted_revs = revision_ids.union(if_present_ids)
 
3462
        else:
 
3463
            all_wanted_revs = revision_ids
3447
3464
        missing_revs = set()
3448
3465
        source_graph = self.source.get_graph()
3449
3466
        # ensure we don't pay silly lookup costs.
3450
 
        searcher = source_graph._make_breadth_first_searcher(revision_ids)
 
3467
        searcher = source_graph._make_breadth_first_searcher(all_wanted_revs)
3451
3468
        null_set = frozenset([_mod_revision.NULL_REVISION])
3452
3469
        searcher_exhausted = False
3453
3470
        while True:
3489
3506
        return searcher.get_result()
3490
3507
 
3491
3508
    @needs_read_lock
3492
 
    def search_missing_revision_ids(self, revision_id=None, find_ghosts=True):
 
3509
    def search_missing_revision_ids(self,
 
3510
            revision_id=symbol_versioning.DEPRECATED_PARAMETER,
 
3511
            find_ghosts=True, revision_ids=None, if_present_ids=None):
3493
3512
        """Return the revision ids that source has that target does not.
3494
3513
 
3495
3514
        :param revision_id: only return revision ids included by this
3496
 
                            revision_id.
 
3515
            revision_id.
 
3516
        :param revision_ids: return revision ids included by these
 
3517
            revision_ids.  NoSuchRevision will be raised if any of these
 
3518
            revisions are not present.
 
3519
        :param if_present_ids: like revision_ids, but will not cause
 
3520
            NoSuchRevision if any of these are absent, instead they will simply
 
3521
            not be in the result.  This is useful for e.g. finding revisions
 
3522
            to fetch for tags, which may reference absent revisions.
3497
3523
        :param find_ghosts: If True find missing revisions in deep history
3498
3524
            rather than just finding the surface difference.
3499
3525
        :return: A bzrlib.graph.SearchResult.
3500
3526
        """
 
3527
        if symbol_versioning.deprecated_passed(revision_id):
 
3528
            symbol_versioning.warn(
 
3529
                'search_missing_revision_ids(revision_id=...) was '
 
3530
                'deprecated in 2.3.  Use revision_ids=[...] instead.',
 
3531
                DeprecationWarning, stacklevel=2)
 
3532
            if revision_ids is not None:
 
3533
                raise AssertionError(
 
3534
                    'revision_ids is mutually exclusive with revision_id')
 
3535
            if revision_id is not None:
 
3536
                revision_ids = [revision_id]
 
3537
        del revision_id
3501
3538
        # stop searching at found target revisions.
3502
 
        if not find_ghosts and revision_id is not None:
3503
 
            return self._walk_to_common_revisions([revision_id])
 
3539
        if not find_ghosts and (revision_ids is not None or if_present_ids is
 
3540
                not None):
 
3541
            return self._walk_to_common_revisions(revision_ids,
 
3542
                    if_present_ids=if_present_ids)
3504
3543
        # generic, possibly worst case, slow code path.
3505
3544
        target_ids = set(self.target.all_revision_ids())
3506
 
        if revision_id is not None:
3507
 
            source_ids = self.source.get_ancestry(revision_id)
3508
 
            if source_ids[0] is not None:
3509
 
                raise AssertionError()
3510
 
            source_ids.pop(0)
3511
 
        else:
3512
 
            source_ids = self.source.all_revision_ids()
 
3545
        source_ids = self._present_source_revisions_for(
 
3546
            revision_ids, if_present_ids)
3513
3547
        result_set = set(source_ids).difference(target_ids)
3514
3548
        return self.source.revision_ids_to_search_result(result_set)
3515
3549
 
 
3550
    def _present_source_revisions_for(self, revision_ids, if_present_ids=None):
 
3551
        """Returns set of all revisions in ancestry of revision_ids present in
 
3552
        the source repo.
 
3553
 
 
3554
        :param revision_ids: if None, all revisions in source are returned.
 
3555
        :param if_present_ids: like revision_ids, but if any/all of these are
 
3556
            absent no error is raised.
 
3557
        """
 
3558
        if revision_ids is not None or if_present_ids is not None:
 
3559
            # First, ensure all specified revisions exist.  Callers expect
 
3560
            # NoSuchRevision when they pass absent revision_ids here.
 
3561
            if revision_ids is None:
 
3562
                revision_ids = set()
 
3563
            if if_present_ids is None:
 
3564
                if_present_ids = set()
 
3565
            revision_ids = set(revision_ids)
 
3566
            if_present_ids = set(if_present_ids)
 
3567
            all_wanted_ids = revision_ids.union(if_present_ids)
 
3568
            graph = self.source.get_graph()
 
3569
            present_revs = set(graph.get_parent_map(all_wanted_ids))
 
3570
            missing = revision_ids.difference(present_revs)
 
3571
            if missing:
 
3572
                raise errors.NoSuchRevision(self.source, missing.pop())
 
3573
            found_ids = all_wanted_ids.intersection(present_revs)
 
3574
            source_ids = [rev_id for (rev_id, parents) in
 
3575
                          graph.iter_ancestry(found_ids)
 
3576
                          if rev_id != _mod_revision.NULL_REVISION
 
3577
                          and parents is not None]
 
3578
        else:
 
3579
            source_ids = self.source.all_revision_ids()
 
3580
        return set(source_ids)
 
3581
 
3516
3582
    @staticmethod
3517
3583
    def _same_model(source, target):
3518
3584
        """True if source and target have the same data representation.
3836
3902
            fetch_spec=None):
3837
3903
        """See InterRepository.fetch()."""
3838
3904
        if fetch_spec is not None:
3839
 
            raise AssertionError("Not implemented yet...")
 
3905
            if (isinstance(fetch_spec, graph.NotInOtherForRevs) and
 
3906
                    len(fetch_spec.required_ids) == 1 and not
 
3907
                    fetch_spec.if_present_ids):
 
3908
                revision_id = list(fetch_spec.required_ids)[0]
 
3909
                del fetch_spec
 
3910
            else:
 
3911
                raise AssertionError("Not implemented yet...")
3840
3912
        ui.ui_factory.warn_experimental_format_fetch(self)
3841
3913
        if (not self.source.supports_rich_root()
3842
3914
            and self.target.supports_rich_root()):
3849
3921
            ui.ui_factory.show_user_warning('cross_format_fetch',
3850
3922
                from_format=self.source._format,
3851
3923
                to_format=self.target._format)
 
3924
        if revision_id:
 
3925
            search_revision_ids = [revision_id]
 
3926
        else:
 
3927
            search_revision_ids = None
3852
3928
        revision_ids = self.target.search_missing_revision_ids(self.source,
3853
 
            revision_id, find_ghosts=find_ghosts).get_keys()
 
3929
            revision_ids=search_revision_ids, find_ghosts=find_ghosts).get_keys()
3854
3930
        if not revision_ids:
3855
3931
            return 0, 0
3856
3932
        revision_ids = tsort.topo_sort(