1707
1706
content is copied.
1710
ui.ui_factory.warn_experimental_format_fetch(self)
1711
from bzrlib.fetch import RepoFetcher
1712
# See <https://launchpad.net/bugs/456077> asking for a warning here
1713
if self.source._format.network_name() != self.target._format.network_name():
1714
ui.ui_factory.show_user_warning('cross_format_fetch',
1715
from_format=self.source._format,
1716
to_format=self.target._format)
1717
f = RepoFetcher(to_repository=self.target,
1718
from_repository=self.source,
1719
last_revision=revision_id,
1720
fetch_spec=fetch_spec,
1721
find_ghosts=find_ghosts)
1723
def _walk_to_common_revisions(self, revision_ids, if_present_ids=None):
1724
"""Walk out from revision_ids in source to revisions target has.
1726
:param revision_ids: The start point for the search.
1727
:return: A set of revision ids.
1729
target_graph = self.target.get_graph()
1730
revision_ids = frozenset(revision_ids)
1732
all_wanted_revs = revision_ids.union(if_present_ids)
1734
all_wanted_revs = revision_ids
1735
missing_revs = set()
1736
source_graph = self.source.get_graph()
1737
# ensure we don't pay silly lookup costs.
1738
searcher = source_graph._make_breadth_first_searcher(all_wanted_revs)
1739
null_set = frozenset([_mod_revision.NULL_REVISION])
1740
searcher_exhausted = False
1744
# Iterate the searcher until we have enough next_revs
1745
while len(next_revs) < self._walk_to_common_revisions_batch_size:
1747
next_revs_part, ghosts_part = searcher.next_with_ghosts()
1748
next_revs.update(next_revs_part)
1749
ghosts.update(ghosts_part)
1750
except StopIteration:
1751
searcher_exhausted = True
1753
# If there are ghosts in the source graph, and the caller asked for
1754
# them, make sure that they are present in the target.
1755
# We don't care about other ghosts as we can't fetch them and
1756
# haven't been asked to.
1757
ghosts_to_check = set(revision_ids.intersection(ghosts))
1758
revs_to_get = set(next_revs).union(ghosts_to_check)
1760
have_revs = set(target_graph.get_parent_map(revs_to_get))
1761
# we always have NULL_REVISION present.
1762
have_revs = have_revs.union(null_set)
1763
# Check if the target is missing any ghosts we need.
1764
ghosts_to_check.difference_update(have_revs)
1766
# One of the caller's revision_ids is a ghost in both the
1767
# source and the target.
1768
raise errors.NoSuchRevision(
1769
self.source, ghosts_to_check.pop())
1770
missing_revs.update(next_revs - have_revs)
1771
# Because we may have walked past the original stop point, make
1772
# sure everything is stopped
1773
stop_revs = searcher.find_seen_ancestors(have_revs)
1774
searcher.stop_searching_any(stop_revs)
1775
if searcher_exhausted:
1777
return searcher.get_result()
1709
raise NotImplementedError(self.fetch)
1779
1711
@needs_read_lock
1780
1712
def search_missing_revision_ids(self,
1795
1727
rather than just finding the surface difference.
1796
1728
:return: A bzrlib.graph.SearchResult.
1798
if symbol_versioning.deprecated_passed(revision_id):
1799
symbol_versioning.warn(
1800
'search_missing_revision_ids(revision_id=...) was '
1801
'deprecated in 2.4. Use revision_ids=[...] instead.',
1802
DeprecationWarning, stacklevel=2)
1803
if revision_ids is not None:
1804
raise AssertionError(
1805
'revision_ids is mutually exclusive with revision_id')
1806
if revision_id is not None:
1807
revision_ids = [revision_id]
1809
# stop searching at found target revisions.
1810
if not find_ghosts and (revision_ids is not None or if_present_ids is
1812
return self._walk_to_common_revisions(revision_ids,
1813
if_present_ids=if_present_ids)
1814
# generic, possibly worst case, slow code path.
1815
target_ids = set(self.target.all_revision_ids())
1816
source_ids = self._present_source_revisions_for(
1817
revision_ids, if_present_ids)
1818
result_set = set(source_ids).difference(target_ids)
1819
return self.source.revision_ids_to_search_result(result_set)
1821
def _present_source_revisions_for(self, revision_ids, if_present_ids=None):
1822
"""Returns set of all revisions in ancestry of revision_ids present in
1825
:param revision_ids: if None, all revisions in source are returned.
1826
:param if_present_ids: like revision_ids, but if any/all of these are
1827
absent no error is raised.
1829
if revision_ids is not None or if_present_ids is not None:
1830
# First, ensure all specified revisions exist. Callers expect
1831
# NoSuchRevision when they pass absent revision_ids here.
1832
if revision_ids is None:
1833
revision_ids = set()
1834
if if_present_ids is None:
1835
if_present_ids = set()
1836
revision_ids = set(revision_ids)
1837
if_present_ids = set(if_present_ids)
1838
all_wanted_ids = revision_ids.union(if_present_ids)
1839
graph = self.source.get_graph()
1840
present_revs = set(graph.get_parent_map(all_wanted_ids))
1841
missing = revision_ids.difference(present_revs)
1843
raise errors.NoSuchRevision(self.source, missing.pop())
1844
found_ids = all_wanted_ids.intersection(present_revs)
1845
source_ids = [rev_id for (rev_id, parents) in
1846
graph.iter_ancestry(found_ids)
1847
if rev_id != _mod_revision.NULL_REVISION
1848
and parents is not None]
1850
source_ids = self.source.all_revision_ids()
1851
return set(source_ids)
1730
raise NotImplementedError(self.search_missing_revision_ids)
1854
1733
def _same_model(source, target):
1874
1753
raise errors.IncompatibleRepositories(source, target,
1875
1754
"different serializers")
1878
def _get_repo_format_to_test(self):
1882
def is_compatible(cls, source, target):
1883
# The default implementation is compatible with everything
1887
InterRepository.register_optimiser(InterRepository)
1890
1757
class CopyConverter(object):
1891
1758
"""A repository conversion tool which just performs a copy of the content.