1830
1831
def get_inventory(self, revision_id):
1831
1832
return list(self.iter_inventories([revision_id]))[0]
1834
def _iter_inventories_rpc(self, revision_ids, ordering):
1835
if ordering is None:
1836
ordering = 'unordered'
1837
path = self.bzrdir._path_for_remote_call(self._client)
1838
body = "\n".join(revision_ids)
1839
response_tuple, response_handler = (
1840
self._call_with_body_bytes_expecting_body(
1841
"VersionedFileRepository.get_inventories",
1842
(path, ordering), body))
1843
if response_tuple[0] != "ok":
1844
raise errors.UnexpectedSmartServerResponse(response_tuple)
1845
deserializer = inventory_delta.InventoryDeltaDeserializer()
1846
byte_stream = response_handler.read_streamed_body()
1847
decoded = smart_repo._byte_stream_to_stream(byte_stream)
1849
# no results whatsoever
1851
src_format, stream = decoded
1852
if src_format.network_name() != self._format.network_name():
1853
raise AssertionError(
1854
"Mismatched RemoteRepository and stream src %r, %r" % (
1855
src_format.network_name(), self._format.network_name()))
1856
# ignore the src format, it's not really relevant
1857
prev_inv = Inventory(root_id=None,
1858
revision_id=_mod_revision.NULL_REVISION)
1859
# there should be just one substream, with inventory deltas
1860
substream_kind, substream = stream.next()
1861
if substream_kind != "inventory-deltas":
1862
raise AssertionError(
1863
"Unexpected stream %r received" % substream_kind)
1864
for record in substream:
1865
(parent_id, new_id, versioned_root, tree_references, invdelta) = (
1866
deserializer.parse_text_bytes(record.get_bytes_as("fulltext")))
1867
if parent_id != prev_inv.revision_id:
1868
raise AssertionError("invalid base %r != %r" % (parent_id,
1869
prev_inv.revision_id))
1870
inv = prev_inv.create_by_apply_delta(invdelta, new_id)
1871
yield inv, inv.revision_id
1874
def _iter_inventories_vfs(self, revision_ids, ordering=None):
1876
return self._real_repository._iter_inventories(revision_ids, ordering)
1833
1878
def iter_inventories(self, revision_ids, ordering=None):
1835
return self._real_repository.iter_inventories(revision_ids, ordering)
1879
"""Get many inventories by revision_ids.
1881
This will buffer some or all of the texts used in constructing the
1882
inventories in memory, but will only parse a single inventory at a
1885
:param revision_ids: The expected revision ids of the inventories.
1886
:param ordering: optional ordering, e.g. 'topological'. If not
1887
specified, the order of revision_ids will be preserved (by
1888
buffering if necessary).
1889
:return: An iterator of inventories.
1891
if ((None in revision_ids)
1892
or (_mod_revision.NULL_REVISION in revision_ids)):
1893
raise ValueError('cannot get null revision inventory')
1894
for inv, revid in self._iter_inventories(revision_ids, ordering):
1896
raise errors.NoSuchRevision(self, revid)
1899
def _iter_inventories(self, revision_ids, ordering=None):
1900
if len(revision_ids) == 0:
1902
missing = set(revision_ids)
1903
if ordering is None:
1904
order_as_requested = True
1906
order = list(revision_ids)
1908
next_revid = order.pop()
1910
order_as_requested = False
1911
if ordering != 'unordered' and self._fallback_repositories:
1912
raise ValueError('unsupported ordering %r' % ordering)
1913
iter_inv_fns = [self._iter_inventories_rpc] + [
1914
fallback._iter_inventories for fallback in
1915
self._fallback_repositories]
1917
for iter_inv in iter_inv_fns:
1918
request = [revid for revid in revision_ids if revid in missing]
1919
for inv, revid in iter_inv(request, ordering):
1922
missing.remove(inv.revision_id)
1923
if ordering != 'unordered':
1927
if order_as_requested:
1928
# Yield as many results as we can while preserving order.
1929
while next_revid in invs:
1930
inv = invs.pop(next_revid)
1931
yield inv, inv.revision_id
1933
next_revid = order.pop()
1935
# We still want to fully consume the stream, just
1936
# in case it is not actually finished at this point
1939
except errors.UnknownSmartMethod:
1940
for inv, revid in self._iter_inventories_vfs(revision_ids, ordering):
1944
if order_as_requested:
1945
if next_revid is not None:
1946
yield None, next_revid
1949
yield invs.get(revid), revid
1952
yield None, missing.pop()
1837
1954
@needs_read_lock
1838
1955
def get_revision(self, revision_id):
2235
2354
revids.update(set(fallback.all_revision_ids()))
2236
2355
return list(revids)
2357
def _filtered_revision_trees(self, revision_ids, file_ids):
2358
"""Return Tree for a revision on this branch with only some files.
2360
:param revision_ids: a sequence of revision-ids;
2361
a revision-id may not be None or 'null:'
2362
:param file_ids: if not None, the result is filtered
2363
so that only those file-ids, their parents and their
2364
children are included.
2366
inventories = self.iter_inventories(revision_ids)
2367
for inv in inventories:
2368
# Should we introduce a FilteredRevisionTree class rather
2369
# than pre-filter the inventory here?
2370
filtered_inv = inv.filter(file_ids)
2371
yield InventoryRevisionTree(self, filtered_inv, filtered_inv.revision_id)
2238
2373
@needs_read_lock
2239
2374
def get_deltas_for_revisions(self, revisions, specific_fileids=None):
2241
return self._real_repository.get_deltas_for_revisions(revisions,
2242
specific_fileids=specific_fileids)
2375
medium = self._client._medium
2376
if medium._is_remote_before((1, 2)):
2378
for delta in self._real_repository.get_deltas_for_revisions(
2379
revisions, specific_fileids):
2382
# Get the revision-ids of interest
2383
required_trees = set()
2384
for revision in revisions:
2385
required_trees.add(revision.revision_id)
2386
required_trees.update(revision.parent_ids[:1])
2388
# Get the matching filtered trees. Note that it's more
2389
# efficient to pass filtered trees to changes_from() rather
2390
# than doing the filtering afterwards. changes_from() could
2391
# arguably do the filtering itself but it's path-based, not
2392
# file-id based, so filtering before or afterwards is
2394
if specific_fileids is None:
2395
trees = dict((t.get_revision_id(), t) for
2396
t in self.revision_trees(required_trees))
2398
trees = dict((t.get_revision_id(), t) for
2399
t in self._filtered_revision_trees(required_trees,
2402
# Calculate the deltas
2403
for revision in revisions:
2404
if not revision.parent_ids:
2405
old_tree = self.revision_tree(_mod_revision.NULL_REVISION)
2407
old_tree = trees[revision.parent_ids[0]]
2408
yield trees[revision.revision_id].changes_from(old_tree)
2244
2410
@needs_read_lock
2245
2411
def get_revision_delta(self, revision_id, specific_fileids=None):