108
114
self._client = client._SmartClient(medium)
110
116
self._client = _client
123
return '%s(%r)' % (self.__class__.__name__, self._client)
125
def _probe_bzrdir(self):
126
medium = self._client._medium
113
127
path = self._path_for_remote_call(self._client)
128
if medium._is_remote_before((2, 1)):
132
self._rpc_open_2_1(path)
134
except errors.UnknownSmartMethod:
135
medium._remember_remote_is_before((2, 1))
138
def _rpc_open_2_1(self, path):
139
response = self._call('BzrDir.open_2.1', path)
140
if response == ('no',):
141
raise errors.NotBranchError(path=self.root_transport.base)
142
elif response[0] == 'yes':
143
if response[1] == 'yes':
144
self._has_working_tree = True
145
elif response[1] == 'no':
146
self._has_working_tree = False
148
raise errors.UnexpectedSmartServerResponse(response)
150
raise errors.UnexpectedSmartServerResponse(response)
152
def _rpc_open(self, path):
114
153
response = self._call('BzrDir.open', path)
115
154
if response not in [('yes',), ('no',)]:
116
155
raise errors.UnexpectedSmartServerResponse(response)
117
156
if response == ('no',):
118
raise errors.NotBranchError(path=transport.base)
157
raise errors.NotBranchError(path=self.root_transport.base)
120
159
def _ensure_real(self):
121
160
"""Ensure that there is a _real_bzrdir set.
204
247
self._ensure_real()
205
248
self._real_bzrdir.destroy_repository()
207
def create_branch(self):
250
def create_branch(self, name=None, repository=None):
208
251
# as per meta1 formats - just delegate to the format object which may
209
252
# be parameterised.
210
real_branch = self._format.get_branch_format().initialize(self)
253
real_branch = self._format.get_branch_format().initialize(self,
254
name=name, repository=repository)
211
255
if not isinstance(real_branch, RemoteBranch):
212
result = RemoteBranch(self, self.find_repository(), real_branch)
256
if not isinstance(repository, RemoteRepository):
257
raise AssertionError(
258
'need a RemoteRepository to use with RemoteBranch, got %r'
260
result = RemoteBranch(self, repository, real_branch, name=name)
214
262
result = real_branch
215
263
# BzrDir.clone_on_transport() uses the result of create_branch but does
221
269
self._next_open_branch_result = result
224
def destroy_branch(self):
272
def destroy_branch(self, name=None):
225
273
"""See BzrDir.destroy_branch"""
226
274
self._ensure_real()
227
self._real_bzrdir.destroy_branch()
275
self._real_bzrdir.destroy_branch(name=name)
228
276
self._next_open_branch_result = None
230
def create_workingtree(self, revision_id=None, from_branch=None):
278
def create_workingtree(self, revision_id=None, from_branch=None,
279
accelerator_tree=None, hardlink=False):
231
280
raise errors.NotLocalUrl(self.transport.base)
233
def find_branch_format(self):
282
def find_branch_format(self, name=None):
234
283
"""Find the branch 'format' for this bzrdir.
236
285
This might be a synthetic object for e.g. RemoteBranch and SVN.
238
b = self.open_branch()
287
b = self.open_branch(name=name)
241
def get_branch_reference(self):
290
def get_branch_reference(self, name=None):
242
291
"""See BzrDir.get_branch_reference()."""
293
# XXX JRV20100304: Support opening colocated branches
294
raise errors.NoColocatedBranchSupport(self)
243
295
response = self._get_branch_reference()
244
296
if response[0] == 'ref':
245
297
return response[1]
249
301
def _get_branch_reference(self):
250
302
path = self._path_for_remote_call(self._client)
251
303
medium = self._client._medium
252
if not medium._is_remote_before((1, 13)):
305
('BzrDir.open_branchV3', (2, 1)),
306
('BzrDir.open_branchV2', (1, 13)),
307
('BzrDir.open_branch', None),
309
for verb, required_version in candidate_calls:
310
if required_version and medium._is_remote_before(required_version):
254
response = self._call('BzrDir.open_branchV2', path)
255
if response[0] not in ('ref', 'branch'):
256
raise errors.UnexpectedSmartServerResponse(response)
313
response = self._call(verb, path)
258
314
except errors.UnknownSmartMethod:
259
medium._remember_remote_is_before((1, 13))
260
response = self._call('BzrDir.open_branch', path)
261
if response[0] != 'ok':
315
if required_version is None:
317
medium._remember_remote_is_before(required_version)
320
if verb == 'BzrDir.open_branch':
321
if response[0] != 'ok':
322
raise errors.UnexpectedSmartServerResponse(response)
323
if response[1] != '':
324
return ('ref', response[1])
326
return ('branch', '')
327
if response[0] not in ('ref', 'branch'):
262
328
raise errors.UnexpectedSmartServerResponse(response)
263
if response[1] != '':
264
return ('ref', response[1])
266
return ('branch', '')
268
def _get_tree_branch(self):
331
def _get_tree_branch(self, name=None):
269
332
"""See BzrDir._get_tree_branch()."""
270
return None, self.open_branch()
333
return None, self.open_branch(name=name)
272
def open_branch(self, _unsupported=False, ignore_fallbacks=False):
335
def open_branch(self, name=None, unsupported=False,
336
ignore_fallbacks=False):
274
338
raise NotImplementedError('unsupported flag support not implemented yet.')
275
339
if self._next_open_branch_result is not None:
276
340
# See create_branch for details.
281
345
if response[0] == 'ref':
282
346
# a branch reference, use the existing BranchReference logic.
283
347
format = BranchReferenceFormat()
284
return format.open(self, _found=True, location=response[1],
285
ignore_fallbacks=ignore_fallbacks)
348
return format.open(self, name=name, _found=True,
349
location=response[1], ignore_fallbacks=ignore_fallbacks)
286
350
branch_format_name = response[1]
287
351
if not branch_format_name:
288
352
branch_format_name = None
289
353
format = RemoteBranchFormat(network_name=branch_format_name)
290
354
return RemoteBranch(self, self.find_repository(), format=format,
291
setup_stacking=not ignore_fallbacks)
355
setup_stacking=not ignore_fallbacks, name=name)
293
357
def _open_repo_v1(self, path):
294
358
verb = 'BzrDir.find_repository'
549
630
return self._custom_format._fetch_reconcile
551
632
def get_format_description(self):
552
return 'bzr remote repository'
634
return 'Remote: ' + self._custom_format.get_format_description()
554
636
def __eq__(self, other):
555
637
return self.__class__ is other.__class__
557
def check_conversion_target(self, target_format):
558
if self.rich_root_data and not target_format.rich_root_data:
559
raise errors.BadConversionTarget(
560
'Does not support rich root data.', target_format)
561
if (self.supports_tree_reference and
562
not getattr(target_format, 'supports_tree_reference', False)):
563
raise errors.BadConversionTarget(
564
'Does not support nested trees', target_format)
566
639
def network_name(self):
567
640
if self._network_name:
568
641
return self._network_name
842
927
parents_provider = self._make_parents_provider(other_repository)
843
928
return graph.Graph(parents_provider)
931
def get_known_graph_ancestry(self, revision_ids):
932
"""Return the known graph for a set of revision ids and their ancestors.
934
st = static_tuple.StaticTuple
935
revision_keys = [st(r_id).intern() for r_id in revision_ids]
936
known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
937
return graph.GraphThunkIdsToKeys(known_graph)
845
939
def gather_stats(self, revid=None, committers=None):
846
940
"""See Repository.gather_stats()."""
847
941
path = self.bzrdir._path_for_remote_call(self._client)
1148
1255
# state, so always add a lock here. If a caller passes us a locked
1149
1256
# repository, they are responsible for unlocking it later.
1150
1257
repository.lock_read()
1258
self._check_fallback_repository(repository)
1151
1259
self._fallback_repositories.append(repository)
1152
1260
# If self._real_repository was parameterised already (e.g. because a
1153
1261
# _real_branch had its get_stacked_on_url method called), then the
1154
1262
# repository to be added may already be in the _real_repositories list.
1155
1263
if self._real_repository is not None:
1156
fallback_locations = [repo.bzrdir.root_transport.base for repo in
1264
fallback_locations = [repo.user_url for repo in
1157
1265
self._real_repository._fallback_repositories]
1158
if repository.bzrdir.root_transport.base not in fallback_locations:
1266
if repository.user_url not in fallback_locations:
1159
1267
self._real_repository.add_fallback_repository(repository)
1269
def _check_fallback_repository(self, repository):
1270
"""Check that this repository can fallback to repository safely.
1272
Raise an error if not.
1274
:param repository: A repository to fallback to.
1276
return _mod_repository.InterRepository._assert_same_model(
1161
1279
def add_inventory(self, revid, inv, parents):
1162
1280
self._ensure_real()
1163
1281
return self._real_repository.add_inventory(revid, inv, parents)
1165
1283
def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1284
parents, basis_inv=None, propagate_caches=False):
1167
1285
self._ensure_real()
1168
1286
return self._real_repository.add_inventory_by_delta(basis_revision_id,
1169
delta, new_revision_id, parents)
1287
delta, new_revision_id, parents, basis_inv=basis_inv,
1288
propagate_caches=propagate_caches)
1171
1290
def add_revision(self, rev_id, rev, inv=None, config=None):
1172
1291
self._ensure_real()
1202
1321
return self._real_repository.make_working_trees()
1204
1323
def refresh_data(self):
1205
"""Re-read any data needed to to synchronise with disk.
1324
"""Re-read any data needed to synchronise with disk.
1207
1326
This method is intended to be called after another repository instance
1208
1327
(such as one used by a smart server) has inserted data into the
1209
repository. It may not be called during a write group, but may be
1210
called at any other time.
1328
repository. On all repositories this will work outside of write groups.
1329
Some repository formats (pack and newer for bzrlib native formats)
1330
support refresh_data inside write groups. If called inside a write
1331
group on a repository that does not support refreshing in a write group
1332
IsInWriteGroupError will be raised.
1212
if self.is_in_write_group():
1213
raise errors.InternalBzrError(
1214
"May not refresh_data while in a write group.")
1215
1334
if self._real_repository is not None:
1216
1335
self._real_repository.refresh_data()
1680
1797
def insert_stream(self, stream, src_format, resume_tokens):
1681
1798
target = self.target_repo
1682
1799
target._unstacked_provider.missing_keys.clear()
1800
candidate_calls = [('Repository.insert_stream_1.19', (1, 19))]
1683
1801
if target._lock_token:
1684
verb = 'Repository.insert_stream_locked'
1685
extra_args = (target._lock_token or '',)
1686
required_version = (1, 14)
1802
candidate_calls.append(('Repository.insert_stream_locked', (1, 14)))
1803
lock_args = (target._lock_token or '',)
1688
verb = 'Repository.insert_stream'
1690
required_version = (1, 13)
1805
candidate_calls.append(('Repository.insert_stream', (1, 13)))
1691
1807
client = target._client
1692
1808
medium = client._medium
1693
if medium._is_remote_before(required_version):
1694
# No possible way this can work.
1695
return self._insert_real(stream, src_format, resume_tokens)
1696
1809
path = target.bzrdir._path_for_remote_call(client)
1697
if not resume_tokens:
1698
# XXX: Ugly but important for correctness, *will* be fixed during
1699
# 1.13 cycle. Pushing a stream that is interrupted results in a
1700
# fallback to the _real_repositories sink *with a partial stream*.
1701
# Thats bad because we insert less data than bzr expected. To avoid
1702
# this we do a trial push to make sure the verb is accessible, and
1703
# do not fallback when actually pushing the stream. A cleanup patch
1704
# is going to look at rewinding/restarting the stream/partial
1810
# Probe for the verb to use with an empty stream before sending the
1811
# real stream to it. We do this both to avoid the risk of sending a
1812
# large request that is then rejected, and because we don't want to
1813
# implement a way to buffer, rewind, or restart the stream.
1815
for verb, required_version in candidate_calls:
1816
if medium._is_remote_before(required_version):
1819
# We've already done the probing (and set _is_remote_before) on
1820
# a previous insert.
1706
1823
byte_stream = smart_repo._stream_to_byte_stream([], src_format)
1708
1825
response = client.call_with_body_stream(
1709
(verb, path, '') + extra_args, byte_stream)
1826
(verb, path, '') + lock_args, byte_stream)
1710
1827
except errors.UnknownSmartMethod:
1711
1828
medium._remember_remote_is_before(required_version)
1712
return self._insert_real(stream, src_format, resume_tokens)
1834
return self._insert_real(stream, src_format, resume_tokens)
1835
self._last_inv_record = None
1836
self._last_substream = None
1837
if required_version < (1, 19):
1838
# Remote side doesn't support inventory deltas. Wrap the stream to
1839
# make sure we don't send any. If the stream contains inventory
1840
# deltas we'll interrupt the smart insert_stream request and
1842
stream = self._stop_stream_if_inventory_delta(stream)
1713
1843
byte_stream = smart_repo._stream_to_byte_stream(
1714
1844
stream, src_format)
1715
1845
resume_tokens = ' '.join(resume_tokens)
1716
1846
response = client.call_with_body_stream(
1717
(verb, path, resume_tokens) + extra_args, byte_stream)
1847
(verb, path, resume_tokens) + lock_args, byte_stream)
1718
1848
if response[0][0] not in ('ok', 'missing-basis'):
1719
1849
raise errors.UnexpectedSmartServerResponse(response)
1850
if self._last_substream is not None:
1851
# The stream included an inventory-delta record, but the remote
1852
# side isn't new enough to support them. So we need to send the
1853
# rest of the stream via VFS.
1854
self.target_repo.refresh_data()
1855
return self._resume_stream_with_vfs(response, src_format)
1720
1856
if response[0][0] == 'missing-basis':
1721
1857
tokens, missing_keys = bencode.bdecode_as_tuple(response[0][1])
1722
1858
resume_tokens = tokens
1725
1861
self.target_repo.refresh_data()
1726
1862
return [], set()
1864
def _resume_stream_with_vfs(self, response, src_format):
1865
"""Resume sending a stream via VFS, first resending the record and
1866
substream that couldn't be sent via an insert_stream verb.
1868
if response[0][0] == 'missing-basis':
1869
tokens, missing_keys = bencode.bdecode_as_tuple(response[0][1])
1870
# Ignore missing_keys, we haven't finished inserting yet
1873
def resume_substream():
1874
# Yield the substream that was interrupted.
1875
for record in self._last_substream:
1877
self._last_substream = None
1878
def resume_stream():
1879
# Finish sending the interrupted substream
1880
yield ('inventory-deltas', resume_substream())
1881
# Then simply continue sending the rest of the stream.
1882
for substream_kind, substream in self._last_stream:
1883
yield substream_kind, substream
1884
return self._insert_real(resume_stream(), src_format, tokens)
1886
def _stop_stream_if_inventory_delta(self, stream):
1887
"""Normally this just lets the original stream pass-through unchanged.
1889
However if any 'inventory-deltas' substream occurs it will stop
1890
streaming, and store the interrupted substream and stream in
1891
self._last_substream and self._last_stream so that the stream can be
1892
resumed by _resume_stream_with_vfs.
1895
stream_iter = iter(stream)
1896
for substream_kind, substream in stream_iter:
1897
if substream_kind == 'inventory-deltas':
1898
self._last_substream = substream
1899
self._last_stream = stream_iter
1902
yield substream_kind, substream
1729
1905
class RemoteStreamSource(repository.StreamSource):
1730
1906
"""Stream data from a remote server."""
1733
1909
if (self.from_repository._fallback_repositories and
1734
1910
self.to_format._fetch_order == 'topological'):
1735
1911
return self._real_stream(self.from_repository, search)
1736
return self.missing_parents_chain(search, [self.from_repository] +
1737
self.from_repository._fallback_repositories)
1914
repos = [self.from_repository]
1920
repos.extend(repo._fallback_repositories)
1921
sources.append(repo)
1922
return self.missing_parents_chain(search, sources)
1924
def get_stream_for_missing_keys(self, missing_keys):
1925
self.from_repository._ensure_real()
1926
real_repo = self.from_repository._real_repository
1927
real_source = real_repo._get_source(self.to_format)
1928
return real_source.get_stream_for_missing_keys(missing_keys)
1739
1930
def _real_stream(self, repo, search):
1740
1931
"""Get a stream for search from repo.
1770
1962
return self._real_stream(repo, search)
1771
1963
client = repo._client
1772
1964
medium = client._medium
1773
if medium._is_remote_before((1, 13)):
1774
# streaming was added in 1.13
1775
return self._real_stream(repo, search)
1776
1965
path = repo.bzrdir._path_for_remote_call(client)
1778
search_bytes = repo._serialise_search_result(search)
1779
response = repo._call_with_body_bytes_expecting_body(
1780
'Repository.get_stream',
1781
(path, self.to_format.network_name()), search_bytes)
1782
response_tuple, response_handler = response
1783
except errors.UnknownSmartMethod:
1784
medium._remember_remote_is_before((1,13))
1966
search_bytes = repo._serialise_search_result(search)
1967
args = (path, self.to_format.network_name())
1969
('Repository.get_stream_1.19', (1, 19)),
1970
('Repository.get_stream', (1, 13))]
1972
for verb, version in candidate_verbs:
1973
if medium._is_remote_before(version):
1976
response = repo._call_with_body_bytes_expecting_body(
1977
verb, args, search_bytes)
1978
except errors.UnknownSmartMethod:
1979
medium._remember_remote_is_before(version)
1981
response_tuple, response_handler = response
1785
1985
return self._real_stream(repo, search)
1786
1986
if response_tuple[0] != 'ok':
1787
1987
raise errors.UnexpectedSmartServerResponse(response_tuple)
1788
1988
byte_stream = response_handler.read_streamed_body()
1789
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
1989
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
1990
self._record_counter)
1790
1991
if src_format.network_name() != repo._format.network_name():
1791
1992
raise AssertionError(
1792
1993
"Mismatched RemoteRepository and stream src %r, %r" % (
1867
2069
self._network_name)
1869
2071
def get_format_description(self):
1870
return 'Remote BZR Branch'
2073
return 'Remote: ' + self._custom_format.get_format_description()
1872
2075
def network_name(self):
1873
2076
return self._network_name
1875
def open(self, a_bzrdir, ignore_fallbacks=False):
1876
return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2078
def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
2079
return a_bzrdir.open_branch(name=name,
2080
ignore_fallbacks=ignore_fallbacks)
1878
def _vfs_initialize(self, a_bzrdir):
2082
def _vfs_initialize(self, a_bzrdir, name):
1879
2083
# Initialisation when using a local bzrdir object, or a non-vfs init
1880
2084
# method is not available on the server.
1881
2085
# self._custom_format is always set - the start of initialize ensures
1883
2087
if isinstance(a_bzrdir, RemoteBzrDir):
1884
2088
a_bzrdir._ensure_real()
1885
result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
2089
result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
1887
2092
# We assume the bzrdir is parameterised; it may not be.
1888
result = self._custom_format.initialize(a_bzrdir)
2093
result = self._custom_format.initialize(a_bzrdir, name)
1889
2094
if (isinstance(a_bzrdir, RemoteBzrDir) and
1890
2095
not isinstance(result, RemoteBranch)):
1891
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
2096
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
1894
def initialize(self, a_bzrdir):
2100
def initialize(self, a_bzrdir, name=None, repository=None):
1895
2101
# 1) get the network name to use.
1896
2102
if self._custom_format:
1897
2103
network_name = self._custom_format.network_name()
1903
2109
network_name = reference_format.network_name()
1904
2110
# Being asked to create on a non RemoteBzrDir:
1905
2111
if not isinstance(a_bzrdir, RemoteBzrDir):
1906
return self._vfs_initialize(a_bzrdir)
2112
return self._vfs_initialize(a_bzrdir, name=name)
1907
2113
medium = a_bzrdir._client._medium
1908
2114
if medium._is_remote_before((1, 13)):
1909
return self._vfs_initialize(a_bzrdir)
2115
return self._vfs_initialize(a_bzrdir, name=name)
1910
2116
# Creating on a remote bzr dir.
1911
2117
# 2) try direct creation via RPC
1912
2118
path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
2119
if name is not None:
2120
# XXX JRV20100304: Support creating colocated branches
2121
raise errors.NoColocatedBranchSupport(self)
1913
2122
verb = 'BzrDir.create_branch'
1915
2124
response = a_bzrdir._call(verb, path, network_name)
1916
2125
except errors.UnknownSmartMethod:
1917
2126
# Fallback - use vfs methods
1918
2127
medium._remember_remote_is_before((1, 13))
1919
return self._vfs_initialize(a_bzrdir)
2128
return self._vfs_initialize(a_bzrdir, name=name)
1920
2129
if response[0] != 'ok':
1921
2130
raise errors.UnexpectedSmartServerResponse(response)
1922
2131
# Turn the response into a RemoteRepository object.
1923
2132
format = RemoteBranchFormat(network_name=response[1])
1924
2133
repo_format = response_tuple_to_repo_format(response[3:])
1925
if response[2] == '':
1926
repo_bzrdir = a_bzrdir
2134
repo_path = response[2]
2135
if repository is not None:
2136
remote_repo_url = urlutils.join(medium.base, repo_path)
2137
url_diff = urlutils.relative_url(repository.user_url,
2140
raise AssertionError(
2141
'repository.user_url %r does not match URL from server '
2142
'response (%r + %r)'
2143
% (repository.user_url, medium.base, repo_path))
2144
remote_repo = repository
1928
repo_bzrdir = RemoteBzrDir(
1929
a_bzrdir.root_transport.clone(response[2]), a_bzrdir._format,
1931
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2147
repo_bzrdir = a_bzrdir
2149
repo_bzrdir = RemoteBzrDir(
2150
a_bzrdir.root_transport.clone(repo_path), a_bzrdir._format,
2152
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
1932
2153
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
1933
format=format, setup_stacking=False)
2154
format=format, setup_stacking=False, name=name)
1934
2155
# XXX: We know this is a new branch, so it must have revno 0, revid
1935
2156
# NULL_REVISION. Creating the branch locked would make this be unable
1936
2157
# to be wrong; here its simply very unlikely to be wrong. RBC 20090225
1956
2177
return self._custom_format.supports_set_append_revisions_only()
1959
class RemoteBranch(branch.Branch, _RpcHelper):
2180
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
1960
2181
"""Branch stored on a server accessed by HPSS RPC.
1962
2183
At the moment most operations are mapped down to simple file operations.
1965
2186
def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
1966
_client=None, format=None, setup_stacking=True):
2187
_client=None, format=None, setup_stacking=True, name=None):
1967
2188
"""Create a RemoteBranch instance.
1969
2190
:param real_branch: An optional local implementation of the branch
2186
2423
self._vfs_set_tags_bytes(bytes)
2188
2425
def lock_read(self):
2426
"""Lock the branch for read operations.
2428
:return: A bzrlib.lock.LogicalLockResult.
2189
2430
self.repository.lock_read()
2190
2431
if not self._lock_mode:
2432
self._note_lock('r')
2191
2433
self._lock_mode = 'r'
2192
2434
self._lock_count = 1
2193
2435
if self._real_branch is not None:
2194
2436
self._real_branch.lock_read()
2196
2438
self._lock_count += 1
2439
return lock.LogicalLockResult(self.unlock)
2198
2441
def _remote_lock_write(self, token):
2199
2442
if token is None:
2200
2443
branch_token = repo_token = ''
2202
2445
branch_token = token
2203
repo_token = self.repository.lock_write()
2446
repo_token = self.repository.lock_write().repository_token
2204
2447
self.repository.unlock()
2205
2448
err_context = {'token': token}
2206
response = self._call(
2207
'Branch.lock_write', self._remote_path(), branch_token,
2208
repo_token or '', **err_context)
2450
response = self._call(
2451
'Branch.lock_write', self._remote_path(), branch_token,
2452
repo_token or '', **err_context)
2453
except errors.LockContention, e:
2454
# The LockContention from the server doesn't have any
2455
# information about the lock_url. We re-raise LockContention
2456
# with valid lock_url.
2457
raise errors.LockContention('(remote lock)',
2458
self.repository.base.split('.bzr/')[0])
2209
2459
if response[0] != 'ok':
2210
2460
raise errors.UnexpectedSmartServerResponse(response)
2211
2461
ok, branch_token, repo_token = response
2569
2822
medium = self._branch._client._medium
2570
2823
if medium._is_remote_before((1, 14)):
2571
2824
return self._vfs_set_option(value, name, section)
2825
if isinstance(value, dict):
2826
if medium._is_remote_before((2, 2)):
2827
return self._vfs_set_option(value, name, section)
2828
return self._set_config_option_dict(value, name, section)
2830
return self._set_config_option(value, name, section)
2832
def _set_config_option(self, value, name, section):
2573
2834
path = self._branch._remote_path()
2574
2835
response = self._branch._client.call('Branch.set_config_option',
2575
2836
path, self._branch._lock_token, self._branch._repo_lock_token,
2576
2837
value.encode('utf8'), name, section or '')
2577
2838
except errors.UnknownSmartMethod:
2839
medium = self._branch._client._medium
2578
2840
medium._remember_remote_is_before((1, 14))
2579
2841
return self._vfs_set_option(value, name, section)
2580
2842
if response != ():
2581
2843
raise errors.UnexpectedSmartServerResponse(response)
2845
def _serialize_option_dict(self, option_dict):
2847
for key, value in option_dict.items():
2848
if isinstance(key, unicode):
2849
key = key.encode('utf8')
2850
if isinstance(value, unicode):
2851
value = value.encode('utf8')
2852
utf8_dict[key] = value
2853
return bencode.bencode(utf8_dict)
2855
def _set_config_option_dict(self, value, name, section):
2857
path = self._branch._remote_path()
2858
serialised_dict = self._serialize_option_dict(value)
2859
response = self._branch._client.call(
2860
'Branch.set_config_option_dict',
2861
path, self._branch._lock_token, self._branch._repo_lock_token,
2862
serialised_dict, name, section or '')
2863
except errors.UnknownSmartMethod:
2864
medium = self._branch._client._medium
2865
medium._remember_remote_is_before((2, 2))
2866
return self._vfs_set_option(value, name, section)
2868
raise errors.UnexpectedSmartServerResponse(response)
2583
2870
def _real_object(self):
2584
2871
self._branch._ensure_real()
2585
2872
return self._branch._real_branch
2668
2955
'Missing key %r in context %r', key_err.args[0], context)
2671
if err.error_verb == 'NoSuchRevision':
2958
if err.error_verb == 'IncompatibleRepositories':
2959
raise errors.IncompatibleRepositories(err.error_args[0],
2960
err.error_args[1], err.error_args[2])
2961
elif err.error_verb == 'NoSuchRevision':
2672
2962
raise NoSuchRevision(find('branch'), err.error_args[0])
2673
2963
elif err.error_verb == 'nosuchrevision':
2674
2964
raise NoSuchRevision(find('repository'), err.error_args[0])
2675
elif err.error_tuple == ('nobranch',):
2676
raise errors.NotBranchError(path=find('bzrdir').root_transport.base)
2965
elif err.error_verb == 'nobranch':
2966
if len(err.error_args) >= 1:
2967
extra = err.error_args[0]
2970
raise errors.NotBranchError(path=find('bzrdir').root_transport.base,
2677
2972
elif err.error_verb == 'norepository':
2678
2973
raise errors.NoRepositoryPresent(find('bzrdir'))
2679
2974
elif err.error_verb == 'LockContention':