490
494
self._next_open_branch_result = None
491
495
return _mod_bzrdir.BzrDir.break_lock(self)
497
def _vfs_checkout_metadir(self):
499
return self._real_bzrdir.checkout_metadir()
501
def checkout_metadir(self):
502
"""Retrieve the controldir format to use for checkouts of this one.
504
medium = self._client._medium
505
if medium._is_remote_before((2, 5)):
506
return self._vfs_checkout_metadir()
507
path = self._path_for_remote_call(self._client)
509
response = self._client.call('BzrDir.checkout_metadir',
511
except errors.UnknownSmartMethod:
512
medium._remember_remote_is_before((2, 5))
513
return self._vfs_checkout_metadir()
514
if len(response) != 3:
515
raise errors.UnexpectedSmartServerResponse(response)
516
control_name, repo_name, branch_name = response
518
format = controldir.network_format_registry.get(control_name)
520
raise errors.UnknownFormatError(kind='control',
524
repo_format = _mod_repository.network_format_registry.get(
527
raise errors.UnknownFormatError(kind='repository',
529
format.repository_format = repo_format
532
format.set_branch_format(
533
branch.network_format_registry.get(branch_name))
535
raise errors.UnknownFormatError(kind='branch',
493
539
def _vfs_cloning_metadir(self, require_stacking=False):
494
540
self._ensure_real()
495
541
return self._real_bzrdir.cloning_metadir(
1720
1768
def get_commit_builder(self, branch, parents, config, timestamp=None,
1721
1769
timezone=None, committer=None, revprops=None,
1722
1770
revision_id=None, lossy=False):
1723
# FIXME: It ought to be possible to call this without immediately
1724
# triggering _ensure_real. For now it's the easiest thing to do.
1726
real_repo = self._real_repository
1727
builder = real_repo.get_commit_builder(branch, parents,
1728
config, timestamp=timestamp, timezone=timezone,
1729
committer=committer, revprops=revprops,
1730
revision_id=revision_id, lossy=lossy)
1771
"""Obtain a CommitBuilder for this repository.
1773
:param branch: Branch to commit to.
1774
:param parents: Revision ids of the parents of the new revision.
1775
:param config: Configuration to use.
1776
:param timestamp: Optional timestamp recorded for commit.
1777
:param timezone: Optional timezone for timestamp.
1778
:param committer: Optional committer to set for commit.
1779
:param revprops: Optional dictionary of revision properties.
1780
:param revision_id: Optional revision id.
1781
:param lossy: Whether to discard data that can not be natively
1782
represented, when pushing to a foreign VCS
1784
if self._fallback_repositories and not self._format.supports_chks:
1785
raise errors.BzrError("Cannot commit directly to a stacked branch"
1786
" in pre-2a formats. See "
1787
"https://bugs.launchpad.net/bzr/+bug/375013 for details.")
1788
if self._format.rich_root_data:
1789
commit_builder_kls = vf_repository.VersionedFileRootCommitBuilder
1791
commit_builder_kls = vf_repository.VersionedFileCommitBuilder
1792
result = commit_builder_kls(self, parents, config,
1793
timestamp, timezone, committer, revprops, revision_id,
1795
self.start_write_group()
1733
1798
def add_fallback_repository(self, repository):
1734
1799
"""Add a repository to use for looking up data not held locally.
1779
1844
delta, new_revision_id, parents, basis_inv=basis_inv,
1780
1845
propagate_caches=propagate_caches)
1782
def add_revision(self, rev_id, rev, inv=None, config=None):
1784
return self._real_repository.add_revision(
1785
rev_id, rev, inv=inv, config=config)
1847
def add_revision(self, revision_id, rev, inv=None):
1848
_mod_revision.check_not_reserved_id(revision_id)
1849
key = (revision_id,)
1850
# check inventory present
1851
if not self.inventories.get_parent_map([key]):
1853
raise errors.WeaveRevisionNotPresent(revision_id,
1856
# yes, this is not suitable for adding with ghosts.
1857
rev.inventory_sha1 = self.add_inventory(revision_id, inv,
1860
rev.inventory_sha1 = self.inventories.get_sha1s([key])[key]
1861
self._add_revision(rev)
1863
def _add_revision(self, rev):
1864
if self._real_repository is not None:
1865
return self._real_repository._add_revision(rev)
1866
text = self._serializer.write_revision_to_string(rev)
1867
key = (rev.revision_id,)
1868
parents = tuple((parent,) for parent in rev.parent_ids)
1869
self._write_group_tokens, missing_keys = self._get_sink().insert_stream(
1870
[('revisions', [FulltextContentFactory(key, parents, None, text)])],
1871
self._format, self._write_group_tokens)
1787
1873
@needs_read_lock
1788
1874
def get_inventory(self, revision_id):
1789
1875
return list(self.iter_inventories([revision_id]))[0]
1877
def _iter_inventories_rpc(self, revision_ids, ordering):
1878
if ordering is None:
1879
ordering = 'unordered'
1880
path = self.bzrdir._path_for_remote_call(self._client)
1881
body = "\n".join(revision_ids)
1882
response_tuple, response_handler = (
1883
self._call_with_body_bytes_expecting_body(
1884
"VersionedFileRepository.get_inventories",
1885
(path, ordering), body))
1886
if response_tuple[0] != "ok":
1887
raise errors.UnexpectedSmartServerResponse(response_tuple)
1888
deserializer = inventory_delta.InventoryDeltaDeserializer()
1889
byte_stream = response_handler.read_streamed_body()
1890
decoded = smart_repo._byte_stream_to_stream(byte_stream)
1892
# no results whatsoever
1894
src_format, stream = decoded
1895
if src_format.network_name() != self._format.network_name():
1896
raise AssertionError(
1897
"Mismatched RemoteRepository and stream src %r, %r" % (
1898
src_format.network_name(), self._format.network_name()))
1899
# ignore the src format, it's not really relevant
1900
prev_inv = Inventory(root_id=None,
1901
revision_id=_mod_revision.NULL_REVISION)
1902
# there should be just one substream, with inventory deltas
1903
substream_kind, substream = stream.next()
1904
if substream_kind != "inventory-deltas":
1905
raise AssertionError(
1906
"Unexpected stream %r received" % substream_kind)
1907
for record in substream:
1908
(parent_id, new_id, versioned_root, tree_references, invdelta) = (
1909
deserializer.parse_text_bytes(record.get_bytes_as("fulltext")))
1910
if parent_id != prev_inv.revision_id:
1911
raise AssertionError("invalid base %r != %r" % (parent_id,
1912
prev_inv.revision_id))
1913
inv = prev_inv.create_by_apply_delta(invdelta, new_id)
1914
yield inv, inv.revision_id
1917
def _iter_inventories_vfs(self, revision_ids, ordering=None):
1919
return self._real_repository._iter_inventories(revision_ids, ordering)
1791
1921
def iter_inventories(self, revision_ids, ordering=None):
1793
return self._real_repository.iter_inventories(revision_ids, ordering)
1922
"""Get many inventories by revision_ids.
1924
This will buffer some or all of the texts used in constructing the
1925
inventories in memory, but will only parse a single inventory at a
1928
:param revision_ids: The expected revision ids of the inventories.
1929
:param ordering: optional ordering, e.g. 'topological'. If not
1930
specified, the order of revision_ids will be preserved (by
1931
buffering if necessary).
1932
:return: An iterator of inventories.
1934
if ((None in revision_ids)
1935
or (_mod_revision.NULL_REVISION in revision_ids)):
1936
raise ValueError('cannot get null revision inventory')
1937
for inv, revid in self._iter_inventories(revision_ids, ordering):
1939
raise errors.NoSuchRevision(self, revid)
1942
def _iter_inventories(self, revision_ids, ordering=None):
1943
if len(revision_ids) == 0:
1945
missing = set(revision_ids)
1946
if ordering is None:
1947
order_as_requested = True
1949
order = list(revision_ids)
1951
next_revid = order.pop()
1953
order_as_requested = False
1954
if ordering != 'unordered' and self._fallback_repositories:
1955
raise ValueError('unsupported ordering %r' % ordering)
1956
iter_inv_fns = [self._iter_inventories_rpc] + [
1957
fallback._iter_inventories for fallback in
1958
self._fallback_repositories]
1960
for iter_inv in iter_inv_fns:
1961
request = [revid for revid in revision_ids if revid in missing]
1962
for inv, revid in iter_inv(request, ordering):
1965
missing.remove(inv.revision_id)
1966
if ordering != 'unordered':
1970
if order_as_requested:
1971
# Yield as many results as we can while preserving order.
1972
while next_revid in invs:
1973
inv = invs.pop(next_revid)
1974
yield inv, inv.revision_id
1976
next_revid = order.pop()
1978
# We still want to fully consume the stream, just
1979
# in case it is not actually finished at this point
1982
except errors.UnknownSmartMethod:
1983
for inv, revid in self._iter_inventories_vfs(revision_ids, ordering):
1987
if order_as_requested:
1988
if next_revid is not None:
1989
yield None, next_revid
1992
yield invs.get(revid), revid
1995
yield None, missing.pop()
1795
1997
@needs_read_lock
1796
1998
def get_revision(self, revision_id):
2193
2400
revids.update(set(fallback.all_revision_ids()))
2194
2401
return list(revids)
2403
def _filtered_revision_trees(self, revision_ids, file_ids):
2404
"""Return Tree for a revision on this branch with only some files.
2406
:param revision_ids: a sequence of revision-ids;
2407
a revision-id may not be None or 'null:'
2408
:param file_ids: if not None, the result is filtered
2409
so that only those file-ids, their parents and their
2410
children are included.
2412
inventories = self.iter_inventories(revision_ids)
2413
for inv in inventories:
2414
# Should we introduce a FilteredRevisionTree class rather
2415
# than pre-filter the inventory here?
2416
filtered_inv = inv.filter(file_ids)
2417
yield InventoryRevisionTree(self, filtered_inv, filtered_inv.revision_id)
2196
2419
@needs_read_lock
2197
2420
def get_deltas_for_revisions(self, revisions, specific_fileids=None):
2199
return self._real_repository.get_deltas_for_revisions(revisions,
2200
specific_fileids=specific_fileids)
2421
medium = self._client._medium
2422
if medium._is_remote_before((1, 2)):
2424
for delta in self._real_repository.get_deltas_for_revisions(
2425
revisions, specific_fileids):
2428
# Get the revision-ids of interest
2429
required_trees = set()
2430
for revision in revisions:
2431
required_trees.add(revision.revision_id)
2432
required_trees.update(revision.parent_ids[:1])
2434
# Get the matching filtered trees. Note that it's more
2435
# efficient to pass filtered trees to changes_from() rather
2436
# than doing the filtering afterwards. changes_from() could
2437
# arguably do the filtering itself but it's path-based, not
2438
# file-id based, so filtering before or afterwards is
2440
if specific_fileids is None:
2441
trees = dict((t.get_revision_id(), t) for
2442
t in self.revision_trees(required_trees))
2444
trees = dict((t.get_revision_id(), t) for
2445
t in self._filtered_revision_trees(required_trees,
2448
# Calculate the deltas
2449
for revision in revisions:
2450
if not revision.parent_ids:
2451
old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
2453
old_tree = trees[revision.parent_ids[0]]
2454
yield trees[revision.revision_id].changes_from(old_tree)
2202
2456
@needs_read_lock
2203
2457
def get_revision_delta(self, revision_id, specific_fileids=None):