921
928
if isinstance(repository, RemoteRepository):
922
929
raise AssertionError()
923
930
self._real_repository = repository
924
# If the _real_repository has _fallback_repositories, clear them out,
925
# because we want it to have the same set as this repository. This is
926
# reasonable to do because the fallbacks we clear here are from a
927
# "real" branch, and we're about to replace them with the equivalents
928
# from a RemoteBranch.
929
self._real_repository._fallback_repositories = []
931
# three code paths happen here:
932
# 1) old servers, RemoteBranch.open() calls _ensure_real before setting
933
# up stacking. In this case self._fallback_repositories is [], and the
934
# real repo is already setup. Preserve the real repo and
935
# RemoteRepository.add_fallback_repository will avoid adding
937
# 2) new servers, RemoteBranch.open() sets up stacking, and when
938
# ensure_real is triggered from a branch, the real repository to
939
# set already has a matching list with separate instances, but
940
# as they are also RemoteRepositories we don't worry about making the
941
# lists be identical.
942
# 3) new servers, RemoteRepository.ensure_real is triggered before
943
# RemoteBranch.ensure real, in this case we get a repo with no fallbacks
944
# and need to populate it.
945
if (self._fallback_repositories and
946
len(self._real_repository._fallback_repositories) !=
947
len(self._fallback_repositories)):
948
if len(self._real_repository._fallback_repositories):
949
raise AssertionError(
950
"cannot cleanly remove existing _fallback_repositories")
930
951
for fb in self._fallback_repositories:
931
952
self._real_repository.add_fallback_repository(fb)
932
953
if self._lock_mode == 'w':
1271
1290
# We don't need to send ghosts back to the server as a position to
1273
1292
stop_keys.difference_update(self._unstacked_provider.missing_keys)
1293
key_count = len(parents_map)
1294
if (NULL_REVISION in result_parents
1295
and NULL_REVISION in self._unstacked_provider.missing_keys):
1296
# If we pruned NULL_REVISION from the stop_keys because it's also
1297
# in our cache of "missing" keys we need to increment our key count
1298
# by 1, because the reconsitituted SearchResult on the server will
1299
# still consider NULL_REVISION to be an included key.
1274
1301
included_keys = start_set.intersection(result_parents)
1275
1302
start_set.difference_update(included_keys)
1276
recipe = ('manual', start_set, stop_keys, len(parents_map))
1303
recipe = ('manual', start_set, stop_keys, key_count)
1277
1304
body = self._serialise_search_recipe(recipe)
1278
1305
path = self.bzrdir._path_for_remote_call(self._client)
1279
1306
for key in keys:
1936
1963
except (errors.NotStacked, errors.UnstackableBranchFormat,
1937
1964
errors.UnstackableRepositoryFormat), e:
1939
# it's relative to this branch...
1940
fallback_url = urlutils.join(self.base, fallback_url)
1941
transports = [self.bzrdir.root_transport]
1942
stacked_on = branch.Branch.open(fallback_url,
1943
possible_transports=transports)
1944
self.repository.add_fallback_repository(stacked_on.repository)
1966
self._activate_fallback_location(fallback_url, None)
1968
def _get_config(self):
1969
return RemoteBranchConfig(self)
1946
1971
def _get_real_transport(self):
1947
1972
# if we try vfs access, return the real branch's vfs transport
2277
2302
self._ensure_real()
2278
2303
return self._real_branch._get_parent_location()
2280
def set_parent(self, url):
2282
return self._real_branch.set_parent(url)
2284
2305
def _set_parent_location(self, url):
2285
# Used by tests, to poke bad urls into branch configurations
2287
self.set_parent(url)
2290
return self._real_branch._set_parent_location(url)
2292
def set_stacked_on_url(self, stacked_location):
2293
"""Set the URL this branch is stacked against.
2295
:raises UnstackableBranchFormat: If the branch does not support
2297
:raises UnstackableRepositoryFormat: If the repository does not support
2306
medium = self._client._medium
2307
if medium._is_remote_before((1, 15)):
2308
return self._vfs_set_parent_location(url)
2310
call_url = url or ''
2311
if type(call_url) is not str:
2312
raise AssertionError('url must be a str or None (%s)' % url)
2313
response = self._call('Branch.set_parent_location',
2314
self._remote_path(), self._lock_token, self._repo_lock_token,
2316
except errors.UnknownSmartMethod:
2317
medium._remember_remote_is_before((1, 15))
2318
return self._vfs_set_parent_location(url)
2320
raise errors.UnexpectedSmartServerResponse(response)
2322
def _vfs_set_parent_location(self, url):
2300
2323
self._ensure_real()
2301
return self._real_branch.set_stacked_on_url(stacked_location)
2324
return self._real_branch._set_parent_location(url)
2303
2326
@needs_write_lock
2304
2327
def pull(self, source, overwrite=False, stop_revision=None,
2372
2395
return self._real_branch.set_push_location(location)
2398
class RemoteConfig(object):
2399
"""A Config that reads and writes from smart verbs.
2401
It is a low-level object that considers config data to be name/value pairs
2402
that may be associated with a section. Assigning meaning to the these
2403
values is done at higher levels like bzrlib.config.TreeConfig.
2406
def get_option(self, name, section=None, default=None):
2407
"""Return the value associated with a named option.
2409
:param name: The name of the value
2410
:param section: The section the option is in (if any)
2411
:param default: The value to return if the value is not set
2412
:return: The value or default value
2415
configobj = self._get_configobj()
2417
section_obj = configobj
2420
section_obj = configobj[section]
2423
return section_obj.get(name, default)
2424
except errors.UnknownSmartMethod:
2425
return self._vfs_get_option(name, section, default)
2427
def _response_to_configobj(self, response):
2428
if len(response[0]) and response[0][0] != 'ok':
2429
raise errors.UnexpectedSmartServerResponse(response)
2430
lines = response[1].read_body_bytes().splitlines()
2431
return config.ConfigObj(lines, encoding='utf-8')
2434
class RemoteBranchConfig(RemoteConfig):
2435
"""A RemoteConfig for Branches."""
2437
def __init__(self, branch):
2438
self._branch = branch
2440
def _get_configobj(self):
2441
path = self._branch._remote_path()
2442
response = self._branch._client.call_expecting_body(
2443
'Branch.get_config_file', path)
2444
return self._response_to_configobj(response)
2446
def set_option(self, value, name, section=None):
2447
"""Set the value associated with a named option.
2449
:param value: The value to set
2450
:param name: The name of the value to set
2451
:param section: The section the option is in (if any)
2453
medium = self._branch._client._medium
2454
if medium._is_remote_before((1, 14)):
2455
return self._vfs_set_option(value, name, section)
2457
path = self._branch._remote_path()
2458
response = self._branch._client.call('Branch.set_config_option',
2459
path, self._branch._lock_token, self._branch._repo_lock_token,
2460
value.encode('utf8'), name, section or '')
2461
except errors.UnknownSmartMethod:
2462
medium._remember_remote_is_before((1, 14))
2463
return self._vfs_set_option(value, name, section)
2465
raise errors.UnexpectedSmartServerResponse(response)
2467
def _real_object(self):
2468
self._branch._ensure_real()
2469
return self._branch._real_branch
2471
def _vfs_set_option(self, value, name, section=None):
2472
return self._real_object()._get_config().set_option(
2473
value, name, section)
2476
class RemoteBzrDirConfig(RemoteConfig):
2477
"""A RemoteConfig for BzrDirs."""
2479
def __init__(self, bzrdir):
2480
self._bzrdir = bzrdir
2482
def _get_configobj(self):
2483
medium = self._bzrdir._client._medium
2484
verb = 'BzrDir.get_config_file'
2485
if medium._is_remote_before((1, 15)):
2486
raise errors.UnknownSmartMethod(verb)
2487
path = self._bzrdir._path_for_remote_call(self._bzrdir._client)
2488
response = self._bzrdir._call_expecting_body(
2490
return self._response_to_configobj(response)
2492
def _vfs_get_option(self, name, section, default):
2493
return self._real_object()._get_config().get_option(
2494
name, section, default)
2496
def set_option(self, value, name, section=None):
2497
"""Set the value associated with a named option.
2499
:param value: The value to set
2500
:param name: The name of the value to set
2501
:param section: The section the option is in (if any)
2503
return self._real_object()._get_config().set_option(
2504
value, name, section)
2506
def _real_object(self):
2507
self._bzrdir._ensure_real()
2508
return self._bzrdir._real_bzrdir
2375
2512
def _extract_tar(tar, to_dir):
2376
2513
"""Extract all the contents of a tarfile object.