1
# Copyright (C) 2006-2010 Canonical Ltd
1
# Copyright (C) 2006, 2007, 2008, 2009 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
34
34
from bzrlib.branch import BranchReferenceFormat
35
35
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
36
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
36
from bzrlib.decorators import needs_read_lock, needs_write_lock
37
37
from bzrlib.errors import (
39
39
SmartProtocolError,
89
89
class RemoteBzrDir(BzrDir, _RpcHelper):
90
90
"""Control directory on a remote server, accessed via bzr:// or similar."""
92
def __init__(self, transport, format, _client=None, _force_probe=False):
92
def __init__(self, transport, format, _client=None):
93
93
"""Construct a RemoteBzrDir.
95
95
:param _client: Private parameter for testing. Disables probing and the
99
99
# this object holds a delegated bzrdir that uses file-level operations
100
100
# to talk to the other side
101
101
self._real_bzrdir = None
102
self._has_working_tree = None
103
102
# 1-shot cache for the call pattern 'create_branch; open_branch' - see
104
103
# create_branch for details.
105
104
self._next_open_branch_result = None
109
108
self._client = client._SmartClient(medium)
111
110
self._client = _client
118
return '%s(%r)' % (self.__class__.__name__, self._client)
120
def _probe_bzrdir(self):
121
medium = self._client._medium
122
113
path = self._path_for_remote_call(self._client)
123
if medium._is_remote_before((2, 1)):
127
self._rpc_open_2_1(path)
129
except errors.UnknownSmartMethod:
130
medium._remember_remote_is_before((2, 1))
133
def _rpc_open_2_1(self, path):
134
response = self._call('BzrDir.open_2.1', path)
135
if response == ('no',):
136
raise errors.NotBranchError(path=self.root_transport.base)
137
elif response[0] == 'yes':
138
if response[1] == 'yes':
139
self._has_working_tree = True
140
elif response[1] == 'no':
141
self._has_working_tree = False
143
raise errors.UnexpectedSmartServerResponse(response)
145
raise errors.UnexpectedSmartServerResponse(response)
147
def _rpc_open(self, path):
148
114
response = self._call('BzrDir.open', path)
149
115
if response not in [('yes',), ('no',)]:
150
116
raise errors.UnexpectedSmartServerResponse(response)
151
117
if response == ('no',):
152
raise errors.NotBranchError(path=self.root_transport.base)
118
raise errors.NotBranchError(path=transport.base)
154
120
def _ensure_real(self):
155
121
"""Ensure that there is a _real_bzrdir set.
157
123
Used before calls to self._real_bzrdir.
159
125
if not self._real_bzrdir:
160
if 'hpssvfs' in debug.debug_flags:
162
warning('VFS BzrDir access triggered\n%s',
163
''.join(traceback.format_stack()))
164
126
self._real_bzrdir = BzrDir.open_from_transport(
165
127
self.root_transport, _server_formats=False)
166
128
self._format._network_name = \
287
249
def _get_branch_reference(self):
288
250
path = self._path_for_remote_call(self._client)
289
251
medium = self._client._medium
291
('BzrDir.open_branchV3', (2, 1)),
292
('BzrDir.open_branchV2', (1, 13)),
293
('BzrDir.open_branch', None),
295
for verb, required_version in candidate_calls:
296
if required_version and medium._is_remote_before(required_version):
252
if not medium._is_remote_before((1, 13)):
299
response = self._call(verb, path)
254
response = self._call('BzrDir.open_branchV2', path)
255
if response[0] not in ('ref', 'branch'):
256
raise errors.UnexpectedSmartServerResponse(response)
300
258
except errors.UnknownSmartMethod:
301
if required_version is None:
303
medium._remember_remote_is_before(required_version)
306
if verb == 'BzrDir.open_branch':
307
if response[0] != 'ok':
308
raise errors.UnexpectedSmartServerResponse(response)
309
if response[1] != '':
310
return ('ref', response[1])
312
return ('branch', '')
313
if response[0] not in ('ref', 'branch'):
259
medium._remember_remote_is_before((1, 13))
260
response = self._call('BzrDir.open_branch', path)
261
if response[0] != 'ok':
314
262
raise errors.UnexpectedSmartServerResponse(response)
263
if response[1] != '':
264
return ('ref', response[1])
266
return ('branch', '')
317
268
def _get_tree_branch(self):
318
269
"""See BzrDir._get_tree_branch()."""
405
356
raise errors.NoRepositoryPresent(self)
407
def has_workingtree(self):
408
if self._has_working_tree is None:
410
self._has_working_tree = self._real_bzrdir.has_workingtree()
411
return self._has_working_tree
413
358
def open_workingtree(self, recommend_upgrade=True):
414
if self.has_workingtree():
360
if self._real_bzrdir.has_workingtree():
415
361
raise errors.NotLocalUrl(self.root_transport)
417
363
raise errors.NoWorkingTree(self.root_transport.base)
615
561
return self._custom_format._fetch_reconcile
617
563
def get_format_description(self):
619
return 'Remote: ' + self._custom_format.get_format_description()
564
return 'bzr remote repository'
621
566
def __eq__(self, other):
622
567
return self.__class__ is other.__class__
638
583
return self._custom_format._serializer
641
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin):
586
class RemoteRepository(_RpcHelper):
642
587
"""Repository accessed over rpc.
644
589
For the moment most operations are performed using local transport-backed
965
910
def is_write_locked(self):
966
911
return self._lock_mode == 'w'
968
def _warn_if_deprecated(self, branch=None):
969
# If we have a real repository, the check will be done there, if we
970
# don't the check will be done remotely.
973
913
def lock_read(self):
974
914
# wrong eventually - want a local lock cache context
975
915
if not self._lock_mode:
977
916
self._lock_mode = 'r'
978
917
self._lock_count = 1
979
918
self._unstacked_provider.enable_cache(cache_misses=True)
1497
1434
return self._real_repository.get_signature_text(revision_id)
1499
1436
@needs_read_lock
1500
def _get_inventory_xml(self, revision_id):
1437
def get_inventory_xml(self, revision_id):
1501
1438
self._ensure_real()
1502
return self._real_repository._get_inventory_xml(revision_id)
1439
return self._real_repository.get_inventory_xml(revision_id)
1504
def _deserialise_inventory(self, revision_id, xml):
1441
def deserialise_inventory(self, revision_id, xml):
1505
1442
self._ensure_real()
1506
return self._real_repository._deserialise_inventory(revision_id, xml)
1443
return self._real_repository.deserialise_inventory(revision_id, xml)
1508
1445
def reconcile(self, other=None, thorough=False):
1509
1446
self._ensure_real()
1802
1739
# The stream included an inventory-delta record, but the remote
1803
1740
# side isn't new enough to support them. So we need to send the
1804
1741
# rest of the stream via VFS.
1805
self.target_repo.refresh_data()
1806
1742
return self._resume_stream_with_vfs(response, src_format)
1807
1743
if response[0][0] == 'missing-basis':
1808
1744
tokens, missing_keys = bencode.bdecode_as_tuple(response[0][1])
1950
1886
:param search: The overall search to satisfy with streams.
1951
1887
:param sources: A list of Repository objects to query.
1953
self.from_serialiser = self.from_repository._format._serializer
1889
self.serialiser = self.to_format._serializer
1954
1890
self.seen_revs = set()
1955
1891
self.referenced_revs = set()
1956
1892
# If there are heads in the search, or the key count is > 0, we are not
1973
1909
def missing_parents_rev_handler(self, substream):
1974
1910
for content in substream:
1975
1911
revision_bytes = content.get_bytes_as('fulltext')
1976
revision = self.from_serialiser.read_revision_from_string(
1912
revision = self.serialiser.read_revision_from_string(revision_bytes)
1978
1913
self.seen_revs.add(content.key[-1])
1979
1914
self.referenced_revs.update(revision.parent_ids)
2109
2043
return self._custom_format.supports_set_append_revisions_only()
2112
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
2046
class RemoteBranch(branch.Branch, _RpcHelper):
2113
2047
"""Branch stored on a server accessed by HPSS RPC.
2115
2049
At the moment most operations are mapped down to simple file operations.
2333
2267
medium = self._client._medium
2334
2268
if medium._is_remote_before((1, 18)):
2335
2269
self._vfs_set_tags_bytes(bytes)
2339
2272
self._remote_path(), self._lock_token, self._repo_lock_token)
2373
2305
def lock_write(self, token=None):
2374
2306
if not self._lock_mode:
2375
self._note_lock('w')
2376
2307
# Lock the branch and repo in one remote call.
2377
2308
remote_tokens = self._remote_lock_write(token)
2378
2309
self._lock_token, self._repo_lock_token = remote_tokens
2837
2766
raise NoSuchRevision(find('branch'), err.error_args[0])
2838
2767
elif err.error_verb == 'nosuchrevision':
2839
2768
raise NoSuchRevision(find('repository'), err.error_args[0])
2840
elif err.error_verb == 'nobranch':
2841
if len(err.error_args) >= 1:
2842
extra = err.error_args[0]
2845
raise errors.NotBranchError(path=find('bzrdir').root_transport.base,
2769
elif err.error_tuple == ('nobranch',):
2770
raise errors.NotBranchError(path=find('bzrdir').root_transport.base)
2847
2771
elif err.error_verb == 'norepository':
2848
2772
raise errors.NoRepositoryPresent(find('bzrdir'))
2849
2773
elif err.error_verb == 'LockContention':