62
63
except errors.ErrorFromSmartServer, err:
63
64
self._translate_error(err, **err_context)
65
def _call_with_body_bytes(self, method, args, body_bytes, **err_context):
67
return self._client.call_with_body_bytes(method, args, body_bytes)
68
except errors.ErrorFromSmartServer, err:
69
self._translate_error(err, **err_context)
71
66
def _call_with_body_bytes_expecting_body(self, method, args, body_bytes,
112
106
self._client = client._SmartClient(medium)
114
108
self._client = _client
121
return '%s(%r)' % (self.__class__.__name__, self._client)
123
def _probe_bzrdir(self):
124
medium = self._client._medium
125
111
path = self._path_for_remote_call(self._client)
126
if medium._is_remote_before((2, 1)):
130
self._rpc_open_2_1(path)
132
except errors.UnknownSmartMethod:
133
medium._remember_remote_is_before((2, 1))
136
def _rpc_open_2_1(self, path):
137
response = self._call('BzrDir.open_2.1', path)
138
if response == ('no',):
139
raise errors.NotBranchError(path=self.root_transport.base)
140
elif response[0] == 'yes':
141
if response[1] == 'yes':
142
self._has_working_tree = True
143
elif response[1] == 'no':
144
self._has_working_tree = False
146
raise errors.UnexpectedSmartServerResponse(response)
148
raise errors.UnexpectedSmartServerResponse(response)
150
def _rpc_open(self, path):
151
112
response = self._call('BzrDir.open', path)
152
113
if response not in [('yes',), ('no',)]:
153
114
raise errors.UnexpectedSmartServerResponse(response)
154
115
if response == ('no',):
155
raise errors.NotBranchError(path=self.root_transport.base)
116
raise errors.NotBranchError(path=transport.base)
157
118
def _ensure_real(self):
158
119
"""Ensure that there is a _real_bzrdir set.
245
202
self._ensure_real()
246
203
self._real_bzrdir.destroy_repository()
248
def create_branch(self, name=None):
205
def create_branch(self):
249
206
# as per meta1 formats - just delegate to the format object which may
250
207
# be parameterised.
251
real_branch = self._format.get_branch_format().initialize(self,
208
real_branch = self._format.get_branch_format().initialize(self)
253
209
if not isinstance(real_branch, RemoteBranch):
254
result = RemoteBranch(self, self.find_repository(), real_branch,
210
result = RemoteBranch(self, self.find_repository(), real_branch)
257
212
result = real_branch
258
213
# BzrDir.clone_on_transport() uses the result of create_branch but does
264
219
self._next_open_branch_result = result
267
def destroy_branch(self, name=None):
222
def destroy_branch(self):
268
223
"""See BzrDir.destroy_branch"""
269
224
self._ensure_real()
270
self._real_bzrdir.destroy_branch(name=name)
225
self._real_bzrdir.destroy_branch()
271
226
self._next_open_branch_result = None
273
228
def create_workingtree(self, revision_id=None, from_branch=None):
274
229
raise errors.NotLocalUrl(self.transport.base)
276
def find_branch_format(self, name=None):
231
def find_branch_format(self):
277
232
"""Find the branch 'format' for this bzrdir.
279
234
This might be a synthetic object for e.g. RemoteBranch and SVN.
281
b = self.open_branch(name=name)
236
b = self.open_branch()
284
def get_branch_reference(self, name=None):
239
def get_branch_reference(self):
285
240
"""See BzrDir.get_branch_reference()."""
287
# XXX JRV20100304: Support opening colocated branches
288
raise errors.NoColocatedBranchSupport(self)
289
241
response = self._get_branch_reference()
290
242
if response[0] == 'ref':
291
243
return response[1]
295
247
def _get_branch_reference(self):
296
248
path = self._path_for_remote_call(self._client)
297
249
medium = self._client._medium
299
('BzrDir.open_branchV3', (2, 1)),
300
('BzrDir.open_branchV2', (1, 13)),
301
('BzrDir.open_branch', None),
303
for verb, required_version in candidate_calls:
304
if required_version and medium._is_remote_before(required_version):
250
if not medium._is_remote_before((1, 13)):
307
response = self._call(verb, path)
252
response = self._call('BzrDir.open_branchV2', path)
253
if response[0] not in ('ref', 'branch'):
254
raise errors.UnexpectedSmartServerResponse(response)
308
256
except errors.UnknownSmartMethod:
309
if required_version is None:
311
medium._remember_remote_is_before(required_version)
314
if verb == 'BzrDir.open_branch':
315
if response[0] != 'ok':
316
raise errors.UnexpectedSmartServerResponse(response)
317
if response[1] != '':
318
return ('ref', response[1])
320
return ('branch', '')
321
if response[0] not in ('ref', 'branch'):
257
medium._remember_remote_is_before((1, 13))
258
response = self._call('BzrDir.open_branch', path)
259
if response[0] != 'ok':
322
260
raise errors.UnexpectedSmartServerResponse(response)
261
if response[1] != '':
262
return ('ref', response[1])
264
return ('branch', '')
325
def _get_tree_branch(self, name=None):
266
def _get_tree_branch(self):
326
267
"""See BzrDir._get_tree_branch()."""
327
return None, self.open_branch(name=name)
268
return None, self.open_branch()
329
def open_branch(self, name=None, unsupported=False,
330
ignore_fallbacks=False):
270
def open_branch(self, _unsupported=False, ignore_fallbacks=False):
332
272
raise NotImplementedError('unsupported flag support not implemented yet.')
333
273
if self._next_open_branch_result is not None:
334
274
# See create_branch for details.
339
279
if response[0] == 'ref':
340
280
# a branch reference, use the existing BranchReference logic.
341
281
format = BranchReferenceFormat()
342
return format.open(self, name=name, _found=True,
343
location=response[1], ignore_fallbacks=ignore_fallbacks)
282
return format.open(self, _found=True, location=response[1],
283
ignore_fallbacks=ignore_fallbacks)
344
284
branch_format_name = response[1]
345
285
if not branch_format_name:
346
286
branch_format_name = None
347
287
format = RemoteBranchFormat(network_name=branch_format_name)
348
288
return RemoteBranch(self, self.find_repository(), format=format,
349
setup_stacking=not ignore_fallbacks, name=name)
289
setup_stacking=not ignore_fallbacks)
351
291
def _open_repo_v1(self, path):
352
292
verb = 'BzrDir.find_repository'
624
547
return self._custom_format._fetch_reconcile
626
549
def get_format_description(self):
628
return 'Remote: ' + self._custom_format.get_format_description()
550
return 'bzr remote repository'
630
552
def __eq__(self, other):
631
553
return self.__class__ is other.__class__
555
def check_conversion_target(self, target_format):
556
if self.rich_root_data and not target_format.rich_root_data:
557
raise errors.BadConversionTarget(
558
'Does not support rich root data.', target_format)
559
if (self.supports_tree_reference and
560
not getattr(target_format, 'supports_tree_reference', False)):
561
raise errors.BadConversionTarget(
562
'Does not support nested trees', target_format)
633
564
def network_name(self):
634
565
if self._network_name:
635
566
return self._network_name
756
670
self._ensure_real()
757
671
return self._real_repository.suspend_write_group()
759
def get_missing_parent_inventories(self, check_for_missing_texts=True):
761
return self._real_repository.get_missing_parent_inventories(
762
check_for_missing_texts=check_for_missing_texts)
764
def _get_rev_id_for_revno_vfs(self, revno, known_pair):
766
return self._real_repository.get_rev_id_for_revno(
769
def get_rev_id_for_revno(self, revno, known_pair):
770
"""See Repository.get_rev_id_for_revno."""
771
path = self.bzrdir._path_for_remote_call(self._client)
773
if self._client._medium._is_remote_before((1, 17)):
774
return self._get_rev_id_for_revno_vfs(revno, known_pair)
775
response = self._call(
776
'Repository.get_rev_id_for_revno', path, revno, known_pair)
777
except errors.UnknownSmartMethod:
778
self._client._medium._remember_remote_is_before((1, 17))
779
return self._get_rev_id_for_revno_vfs(revno, known_pair)
780
if response[0] == 'ok':
781
return True, response[1]
782
elif response[0] == 'history-incomplete':
783
known_pair = response[1:3]
784
for fallback in self._fallback_repositories:
785
found, result = fallback.get_rev_id_for_revno(revno, known_pair)
790
# Not found in any fallbacks
791
return False, known_pair
793
raise errors.UnexpectedSmartServerResponse(response)
673
def get_missing_parent_inventories(self):
675
return self._real_repository.get_missing_parent_inventories()
795
677
def _ensure_real(self):
796
678
"""Ensure that there is a _real_repository set.
896
778
result.add(_mod_revision.NULL_REVISION)
899
def _has_same_fallbacks(self, other_repo):
900
"""Returns true if the repositories have the same fallbacks."""
901
# XXX: copied from Repository; it should be unified into a base class
902
# <https://bugs.edge.launchpad.net/bzr/+bug/401622>
903
my_fb = self._fallback_repositories
904
other_fb = other_repo._fallback_repositories
905
if len(my_fb) != len(other_fb):
907
for f, g in zip(my_fb, other_fb):
908
if not f.has_same_location(g):
912
781
def has_same_location(self, other):
913
# TODO: Move to RepositoryBase and unify with the regular Repository
914
# one; unfortunately the tests rely on slightly different behaviour at
915
# present -- mbp 20090710
916
782
return (self.__class__ is other.__class__ and
917
783
self.bzrdir.transport.base == other.bzrdir.transport.base)
921
787
parents_provider = self._make_parents_provider(other_repository)
922
788
return graph.Graph(parents_provider)
925
def get_known_graph_ancestry(self, revision_ids):
926
"""Return the known graph for a set of revision ids and their ancestors.
928
st = static_tuple.StaticTuple
929
revision_keys = [st(r_id).intern() for r_id in revision_ids]
930
known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
931
return graph.GraphThunkIdsToKeys(known_graph)
933
790
def gather_stats(self, revid=None, committers=None):
934
791
"""See Repository.gather_stats()."""
935
792
path = self.bzrdir._path_for_remote_call(self._client)
995
852
def is_write_locked(self):
996
853
return self._lock_mode == 'w'
998
def _warn_if_deprecated(self, branch=None):
999
# If we have a real repository, the check will be done there, if we
1000
# don't the check will be done remotely.
1003
855
def lock_read(self):
1004
"""Lock the repository for read operations.
1006
:return: A bzrlib.lock.LogicalLockResult.
1008
856
# wrong eventually - want a local lock cache context
1009
857
if not self._lock_mode:
1010
self._note_lock('r')
1011
858
self._lock_mode = 'r'
1012
859
self._lock_count = 1
1013
860
self._unstacked_provider.enable_cache(cache_misses=True)
1014
861
if self._real_repository is not None:
1015
862
self._real_repository.lock_read()
1016
for repo in self._fallback_repositories:
1019
864
self._lock_count += 1
1020
return lock.LogicalLockResult(self.unlock)
865
for repo in self._fallback_repositories:
1022
868
def _remote_lock_write(self, token):
1023
869
path = self.bzrdir._path_for_remote_call(self._client)
1244
1084
# We need to accumulate additional repositories here, to pass them in
1245
1085
# on various RPC's.
1247
if self.is_locked():
1248
# We will call fallback.unlock() when we transition to the unlocked
1249
# state, so always add a lock here. If a caller passes us a locked
1250
# repository, they are responsible for unlocking it later.
1251
repository.lock_read()
1252
self._check_fallback_repository(repository)
1253
1087
self._fallback_repositories.append(repository)
1254
1088
# If self._real_repository was parameterised already (e.g. because a
1255
1089
# _real_branch had its get_stacked_on_url method called), then the
1256
1090
# repository to be added may already be in the _real_repositories list.
1257
1091
if self._real_repository is not None:
1258
fallback_locations = [repo.user_url for repo in
1092
fallback_locations = [repo.bzrdir.root_transport.base for repo in
1259
1093
self._real_repository._fallback_repositories]
1260
if repository.user_url not in fallback_locations:
1094
if repository.bzrdir.root_transport.base not in fallback_locations:
1261
1095
self._real_repository.add_fallback_repository(repository)
1263
def _check_fallback_repository(self, repository):
1264
"""Check that this repository can fallback to repository safely.
1266
Raise an error if not.
1268
:param repository: A repository to fallback to.
1270
return _mod_repository.InterRepository._assert_same_model(
1273
1097
def add_inventory(self, revid, inv, parents):
1274
1098
self._ensure_real()
1275
1099
return self._real_repository.add_inventory(revid, inv, parents)
1277
1101
def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1278
parents, basis_inv=None, propagate_caches=False):
1279
1103
self._ensure_real()
1280
1104
return self._real_repository.add_inventory_by_delta(basis_revision_id,
1281
delta, new_revision_id, parents, basis_inv=basis_inv,
1282
propagate_caches=propagate_caches)
1105
delta, new_revision_id, parents)
1284
1107
def add_revision(self, rev_id, rev, inv=None, config=None):
1285
1108
self._ensure_real()
1315
1138
return self._real_repository.make_working_trees()
1317
1140
def refresh_data(self):
1318
"""Re-read any data needed to synchronise with disk.
1141
"""Re-read any data needed to to synchronise with disk.
1320
1143
This method is intended to be called after another repository instance
1321
1144
(such as one used by a smart server) has inserted data into the
1322
repository. On all repositories this will work outside of write groups.
1323
Some repository formats (pack and newer for bzrlib native formats)
1324
support refresh_data inside write groups. If called inside a write
1325
group on a repository that does not support refreshing in a write group
1326
IsInWriteGroupError will be raised.
1145
repository. It may not be called during a write group, but may be
1146
called at any other time.
1148
if self.is_in_write_group():
1149
raise errors.InternalBzrError(
1150
"May not refresh_data while in a write group.")
1328
1151
if self._real_repository is not None:
1329
1152
self._real_repository.refresh_data()
1791
1614
def insert_stream(self, stream, src_format, resume_tokens):
1792
1615
target = self.target_repo
1793
1616
target._unstacked_provider.missing_keys.clear()
1794
candidate_calls = [('Repository.insert_stream_1.19', (1, 19))]
1795
1617
if target._lock_token:
1796
candidate_calls.append(('Repository.insert_stream_locked', (1, 14)))
1797
lock_args = (target._lock_token or '',)
1618
verb = 'Repository.insert_stream_locked'
1619
extra_args = (target._lock_token or '',)
1620
required_version = (1, 14)
1799
candidate_calls.append(('Repository.insert_stream', (1, 13)))
1622
verb = 'Repository.insert_stream'
1624
required_version = (1, 13)
1801
1625
client = target._client
1802
1626
medium = client._medium
1627
if medium._is_remote_before(required_version):
1628
# No possible way this can work.
1629
return self._insert_real(stream, src_format, resume_tokens)
1803
1630
path = target.bzrdir._path_for_remote_call(client)
1804
# Probe for the verb to use with an empty stream before sending the
1805
# real stream to it. We do this both to avoid the risk of sending a
1806
# large request that is then rejected, and because we don't want to
1807
# implement a way to buffer, rewind, or restart the stream.
1809
for verb, required_version in candidate_calls:
1810
if medium._is_remote_before(required_version):
1813
# We've already done the probing (and set _is_remote_before) on
1814
# a previous insert.
1631
if not resume_tokens:
1632
# XXX: Ugly but important for correctness, *will* be fixed during
1633
# 1.13 cycle. Pushing a stream that is interrupted results in a
1634
# fallback to the _real_repositories sink *with a partial stream*.
1635
# Thats bad because we insert less data than bzr expected. To avoid
1636
# this we do a trial push to make sure the verb is accessible, and
1637
# do not fallback when actually pushing the stream. A cleanup patch
1638
# is going to look at rewinding/restarting the stream/partial
1817
1640
byte_stream = smart_repo._stream_to_byte_stream([], src_format)
1819
1642
response = client.call_with_body_stream(
1820
(verb, path, '') + lock_args, byte_stream)
1643
(verb, path, '') + extra_args, byte_stream)
1821
1644
except errors.UnknownSmartMethod:
1822
1645
medium._remember_remote_is_before(required_version)
1828
return self._insert_real(stream, src_format, resume_tokens)
1829
self._last_inv_record = None
1830
self._last_substream = None
1831
if required_version < (1, 19):
1832
# Remote side doesn't support inventory deltas. Wrap the stream to
1833
# make sure we don't send any. If the stream contains inventory
1834
# deltas we'll interrupt the smart insert_stream request and
1836
stream = self._stop_stream_if_inventory_delta(stream)
1646
return self._insert_real(stream, src_format, resume_tokens)
1837
1647
byte_stream = smart_repo._stream_to_byte_stream(
1838
1648
stream, src_format)
1839
1649
resume_tokens = ' '.join(resume_tokens)
1840
1650
response = client.call_with_body_stream(
1841
(verb, path, resume_tokens) + lock_args, byte_stream)
1651
(verb, path, resume_tokens) + extra_args, byte_stream)
1842
1652
if response[0][0] not in ('ok', 'missing-basis'):
1843
1653
raise errors.UnexpectedSmartServerResponse(response)
1844
if self._last_substream is not None:
1845
# The stream included an inventory-delta record, but the remote
1846
# side isn't new enough to support them. So we need to send the
1847
# rest of the stream via VFS.
1848
self.target_repo.refresh_data()
1849
return self._resume_stream_with_vfs(response, src_format)
1850
1654
if response[0][0] == 'missing-basis':
1851
1655
tokens, missing_keys = bencode.bdecode_as_tuple(response[0][1])
1852
1656
resume_tokens = tokens
1855
1659
self.target_repo.refresh_data()
1856
1660
return [], set()
1858
def _resume_stream_with_vfs(self, response, src_format):
1859
"""Resume sending a stream via VFS, first resending the record and
1860
substream that couldn't be sent via an insert_stream verb.
1862
if response[0][0] == 'missing-basis':
1863
tokens, missing_keys = bencode.bdecode_as_tuple(response[0][1])
1864
# Ignore missing_keys, we haven't finished inserting yet
1867
def resume_substream():
1868
# Yield the substream that was interrupted.
1869
for record in self._last_substream:
1871
self._last_substream = None
1872
def resume_stream():
1873
# Finish sending the interrupted substream
1874
yield ('inventory-deltas', resume_substream())
1875
# Then simply continue sending the rest of the stream.
1876
for substream_kind, substream in self._last_stream:
1877
yield substream_kind, substream
1878
return self._insert_real(resume_stream(), src_format, tokens)
1880
def _stop_stream_if_inventory_delta(self, stream):
1881
"""Normally this just lets the original stream pass-through unchanged.
1883
However if any 'inventory-deltas' substream occurs it will stop
1884
streaming, and store the interrupted substream and stream in
1885
self._last_substream and self._last_stream so that the stream can be
1886
resumed by _resume_stream_with_vfs.
1889
stream_iter = iter(stream)
1890
for substream_kind, substream in stream_iter:
1891
if substream_kind == 'inventory-deltas':
1892
self._last_substream = substream
1893
self._last_stream = stream_iter
1896
yield substream_kind, substream
1899
1663
class RemoteStreamSource(repository.StreamSource):
1900
1664
"""Stream data from a remote server."""
1903
1667
if (self.from_repository._fallback_repositories and
1904
1668
self.to_format._fetch_order == 'topological'):
1905
1669
return self._real_stream(self.from_repository, search)
1908
repos = [self.from_repository]
1914
repos.extend(repo._fallback_repositories)
1915
sources.append(repo)
1916
return self.missing_parents_chain(search, sources)
1918
def get_stream_for_missing_keys(self, missing_keys):
1919
self.from_repository._ensure_real()
1920
real_repo = self.from_repository._real_repository
1921
real_source = real_repo._get_source(self.to_format)
1922
return real_source.get_stream_for_missing_keys(missing_keys)
1670
return self.missing_parents_chain(search, [self.from_repository] +
1671
self.from_repository._fallback_repositories)
1924
1673
def _real_stream(self, repo, search):
1925
1674
"""Get a stream for search from repo.
1956
1704
return self._real_stream(repo, search)
1957
1705
client = repo._client
1958
1706
medium = client._medium
1707
if medium._is_remote_before((1, 13)):
1708
# streaming was added in 1.13
1709
return self._real_stream(repo, search)
1959
1710
path = repo.bzrdir._path_for_remote_call(client)
1960
search_bytes = repo._serialise_search_result(search)
1961
args = (path, self.to_format.network_name())
1963
('Repository.get_stream_1.19', (1, 19)),
1964
('Repository.get_stream', (1, 13))]
1966
for verb, version in candidate_verbs:
1967
if medium._is_remote_before(version):
1970
response = repo._call_with_body_bytes_expecting_body(
1971
verb, args, search_bytes)
1972
except errors.UnknownSmartMethod:
1973
medium._remember_remote_is_before(version)
1975
response_tuple, response_handler = response
1712
search_bytes = repo._serialise_search_result(search)
1713
response = repo._call_with_body_bytes_expecting_body(
1714
'Repository.get_stream',
1715
(path, self.to_format.network_name()), search_bytes)
1716
response_tuple, response_handler = response
1717
except errors.UnknownSmartMethod:
1718
medium._remember_remote_is_before((1,13))
1979
1719
return self._real_stream(repo, search)
1980
1720
if response_tuple[0] != 'ok':
1981
1721
raise errors.UnexpectedSmartServerResponse(response_tuple)
2062
1801
self._network_name)
2064
1803
def get_format_description(self):
2066
return 'Remote: ' + self._custom_format.get_format_description()
1804
return 'Remote BZR Branch'
2068
1806
def network_name(self):
2069
1807
return self._network_name
2071
def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
2072
return a_bzrdir.open_branch(name=name,
2073
ignore_fallbacks=ignore_fallbacks)
1809
def open(self, a_bzrdir, ignore_fallbacks=False):
1810
return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2075
def _vfs_initialize(self, a_bzrdir, name):
1812
def _vfs_initialize(self, a_bzrdir):
2076
1813
# Initialisation when using a local bzrdir object, or a non-vfs init
2077
1814
# method is not available on the server.
2078
1815
# self._custom_format is always set - the start of initialize ensures
2080
1817
if isinstance(a_bzrdir, RemoteBzrDir):
2081
1818
a_bzrdir._ensure_real()
2082
result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
1819
result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
2085
1821
# We assume the bzrdir is parameterised; it may not be.
2086
result = self._custom_format.initialize(a_bzrdir, name)
1822
result = self._custom_format.initialize(a_bzrdir)
2087
1823
if (isinstance(a_bzrdir, RemoteBzrDir) and
2088
1824
not isinstance(result, RemoteBranch)):
2089
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
1825
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
2093
def initialize(self, a_bzrdir, name=None):
1828
def initialize(self, a_bzrdir):
2094
1829
# 1) get the network name to use.
2095
1830
if self._custom_format:
2096
1831
network_name = self._custom_format.network_name()
2102
1837
network_name = reference_format.network_name()
2103
1838
# Being asked to create on a non RemoteBzrDir:
2104
1839
if not isinstance(a_bzrdir, RemoteBzrDir):
2105
return self._vfs_initialize(a_bzrdir, name=name)
1840
return self._vfs_initialize(a_bzrdir)
2106
1841
medium = a_bzrdir._client._medium
2107
1842
if medium._is_remote_before((1, 13)):
2108
return self._vfs_initialize(a_bzrdir, name=name)
1843
return self._vfs_initialize(a_bzrdir)
2109
1844
# Creating on a remote bzr dir.
2110
1845
# 2) try direct creation via RPC
2111
1846
path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
2112
if name is not None:
2113
# XXX JRV20100304: Support creating colocated branches
2114
raise errors.NoColocatedBranchSupport(self)
2115
1847
verb = 'BzrDir.create_branch'
2117
1849
response = a_bzrdir._call(verb, path, network_name)
2118
1850
except errors.UnknownSmartMethod:
2119
1851
# Fallback - use vfs methods
2120
1852
medium._remember_remote_is_before((1, 13))
2121
return self._vfs_initialize(a_bzrdir, name=name)
1853
return self._vfs_initialize(a_bzrdir)
2122
1854
if response[0] != 'ok':
2123
1855
raise errors.UnexpectedSmartServerResponse(response)
2124
1856
# Turn the response into a RemoteRepository object.
2153
1885
self._ensure_real()
2154
1886
return self._custom_format.supports_stacking()
2156
def supports_set_append_revisions_only(self):
2158
return self._custom_format.supports_set_append_revisions_only()
2161
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
1889
class RemoteBranch(branch.Branch, _RpcHelper):
2162
1890
"""Branch stored on a server accessed by HPSS RPC.
2164
1892
At the moment most operations are mapped down to simple file operations.
2167
1895
def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
2168
_client=None, format=None, setup_stacking=True, name=None):
1896
_client=None, format=None, setup_stacking=True):
2169
1897
"""Create a RemoteBranch instance.
2171
1899
:param real_branch: An optional local implementation of the branch
2177
1905
:param setup_stacking: If True make an RPC call to determine the
2178
1906
stacked (or not) status of the branch. If False assume the branch
2179
1907
is not stacked.
2180
:param name: Colocated branch name
2182
1909
# We intentionally don't call the parent class's __init__, because it
2183
1910
# will try to assign to self.tags, which is a property in this subclass.
2184
1911
# And the parent's __init__ doesn't do much anyway.
1912
self._revision_id_to_revno_cache = None
1913
self._partial_revision_id_to_revno_cache = {}
1914
self._revision_history_cache = None
1915
self._last_revision_info_cache = None
1916
self._merge_sorted_revisions_cache = None
2185
1917
self.bzrdir = remote_bzrdir
2186
1918
if _client is not None:
2187
1919
self._client = _client
2377
2093
return self._vfs_get_tags_bytes()
2378
2094
return response[0]
2380
def _vfs_set_tags_bytes(self, bytes):
2382
return self._real_branch._set_tags_bytes(bytes)
2384
def _set_tags_bytes(self, bytes):
2385
medium = self._client._medium
2386
if medium._is_remote_before((1, 18)):
2387
self._vfs_set_tags_bytes(bytes)
2391
self._remote_path(), self._lock_token, self._repo_lock_token)
2392
response = self._call_with_body_bytes(
2393
'Branch.set_tags_bytes', args, bytes)
2394
except errors.UnknownSmartMethod:
2395
medium._remember_remote_is_before((1, 18))
2396
self._vfs_set_tags_bytes(bytes)
2398
2096
def lock_read(self):
2399
"""Lock the branch for read operations.
2401
:return: A bzrlib.lock.LogicalLockResult.
2403
2097
self.repository.lock_read()
2404
2098
if not self._lock_mode:
2405
self._note_lock('r')
2406
2099
self._lock_mode = 'r'
2407
2100
self._lock_count = 1
2408
2101
if self._real_branch is not None:
2409
2102
self._real_branch.lock_read()
2411
2104
self._lock_count += 1
2412
return lock.LogicalLockResult(self.unlock)
2414
2106
def _remote_lock_write(self, token):
2415
2107
if token is None:
2416
2108
branch_token = repo_token = ''
2418
2110
branch_token = token
2419
repo_token = self.repository.lock_write().repository_token
2111
repo_token = self.repository.lock_write()
2420
2112
self.repository.unlock()
2421
2113
err_context = {'token': token}
2422
2114
response = self._call(
2516
2210
raise NotImplementedError(self.dont_leave_lock_in_place)
2517
2211
self._leave_lock = False
2520
def get_rev_id(self, revno, history=None):
2522
return _mod_revision.NULL_REVISION
2523
last_revision_info = self.last_revision_info()
2524
ok, result = self.repository.get_rev_id_for_revno(
2525
revno, last_revision_info)
2528
missing_parent = result[1]
2529
# Either the revision named by the server is missing, or its parent
2530
# is. Call get_parent_map to determine which, so that we report a
2532
parent_map = self.repository.get_parent_map([missing_parent])
2533
if missing_parent in parent_map:
2534
missing_parent = parent_map[missing_parent]
2535
raise errors.RevisionNotPresent(missing_parent, self.repository)
2537
2213
def _last_revision_info(self):
2538
2214
response = self._call('Branch.last_revision_info', self._remote_path())
2539
2215
if response[0] != 'ok':
2887
2560
'Missing key %r in context %r', key_err.args[0], context)
2890
if err.error_verb == 'IncompatibleRepositories':
2891
raise errors.IncompatibleRepositories(err.error_args[0],
2892
err.error_args[1], err.error_args[2])
2893
elif err.error_verb == 'NoSuchRevision':
2563
if err.error_verb == 'NoSuchRevision':
2894
2564
raise NoSuchRevision(find('branch'), err.error_args[0])
2895
2565
elif err.error_verb == 'nosuchrevision':
2896
2566
raise NoSuchRevision(find('repository'), err.error_args[0])
2897
elif err.error_verb == 'nobranch':
2898
if len(err.error_args) >= 1:
2899
extra = err.error_args[0]
2902
raise errors.NotBranchError(path=find('bzrdir').root_transport.base,
2567
elif err.error_tuple == ('nobranch',):
2568
raise errors.NotBranchError(path=find('bzrdir').root_transport.base)
2904
2569
elif err.error_verb == 'norepository':
2905
2570
raise errors.NoRepositoryPresent(find('bzrdir'))
2906
2571
elif err.error_verb == 'LockContention':