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,
522
532
return self._supports_external_lookups
535
def supports_funky_characters(self):
536
if self._supports_funky_characters is None:
538
self._supports_funky_characters = \
539
self._custom_format.supports_funky_characters
540
return self._supports_funky_characters
525
543
def supports_tree_reference(self):
526
544
if self._supports_tree_reference is None:
527
545
self._ensure_real()
895
913
def _has_same_fallbacks(self, other_repo):
896
914
"""Returns true if the repositories have the same fallbacks."""
897
915
# XXX: copied from Repository; it should be unified into a base class
898
# <https://bugs.edge.launchpad.net/bzr/+bug/401622>
916
# <https://bugs.launchpad.net/bzr/+bug/401622>
899
917
my_fb = self._fallback_repositories
900
918
other_fb = other_repo._fallback_repositories
901
919
if len(my_fb) != len(other_fb):
1306
1329
return self._real_repository.make_working_trees()
1308
1331
def refresh_data(self):
1309
"""Re-read any data needed to to synchronise with disk.
1332
"""Re-read any data needed to synchronise with disk.
1311
1334
This method is intended to be called after another repository instance
1312
1335
(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.
1336
repository. On all repositories this will work outside of write groups.
1337
Some repository formats (pack and newer for bzrlib native formats)
1338
support refresh_data inside write groups. If called inside a write
1339
group on a repository that does not support refreshing in a write group
1340
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
1342
if self._real_repository is not None:
1320
1343
self._real_repository.refresh_data()
1335
1358
@needs_read_lock
1336
def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1359
def search_missing_revision_ids(self, other,
1360
revision_id=symbol_versioning.DEPRECATED_PARAMETER,
1361
find_ghosts=True, revision_ids=None, if_present_ids=None):
1337
1362
"""Return the revision ids that other has that this does not.
1339
1364
These are returned in topological order.
1341
1366
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)
1368
if symbol_versioning.deprecated_passed(revision_id):
1369
symbol_versioning.warn(
1370
'search_missing_revision_ids(revision_id=...) was '
1371
'deprecated in 2.4. Use revision_ids=[...] instead.',
1372
DeprecationWarning, stacklevel=2)
1373
if revision_ids is not None:
1374
raise AssertionError(
1375
'revision_ids is mutually exclusive with revision_id')
1376
if revision_id is not None:
1377
revision_ids = [revision_id]
1378
inter_repo = repository.InterRepository.get(other, self)
1379
return inter_repo.search_missing_revision_ids(
1380
find_ghosts=find_ghosts, revision_ids=revision_ids,
1381
if_present_ids=if_present_ids)
1346
def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
1383
def fetch(self, source, revision_id=None, find_ghosts=False,
1347
1384
fetch_spec=None):
1348
1385
# No base implementation to use as RemoteRepository is not a subclass
1349
1386
# of Repository; so this is a copy of Repository.fetch().
1367
1404
# the InterRepository base class, which raises an
1368
1405
# IncompatibleRepositories when asked to fetch.
1369
1406
inter = repository.InterRepository.get(source, self)
1370
return inter.fetch(revision_id=revision_id, pb=pb,
1407
return inter.fetch(revision_id=revision_id,
1371
1408
find_ghosts=find_ghosts, fetch_spec=fetch_spec)
1373
1410
def create_bundle(self, target, base, fileobj, format=None):
1748
1785
return '\n'.join((start_keys, stop_keys, count))
1750
1787
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)]
1788
parts = search_result.get_network_struct()
1757
1789
return '\n'.join(parts)
1759
1791
def autopack(self):
1962
1995
verb, args, search_bytes)
1963
1996
except errors.UnknownSmartMethod:
1964
1997
medium._remember_remote_is_before(version)
1998
except errors.UnknownErrorFromSmartServer, e:
1999
if isinstance(search, graph.EverythingResult):
2000
error_verb = e.error_from_smart_server.error_verb
2001
if error_verb == 'BadSearch':
2002
# Pre-2.4 servers don't support this sort of search.
2003
# XXX: perhaps falling back to VFS on BadSearch is a
2004
# good idea in general? It might provide a little bit
2005
# of protection against client-side bugs.
2006
medium._remember_remote_is_before((2, 4))
1966
2010
response_tuple, response_handler = response
1967
2011
found_verb = True
1971
2015
if response_tuple[0] != 'ok':
1972
2016
raise errors.UnexpectedSmartServerResponse(response_tuple)
1973
2017
byte_stream = response_handler.read_streamed_body()
1974
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
2018
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
2019
self._record_counter)
1975
2020
if src_format.network_name() != repo._format.network_name():
1976
2021
raise AssertionError(
1977
2022
"Mismatched RemoteRepository and stream src %r, %r" % (
2115
2160
# Turn the response into a RemoteRepository object.
2116
2161
format = RemoteBranchFormat(network_name=response[1])
2117
2162
repo_format = response_tuple_to_repo_format(response[3:])
2118
if response[2] == '':
2119
repo_bzrdir = a_bzrdir
2163
repo_path = response[2]
2164
if repository is not None:
2165
remote_repo_url = urlutils.join(a_bzrdir.user_url, repo_path)
2166
url_diff = urlutils.relative_url(repository.user_url,
2169
raise AssertionError(
2170
'repository.user_url %r does not match URL from server '
2171
'response (%r + %r)'
2172
% (repository.user_url, a_bzrdir.user_url, repo_path))
2173
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)
2176
repo_bzrdir = a_bzrdir
2178
repo_bzrdir = RemoteBzrDir(
2179
a_bzrdir.root_transport.clone(repo_path), a_bzrdir._format,
2181
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2125
2182
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2126
2183
format=format, setup_stacking=False, name=name)
2127
2184
# XXX: We know this is a new branch, so it must have revno 0, revid
2148
2205
self._ensure_real()
2149
2206
return self._custom_format.supports_set_append_revisions_only()
2208
def _use_default_local_heads_to_fetch(self):
2209
# If the branch format is a metadir format *and* its heads_to_fetch
2210
# implementation is not overridden vs the base class, we can use the
2211
# base class logic rather than use the heads_to_fetch RPC. This is
2212
# usually cheaper in terms of net round trips, as the last-revision and
2213
# tags info fetched is cached and would be fetched anyway.
2215
if isinstance(self._custom_format, branch.BranchFormatMetadir):
2216
branch_class = self._custom_format._branch_class()
2217
heads_to_fetch_impl = branch_class.heads_to_fetch.im_func
2218
if heads_to_fetch_impl is branch.Branch.heads_to_fetch.im_func:
2152
2222
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
2153
2223
"""Branch stored on a server accessed by HPSS RPC.
2357
2427
self._ensure_real()
2358
2428
return self._real_branch._get_tags_bytes()
2360
2431
def _get_tags_bytes(self):
2432
if self._tags_bytes is None:
2433
self._tags_bytes = self._get_tags_bytes_via_hpss()
2434
return self._tags_bytes
2436
def _get_tags_bytes_via_hpss(self):
2361
2437
medium = self._client._medium
2362
2438
if medium._is_remote_before((1, 13)):
2363
2439
return self._vfs_get_tags_bytes()
2396
2478
self._real_branch.lock_read()
2398
2480
self._lock_count += 1
2481
return lock.LogicalLockResult(self.unlock)
2400
2483
def _remote_lock_write(self, token):
2401
2484
if token is None:
2402
2485
branch_token = repo_token = ''
2404
2487
branch_token = token
2405
repo_token = self.repository.lock_write()
2488
repo_token = self.repository.lock_write().repository_token
2406
2489
self.repository.unlock()
2407
2490
err_context = {'token': token}
2408
response = self._call(
2409
'Branch.lock_write', self._remote_path(), branch_token,
2410
repo_token or '', **err_context)
2492
response = self._call(
2493
'Branch.lock_write', self._remote_path(), branch_token,
2494
repo_token or '', **err_context)
2495
except errors.LockContention, e:
2496
# The LockContention from the server doesn't have any
2497
# information about the lock_url. We re-raise LockContention
2498
# with valid lock_url.
2499
raise errors.LockContention('(remote lock)',
2500
self.repository.base.split('.bzr/')[0])
2411
2501
if response[0] != 'ok':
2412
2502
raise errors.UnexpectedSmartServerResponse(response)
2413
2503
ok, branch_token, repo_token = response
2445
2535
self._lock_count += 1
2446
2536
# Re-lock the repository too.
2447
2537
self.repository.lock_write(self._repo_lock_token)
2448
return self._lock_token or None
2538
return BranchWriteLockResult(self.unlock, self._lock_token or None)
2450
2540
def _unlock(self, branch_token, repo_token):
2451
2541
err_context = {'token': str((branch_token, repo_token))}
2715
2805
self._ensure_real()
2716
2806
return self._real_branch.set_push_location(location)
2808
def heads_to_fetch(self):
2809
if self._format._use_default_local_heads_to_fetch():
2810
# We recognise this format, and its heads-to-fetch implementation
2811
# is the default one (tip + tags). In this case it's cheaper to
2812
# just use the default implementation rather than a special RPC as
2813
# the tip and tags data is cached.
2814
return branch.Branch.heads_to_fetch(self)
2815
medium = self._client._medium
2816
if medium._is_remote_before((2, 4)):
2817
return self._vfs_heads_to_fetch()
2819
return self._rpc_heads_to_fetch()
2820
except errors.UnknownSmartMethod:
2821
medium._remember_remote_is_before((2, 4))
2822
return self._vfs_heads_to_fetch()
2824
def _rpc_heads_to_fetch(self):
2825
response = self._call('Branch.heads_to_fetch', self._remote_path())
2826
if len(response) != 2:
2827
raise errors.UnexpectedSmartServerResponse(response)
2828
must_fetch, if_present_fetch = response
2829
return set(must_fetch), set(if_present_fetch)
2831
def _vfs_heads_to_fetch(self):
2833
return self._real_branch.heads_to_fetch()
2719
2836
class RemoteConfig(object):
2720
2837
"""A Config that reads and writes from smart verbs.
2774
2891
medium = self._branch._client._medium
2775
2892
if medium._is_remote_before((1, 14)):
2776
2893
return self._vfs_set_option(value, name, section)
2894
if isinstance(value, dict):
2895
if medium._is_remote_before((2, 2)):
2896
return self._vfs_set_option(value, name, section)
2897
return self._set_config_option_dict(value, name, section)
2899
return self._set_config_option(value, name, section)
2901
def _set_config_option(self, value, name, section):
2778
2903
path = self._branch._remote_path()
2779
2904
response = self._branch._client.call('Branch.set_config_option',
2780
2905
path, self._branch._lock_token, self._branch._repo_lock_token,
2781
2906
value.encode('utf8'), name, section or '')
2782
2907
except errors.UnknownSmartMethod:
2908
medium = self._branch._client._medium
2783
2909
medium._remember_remote_is_before((1, 14))
2784
2910
return self._vfs_set_option(value, name, section)
2785
2911
if response != ():
2786
2912
raise errors.UnexpectedSmartServerResponse(response)
2914
def _serialize_option_dict(self, option_dict):
2916
for key, value in option_dict.items():
2917
if isinstance(key, unicode):
2918
key = key.encode('utf8')
2919
if isinstance(value, unicode):
2920
value = value.encode('utf8')
2921
utf8_dict[key] = value
2922
return bencode.bencode(utf8_dict)
2924
def _set_config_option_dict(self, value, name, section):
2926
path = self._branch._remote_path()
2927
serialised_dict = self._serialize_option_dict(value)
2928
response = self._branch._client.call(
2929
'Branch.set_config_option_dict',
2930
path, self._branch._lock_token, self._branch._repo_lock_token,
2931
serialised_dict, name, section or '')
2932
except errors.UnknownSmartMethod:
2933
medium = self._branch._client._medium
2934
medium._remember_remote_is_before((2, 2))
2935
return self._vfs_set_option(value, name, section)
2937
raise errors.UnexpectedSmartServerResponse(response)
2788
2939
def _real_object(self):
2789
2940
self._branch._ensure_real()
2790
2941
return self._branch._real_branch
2873
3024
'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':
3027
if err.error_verb == 'NoSuchRevision':
2880
3028
raise NoSuchRevision(find('branch'), err.error_args[0])
2881
3029
elif err.error_verb == 'nosuchrevision':
2882
3030
raise NoSuchRevision(find('repository'), err.error_args[0])
2890
3038
elif err.error_verb == 'norepository':
2891
3039
raise errors.NoRepositoryPresent(find('bzrdir'))
2892
elif err.error_verb == 'LockContention':
2893
raise errors.LockContention('(remote lock)')
2894
3040
elif err.error_verb == 'UnlockableTransport':
2895
3041
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
3042
elif err.error_verb == 'TokenMismatch':
2899
3043
raise errors.TokenMismatch(find('token'), '(remote token)')
2900
3044
elif err.error_verb == 'Diverged':
2901
3045
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
3046
elif err.error_verb == 'NotStacked':
2909
3047
raise errors.NotStacked(branch=find('branch'))
2910
3048
elif err.error_verb == 'PermissionDenied':
2920
3058
elif err.error_verb == 'NoSuchFile':
2921
3059
path = get_path()
2922
3060
raise errors.NoSuchFile(path)
3061
_translate_error_without_context(err)
3064
def _translate_error_without_context(err):
3065
"""Translate any ErrorFromSmartServer values that don't require context"""
3066
if err.error_verb == 'IncompatibleRepositories':
3067
raise errors.IncompatibleRepositories(err.error_args[0],
3068
err.error_args[1], err.error_args[2])
3069
elif err.error_verb == 'LockContention':
3070
raise errors.LockContention('(remote lock)')
3071
elif err.error_verb == 'LockFailed':
3072
raise errors.LockFailed(err.error_args[0], err.error_args[1])
3073
elif err.error_verb == 'TipChangeRejected':
3074
raise errors.TipChangeRejected(err.error_args[0].decode('utf8'))
3075
elif err.error_verb == 'UnstackableBranchFormat':
3076
raise errors.UnstackableBranchFormat(*err.error_args)
3077
elif err.error_verb == 'UnstackableRepositoryFormat':
3078
raise errors.UnstackableRepositoryFormat(*err.error_args)
2923
3079
elif err.error_verb == 'FileExists':
2924
3080
raise errors.FileExists(err.error_args[0])
2925
3081
elif err.error_verb == 'DirectoryNotEmpty':
2944
3100
raise UnicodeEncodeError(encoding, val, start, end, reason)
2945
3101
elif err.error_verb == 'ReadOnlyError':
2946
3102
raise errors.TransportNotPossible('readonly transport')
3103
elif err.error_verb == 'MemoryError':
3104
raise errors.BzrError("remote server out of memory\n"
3105
"Retry non-remotely, or contact the server admin for details.")
2947
3106
raise errors.UnknownErrorFromSmartServer(err)