32
33
revision as _mod_revision,
36
from bzrlib.branch import BranchReferenceFormat
38
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
37
39
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
38
40
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
39
41
from bzrlib.errors import (
244
247
self._ensure_real()
245
248
self._real_bzrdir.destroy_repository()
247
def create_branch(self, name=None):
250
def create_branch(self, name=None, repository=None):
248
251
# as per meta1 formats - just delegate to the format object which may
249
252
# be parameterised.
250
253
real_branch = self._format.get_branch_format().initialize(self,
254
name=name, repository=repository)
252
255
if not isinstance(real_branch, RemoteBranch):
253
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)
256
262
result = real_branch
257
263
# BzrDir.clone_on_transport() uses the result of create_branch but does
269
275
self._real_bzrdir.destroy_branch(name=name)
270
276
self._next_open_branch_result = None
272
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):
273
280
raise errors.NotLocalUrl(self.transport.base)
275
def find_branch_format(self):
282
def find_branch_format(self, name=None):
276
283
"""Find the branch 'format' for this bzrdir.
278
285
This might be a synthetic object for e.g. RemoteBranch and SVN.
280
b = self.open_branch()
287
b = self.open_branch(name=name)
283
def get_branch_reference(self):
290
def get_branch_reference(self, name=None):
284
291
"""See BzrDir.get_branch_reference()."""
293
# XXX JRV20100304: Support opening colocated branches
294
raise errors.NoColocatedBranchSupport(self)
285
295
response = self._get_branch_reference()
286
296
if response[0] == 'ref':
287
297
return response[1]
318
328
raise errors.UnexpectedSmartServerResponse(response)
321
def _get_tree_branch(self):
331
def _get_tree_branch(self, name=None):
322
332
"""See BzrDir._get_tree_branch()."""
323
return None, self.open_branch()
333
return None, self.open_branch(name=name)
325
335
def open_branch(self, name=None, unsupported=False,
326
336
ignore_fallbacks=False):
441
451
"""Upgrading of remote bzrdirs is not supported yet."""
444
def needs_format_conversion(self, format=None):
454
def needs_format_conversion(self, format):
445
455
"""Upgrading of remote bzrdirs is not supported yet."""
447
symbol_versioning.warn(symbol_versioning.deprecated_in((1, 13, 0))
448
% 'needs_format_conversion(format=None)')
451
458
def clone(self, url, revision_id=None, force_new_repo=False,
895
902
def _has_same_fallbacks(self, other_repo):
896
903
"""Returns true if the repositories have the same fallbacks."""
897
904
# XXX: copied from Repository; it should be unified into a base class
898
# <https://bugs.edge.launchpad.net/bzr/+bug/401622>
905
# <https://bugs.launchpad.net/bzr/+bug/401622>
899
906
my_fb = self._fallback_repositories
900
907
other_fb = other_repo._fallback_repositories
901
908
if len(my_fb) != len(other_fb):
1306
1318
return self._real_repository.make_working_trees()
1308
1320
def refresh_data(self):
1309
"""Re-read any data needed to to synchronise with disk.
1321
"""Re-read any data needed to synchronise with disk.
1311
1323
This method is intended to be called after another repository instance
1312
1324
(such as one used by a smart server) has inserted data into the
1313
repository. It may not be called during a write group, but may be
1314
called at any other time.
1325
repository. On all repositories this will work outside of write groups.
1326
Some repository formats (pack and newer for bzrlib native formats)
1327
support refresh_data inside write groups. If called inside a write
1328
group on a repository that does not support refreshing in a write group
1329
IsInWriteGroupError will be raised.
1316
if self.is_in_write_group():
1317
raise errors.InternalBzrError(
1318
"May not refresh_data while in a write group.")
1319
1331
if self._real_repository is not None:
1320
1332
self._real_repository.refresh_data()
1335
1347
@needs_read_lock
1336
def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1348
def search_missing_revision_ids(self, other,
1349
revision_id=symbol_versioning.DEPRECATED_PARAMETER,
1350
find_ghosts=True, revision_ids=None, if_present_ids=None):
1337
1351
"""Return the revision ids that other has that this does not.
1339
1353
These are returned in topological order.
1341
1355
revision_id: only return revision ids included by revision_id.
1343
return repository.InterRepository.get(
1344
other, self).search_missing_revision_ids(revision_id, find_ghosts)
1357
if symbol_versioning.deprecated_passed(revision_id):
1358
symbol_versioning.warn(
1359
'search_missing_revision_ids(revision_id=...) was '
1360
'deprecated in 2.4. Use revision_ids=[...] instead.',
1361
DeprecationWarning, stacklevel=2)
1362
if revision_ids is not None:
1363
raise AssertionError(
1364
'revision_ids is mutually exclusive with revision_id')
1365
if revision_id is not None:
1366
revision_ids = [revision_id]
1367
inter_repo = repository.InterRepository.get(other, self)
1368
return inter_repo.search_missing_revision_ids(
1369
find_ghosts=find_ghosts, revision_ids=revision_ids,
1370
if_present_ids=if_present_ids)
1346
def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
1372
def fetch(self, source, revision_id=None, find_ghosts=False,
1347
1373
fetch_spec=None):
1348
1374
# No base implementation to use as RemoteRepository is not a subclass
1349
1375
# of Repository; so this is a copy of Repository.fetch().
1367
1393
# the InterRepository base class, which raises an
1368
1394
# IncompatibleRepositories when asked to fetch.
1369
1395
inter = repository.InterRepository.get(source, self)
1370
return inter.fetch(revision_id=revision_id, pb=pb,
1396
return inter.fetch(revision_id=revision_id,
1371
1397
find_ghosts=find_ghosts, fetch_spec=fetch_spec)
1373
1399
def create_bundle(self, target, base, fileobj, format=None):
1748
1774
return '\n'.join((start_keys, stop_keys, count))
1750
1776
def _serialise_search_result(self, search_result):
1751
if isinstance(search_result, graph.PendingAncestryResult):
1752
parts = ['ancestry-of']
1753
parts.extend(search_result.heads)
1755
recipe = search_result.get_recipe()
1756
parts = [recipe[0], self._serialise_search_recipe(recipe)]
1777
parts = search_result.get_network_struct()
1757
1778
return '\n'.join(parts)
1759
1780
def autopack(self):
1962
1984
verb, args, search_bytes)
1963
1985
except errors.UnknownSmartMethod:
1964
1986
medium._remember_remote_is_before(version)
1987
except errors.UnknownErrorFromSmartServer, e:
1988
if isinstance(search, graph.EverythingResult):
1989
error_verb = e.error_from_smart_server.error_verb
1990
if error_verb == 'BadSearch':
1991
# Pre-2.4 servers don't support this sort of search.
1992
# XXX: perhaps falling back to VFS on BadSearch is a
1993
# good idea in general? It might provide a little bit
1994
# of protection against client-side bugs.
1995
medium._remember_remote_is_before((2, 4))
1966
1999
response_tuple, response_handler = response
1967
2000
found_verb = True
1971
2004
if response_tuple[0] != 'ok':
1972
2005
raise errors.UnexpectedSmartServerResponse(response_tuple)
1973
2006
byte_stream = response_handler.read_streamed_body()
1974
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
2007
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
2008
self._record_counter)
1975
2009
if src_format.network_name() != repo._format.network_name():
1976
2010
raise AssertionError(
1977
2011
"Mismatched RemoteRepository and stream src %r, %r" % (
2115
2149
# Turn the response into a RemoteRepository object.
2116
2150
format = RemoteBranchFormat(network_name=response[1])
2117
2151
repo_format = response_tuple_to_repo_format(response[3:])
2118
if response[2] == '':
2119
repo_bzrdir = a_bzrdir
2152
repo_path = response[2]
2153
if repository is not None:
2154
remote_repo_url = urlutils.join(a_bzrdir.user_url, repo_path)
2155
url_diff = urlutils.relative_url(repository.user_url,
2158
raise AssertionError(
2159
'repository.user_url %r does not match URL from server '
2160
'response (%r + %r)'
2161
% (repository.user_url, a_bzrdir.user_url, repo_path))
2162
remote_repo = repository
2121
repo_bzrdir = RemoteBzrDir(
2122
a_bzrdir.root_transport.clone(response[2]), a_bzrdir._format,
2124
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2165
repo_bzrdir = a_bzrdir
2167
repo_bzrdir = RemoteBzrDir(
2168
a_bzrdir.root_transport.clone(repo_path), a_bzrdir._format,
2170
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2125
2171
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2126
2172
format=format, setup_stacking=False, name=name)
2127
2173
# XXX: We know this is a new branch, so it must have revno 0, revid
2148
2194
self._ensure_real()
2149
2195
return self._custom_format.supports_set_append_revisions_only()
2197
def _use_default_local_heads_to_fetch(self):
2198
# If the branch format is a metadir format *and* its heads_to_fetch
2199
# implementation is not overridden vs the base class, we can use the
2200
# base class logic rather than use the heads_to_fetch RPC. This is
2201
# usually cheaper in terms of net round trips, as the last-revision and
2202
# tags info fetched is cached and would be fetched anyway.
2204
if isinstance(self._custom_format, branch.BranchFormatMetadir):
2205
branch_class = self._custom_format._branch_class()
2206
heads_to_fetch_impl = branch_class.heads_to_fetch.im_func
2207
if heads_to_fetch_impl is branch.Branch.heads_to_fetch.im_func:
2152
2211
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
2153
2212
"""Branch stored on a server accessed by HPSS RPC.
2357
2416
self._ensure_real()
2358
2417
return self._real_branch._get_tags_bytes()
2360
2420
def _get_tags_bytes(self):
2421
if self._tags_bytes is None:
2422
self._tags_bytes = self._get_tags_bytes_via_hpss()
2423
return self._tags_bytes
2425
def _get_tags_bytes_via_hpss(self):
2361
2426
medium = self._client._medium
2362
2427
if medium._is_remote_before((1, 13)):
2363
2428
return self._vfs_get_tags_bytes()
2396
2467
self._real_branch.lock_read()
2398
2469
self._lock_count += 1
2470
return lock.LogicalLockResult(self.unlock)
2400
2472
def _remote_lock_write(self, token):
2401
2473
if token is None:
2402
2474
branch_token = repo_token = ''
2404
2476
branch_token = token
2405
repo_token = self.repository.lock_write()
2477
repo_token = self.repository.lock_write().repository_token
2406
2478
self.repository.unlock()
2407
2479
err_context = {'token': token}
2408
response = self._call(
2409
'Branch.lock_write', self._remote_path(), branch_token,
2410
repo_token or '', **err_context)
2481
response = self._call(
2482
'Branch.lock_write', self._remote_path(), branch_token,
2483
repo_token or '', **err_context)
2484
except errors.LockContention, e:
2485
# The LockContention from the server doesn't have any
2486
# information about the lock_url. We re-raise LockContention
2487
# with valid lock_url.
2488
raise errors.LockContention('(remote lock)',
2489
self.repository.base.split('.bzr/')[0])
2411
2490
if response[0] != 'ok':
2412
2491
raise errors.UnexpectedSmartServerResponse(response)
2413
2492
ok, branch_token, repo_token = response
2445
2524
self._lock_count += 1
2446
2525
# Re-lock the repository too.
2447
2526
self.repository.lock_write(self._repo_lock_token)
2448
return self._lock_token or None
2527
return BranchWriteLockResult(self.unlock, self._lock_token or None)
2450
2529
def _unlock(self, branch_token, repo_token):
2451
2530
err_context = {'token': str((branch_token, repo_token))}
2715
2794
self._ensure_real()
2716
2795
return self._real_branch.set_push_location(location)
2797
def heads_to_fetch(self):
2798
if self._format._use_default_local_heads_to_fetch():
2799
# We recognise this format, and its heads-to-fetch implementation
2800
# is the default one (tip + tags). In this case it's cheaper to
2801
# just use the default implementation rather than a special RPC as
2802
# the tip and tags data is cached.
2803
return branch.Branch.heads_to_fetch(self)
2804
medium = self._client._medium
2805
if medium._is_remote_before((2, 4)):
2806
return self._vfs_heads_to_fetch()
2808
return self._rpc_heads_to_fetch()
2809
except errors.UnknownSmartMethod:
2810
medium._remember_remote_is_before((2, 4))
2811
return self._vfs_heads_to_fetch()
2813
def _rpc_heads_to_fetch(self):
2814
response = self._call('Branch.heads_to_fetch', self._remote_path())
2815
if len(response) != 2:
2816
raise errors.UnexpectedSmartServerResponse(response)
2817
must_fetch, if_present_fetch = response
2818
return set(must_fetch), set(if_present_fetch)
2820
def _vfs_heads_to_fetch(self):
2822
return self._real_branch.heads_to_fetch()
2719
2825
class RemoteConfig(object):
2720
2826
"""A Config that reads and writes from smart verbs.
2774
2880
medium = self._branch._client._medium
2775
2881
if medium._is_remote_before((1, 14)):
2776
2882
return self._vfs_set_option(value, name, section)
2883
if isinstance(value, dict):
2884
if medium._is_remote_before((2, 2)):
2885
return self._vfs_set_option(value, name, section)
2886
return self._set_config_option_dict(value, name, section)
2888
return self._set_config_option(value, name, section)
2890
def _set_config_option(self, value, name, section):
2778
2892
path = self._branch._remote_path()
2779
2893
response = self._branch._client.call('Branch.set_config_option',
2780
2894
path, self._branch._lock_token, self._branch._repo_lock_token,
2781
2895
value.encode('utf8'), name, section or '')
2782
2896
except errors.UnknownSmartMethod:
2897
medium = self._branch._client._medium
2783
2898
medium._remember_remote_is_before((1, 14))
2784
2899
return self._vfs_set_option(value, name, section)
2785
2900
if response != ():
2786
2901
raise errors.UnexpectedSmartServerResponse(response)
2903
def _serialize_option_dict(self, option_dict):
2905
for key, value in option_dict.items():
2906
if isinstance(key, unicode):
2907
key = key.encode('utf8')
2908
if isinstance(value, unicode):
2909
value = value.encode('utf8')
2910
utf8_dict[key] = value
2911
return bencode.bencode(utf8_dict)
2913
def _set_config_option_dict(self, value, name, section):
2915
path = self._branch._remote_path()
2916
serialised_dict = self._serialize_option_dict(value)
2917
response = self._branch._client.call(
2918
'Branch.set_config_option_dict',
2919
path, self._branch._lock_token, self._branch._repo_lock_token,
2920
serialised_dict, name, section or '')
2921
except errors.UnknownSmartMethod:
2922
medium = self._branch._client._medium
2923
medium._remember_remote_is_before((2, 2))
2924
return self._vfs_set_option(value, name, section)
2926
raise errors.UnexpectedSmartServerResponse(response)
2788
2928
def _real_object(self):
2789
2929
self._branch._ensure_real()
2790
2930
return self._branch._real_branch
2873
3013
'Missing key %r in context %r', key_err.args[0], context)
2876
if err.error_verb == 'IncompatibleRepositories':
2877
raise errors.IncompatibleRepositories(err.error_args[0],
2878
err.error_args[1], err.error_args[2])
2879
elif err.error_verb == 'NoSuchRevision':
3016
if err.error_verb == 'NoSuchRevision':
2880
3017
raise NoSuchRevision(find('branch'), err.error_args[0])
2881
3018
elif err.error_verb == 'nosuchrevision':
2882
3019
raise NoSuchRevision(find('repository'), err.error_args[0])
2890
3027
elif err.error_verb == 'norepository':
2891
3028
raise errors.NoRepositoryPresent(find('bzrdir'))
2892
elif err.error_verb == 'LockContention':
2893
raise errors.LockContention('(remote lock)')
2894
3029
elif err.error_verb == 'UnlockableTransport':
2895
3030
raise errors.UnlockableTransport(find('bzrdir').root_transport)
2896
elif err.error_verb == 'LockFailed':
2897
raise errors.LockFailed(err.error_args[0], err.error_args[1])
2898
3031
elif err.error_verb == 'TokenMismatch':
2899
3032
raise errors.TokenMismatch(find('token'), '(remote token)')
2900
3033
elif err.error_verb == 'Diverged':
2901
3034
raise errors.DivergedBranches(find('branch'), find('other_branch'))
2902
elif err.error_verb == 'TipChangeRejected':
2903
raise errors.TipChangeRejected(err.error_args[0].decode('utf8'))
2904
elif err.error_verb == 'UnstackableBranchFormat':
2905
raise errors.UnstackableBranchFormat(*err.error_args)
2906
elif err.error_verb == 'UnstackableRepositoryFormat':
2907
raise errors.UnstackableRepositoryFormat(*err.error_args)
2908
3035
elif err.error_verb == 'NotStacked':
2909
3036
raise errors.NotStacked(branch=find('branch'))
2910
3037
elif err.error_verb == 'PermissionDenied':
2920
3047
elif err.error_verb == 'NoSuchFile':
2921
3048
path = get_path()
2922
3049
raise errors.NoSuchFile(path)
3050
_translate_error_without_context(err)
3053
def _translate_error_without_context(err):
3054
"""Translate any ErrorFromSmartServer values that don't require context"""
3055
if err.error_verb == 'IncompatibleRepositories':
3056
raise errors.IncompatibleRepositories(err.error_args[0],
3057
err.error_args[1], err.error_args[2])
3058
elif err.error_verb == 'LockContention':
3059
raise errors.LockContention('(remote lock)')
3060
elif err.error_verb == 'LockFailed':
3061
raise errors.LockFailed(err.error_args[0], err.error_args[1])
3062
elif err.error_verb == 'TipChangeRejected':
3063
raise errors.TipChangeRejected(err.error_args[0].decode('utf8'))
3064
elif err.error_verb == 'UnstackableBranchFormat':
3065
raise errors.UnstackableBranchFormat(*err.error_args)
3066
elif err.error_verb == 'UnstackableRepositoryFormat':
3067
raise errors.UnstackableRepositoryFormat(*err.error_args)
2923
3068
elif err.error_verb == 'FileExists':
2924
3069
raise errors.FileExists(err.error_args[0])
2925
3070
elif err.error_verb == 'DirectoryNotEmpty':
2944
3089
raise UnicodeEncodeError(encoding, val, start, end, reason)
2945
3090
elif err.error_verb == 'ReadOnlyError':
2946
3091
raise errors.TransportNotPossible('readonly transport')
3092
elif err.error_verb == 'MemoryError':
3093
raise errors.BzrError("remote server out of memory\n"
3094
"Retry non-remotely, or contact the server admin for details.")
2947
3095
raise errors.UnknownErrorFromSmartServer(err)