33
32
revision as _mod_revision,
38
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
36
from bzrlib.branch import BranchReferenceFormat
39
37
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
40
38
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
41
39
from bzrlib.errors import (
247
244
self._ensure_real()
248
245
self._real_bzrdir.destroy_repository()
250
def create_branch(self, name=None, repository=None):
247
def create_branch(self, name=None):
251
248
# as per meta1 formats - just delegate to the format object which may
252
249
# be parameterised.
253
250
real_branch = self._format.get_branch_format().initialize(self,
254
name=name, repository=repository)
255
252
if not isinstance(real_branch, RemoteBranch):
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)
253
result = RemoteBranch(self, self.find_repository(), real_branch,
262
256
result = real_branch
263
257
# BzrDir.clone_on_transport() uses the result of create_branch but does
275
269
self._real_bzrdir.destroy_branch(name=name)
276
270
self._next_open_branch_result = None
278
def create_workingtree(self, revision_id=None, from_branch=None,
279
accelerator_tree=None, hardlink=False):
272
def create_workingtree(self, revision_id=None, from_branch=None):
280
273
raise errors.NotLocalUrl(self.transport.base)
282
def find_branch_format(self, name=None):
275
def find_branch_format(self):
283
276
"""Find the branch 'format' for this bzrdir.
285
278
This might be a synthetic object for e.g. RemoteBranch and SVN.
287
b = self.open_branch(name=name)
280
b = self.open_branch()
290
def get_branch_reference(self, name=None):
283
def get_branch_reference(self):
291
284
"""See BzrDir.get_branch_reference()."""
293
# XXX JRV20100304: Support opening colocated branches
294
raise errors.NoColocatedBranchSupport(self)
295
285
response = self._get_branch_reference()
296
286
if response[0] == 'ref':
297
287
return response[1]
328
318
raise errors.UnexpectedSmartServerResponse(response)
331
def _get_tree_branch(self, name=None):
321
def _get_tree_branch(self):
332
322
"""See BzrDir._get_tree_branch()."""
333
return None, self.open_branch(name=name)
323
return None, self.open_branch()
335
325
def open_branch(self, name=None, unsupported=False,
336
326
ignore_fallbacks=False):
451
441
"""Upgrading of remote bzrdirs is not supported yet."""
454
def needs_format_conversion(self, format):
444
def needs_format_conversion(self, format=None):
455
445
"""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)')
458
451
def clone(self, url, revision_id=None, force_new_repo=False,
902
895
def _has_same_fallbacks(self, other_repo):
903
896
"""Returns true if the repositories have the same fallbacks."""
904
897
# XXX: copied from Repository; it should be unified into a base class
905
# <https://bugs.launchpad.net/bzr/+bug/401622>
898
# <https://bugs.edge.launchpad.net/bzr/+bug/401622>
906
899
my_fb = self._fallback_repositories
907
900
other_fb = other_repo._fallback_repositories
908
901
if len(my_fb) != len(other_fb):
1318
1306
return self._real_repository.make_working_trees()
1320
1308
def refresh_data(self):
1321
"""Re-read any data needed to synchronise with disk.
1309
"""Re-read any data needed to to synchronise with disk.
1323
1311
This method is intended to be called after another repository instance
1324
1312
(such as one used by a smart server) has inserted data into the
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.
1313
repository. It may not be called during a write group, but may be
1314
called at any other time.
1316
if self.is_in_write_group():
1317
raise errors.InternalBzrError(
1318
"May not refresh_data while in a write group.")
1331
1319
if self._real_repository is not None:
1332
1320
self._real_repository.refresh_data()
1347
1335
@needs_read_lock
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):
1336
def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1351
1337
"""Return the revision ids that other has that this does not.
1353
1339
These are returned in topological order.
1355
1341
revision_id: only return revision ids included by revision_id.
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)
1343
return repository.InterRepository.get(
1344
other, self).search_missing_revision_ids(revision_id, find_ghosts)
1372
def fetch(self, source, revision_id=None, find_ghosts=False,
1346
def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
1373
1347
fetch_spec=None):
1374
1348
# No base implementation to use as RemoteRepository is not a subclass
1375
1349
# of Repository; so this is a copy of Repository.fetch().
1393
1367
# the InterRepository base class, which raises an
1394
1368
# IncompatibleRepositories when asked to fetch.
1395
1369
inter = repository.InterRepository.get(source, self)
1396
return inter.fetch(revision_id=revision_id,
1370
return inter.fetch(revision_id=revision_id, pb=pb,
1397
1371
find_ghosts=find_ghosts, fetch_spec=fetch_spec)
1399
1373
def create_bundle(self, target, base, fileobj, format=None):
1774
1748
return '\n'.join((start_keys, stop_keys, count))
1776
1750
def _serialise_search_result(self, search_result):
1777
parts = search_result.get_network_struct()
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)]
1778
1757
return '\n'.join(parts)
1780
1759
def autopack(self):
1984
1962
verb, args, search_bytes)
1985
1963
except errors.UnknownSmartMethod:
1986
1964
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))
1999
1966
response_tuple, response_handler = response
2000
1967
found_verb = True
2004
1971
if response_tuple[0] != 'ok':
2005
1972
raise errors.UnexpectedSmartServerResponse(response_tuple)
2006
1973
byte_stream = response_handler.read_streamed_body()
2007
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
2008
self._record_counter)
1974
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
2009
1975
if src_format.network_name() != repo._format.network_name():
2010
1976
raise AssertionError(
2011
1977
"Mismatched RemoteRepository and stream src %r, %r" % (
2149
2115
# Turn the response into a RemoteRepository object.
2150
2116
format = RemoteBranchFormat(network_name=response[1])
2151
2117
repo_format = response_tuple_to_repo_format(response[3:])
2152
repo_path = response[2]
2153
if repository is not None:
2154
remote_repo_url = urlutils.join(medium.base, 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, medium.base, repo_path))
2162
remote_repo = repository
2118
if response[2] == '':
2119
repo_bzrdir = a_bzrdir
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)
2121
repo_bzrdir = RemoteBzrDir(
2122
a_bzrdir.root_transport.clone(response[2]), a_bzrdir._format,
2124
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2171
2125
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2172
2126
format=format, setup_stacking=False, name=name)
2173
2127
# XXX: We know this is a new branch, so it must have revno 0, revid
2194
2148
self._ensure_real()
2195
2149
return self._custom_format.supports_set_append_revisions_only()
2197
def _native_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 free 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:
2211
2152
class RemoteBranch(branch.Branch, _RpcHelper, lock._RelockDebugMixin):
2212
2153
"""Branch stored on a server accessed by HPSS RPC.
2416
2357
self._ensure_real()
2417
2358
return self._real_branch._get_tags_bytes()
2420
2360
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):
2426
2361
medium = self._client._medium
2427
2362
if medium._is_remote_before((1, 13)):
2428
2363
return self._vfs_get_tags_bytes()
2467
2396
self._real_branch.lock_read()
2469
2398
self._lock_count += 1
2470
return lock.LogicalLockResult(self.unlock)
2472
2400
def _remote_lock_write(self, token):
2473
2401
if token is None:
2474
2402
branch_token = repo_token = ''
2476
2404
branch_token = token
2477
repo_token = self.repository.lock_write().repository_token
2405
repo_token = self.repository.lock_write()
2478
2406
self.repository.unlock()
2479
2407
err_context = {'token': token}
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])
2408
response = self._call(
2409
'Branch.lock_write', self._remote_path(), branch_token,
2410
repo_token or '', **err_context)
2490
2411
if response[0] != 'ok':
2491
2412
raise errors.UnexpectedSmartServerResponse(response)
2492
2413
ok, branch_token, repo_token = response
2524
2445
self._lock_count += 1
2525
2446
# Re-lock the repository too.
2526
2447
self.repository.lock_write(self._repo_lock_token)
2527
return BranchWriteLockResult(self.unlock, self._lock_token or None)
2448
return self._lock_token or None
2529
2450
def _unlock(self, branch_token, repo_token):
2530
2451
err_context = {'token': str((branch_token, repo_token))}
2794
2715
self._ensure_real()
2795
2716
return self._real_branch.set_push_location(location)
2797
def heads_to_fetch(self):
2798
if self._format._native_heads_to_fetch():
2799
return branch.Branch.heads_to_fetch(self)
2800
medium = self._client._medium
2801
if medium._is_remote_before((2, 4)):
2802
return self._vfs_heads_to_fetch()
2804
return self._rpc_heads_to_fetch()
2805
except errors.UnknownSmartMethod:
2806
medium._remember_remote_is_before((2, 4))
2807
return self._vfs_heads_to_fetch()
2809
def _rpc_heads_to_fetch(self):
2810
response = self._call('Branch.heads_to_fetch', self._remote_path())
2811
if len(response) != 2:
2812
raise errors.UnexpectedSmartServerResponse(response)
2813
must_fetch, if_present_fetch = response
2814
return set(must_fetch), set(if_present_fetch)
2816
def _vfs_heads_to_fetch(self):
2818
return self._real_branch.heads_to_fetch()
2821
2719
class RemoteConfig(object):
2822
2720
"""A Config that reads and writes from smart verbs.
2876
2774
medium = self._branch._client._medium
2877
2775
if medium._is_remote_before((1, 14)):
2878
2776
return self._vfs_set_option(value, name, section)
2879
if isinstance(value, dict):
2880
if medium._is_remote_before((2, 2)):
2881
return self._vfs_set_option(value, name, section)
2882
return self._set_config_option_dict(value, name, section)
2884
return self._set_config_option(value, name, section)
2886
def _set_config_option(self, value, name, section):
2888
2778
path = self._branch._remote_path()
2889
2779
response = self._branch._client.call('Branch.set_config_option',
2890
2780
path, self._branch._lock_token, self._branch._repo_lock_token,
2891
2781
value.encode('utf8'), name, section or '')
2892
2782
except errors.UnknownSmartMethod:
2893
medium = self._branch._client._medium
2894
2783
medium._remember_remote_is_before((1, 14))
2895
2784
return self._vfs_set_option(value, name, section)
2896
2785
if response != ():
2897
2786
raise errors.UnexpectedSmartServerResponse(response)
2899
def _serialize_option_dict(self, option_dict):
2901
for key, value in option_dict.items():
2902
if isinstance(key, unicode):
2903
key = key.encode('utf8')
2904
if isinstance(value, unicode):
2905
value = value.encode('utf8')
2906
utf8_dict[key] = value
2907
return bencode.bencode(utf8_dict)
2909
def _set_config_option_dict(self, value, name, section):
2911
path = self._branch._remote_path()
2912
serialised_dict = self._serialize_option_dict(value)
2913
response = self._branch._client.call(
2914
'Branch.set_config_option_dict',
2915
path, self._branch._lock_token, self._branch._repo_lock_token,
2916
serialised_dict, name, section or '')
2917
except errors.UnknownSmartMethod:
2918
medium = self._branch._client._medium
2919
medium._remember_remote_is_before((2, 2))
2920
return self._vfs_set_option(value, name, section)
2922
raise errors.UnexpectedSmartServerResponse(response)
2924
2788
def _real_object(self):
2925
2789
self._branch._ensure_real()
2926
2790
return self._branch._real_branch