911
917
if isinstance(repository, RemoteRepository):
912
918
raise AssertionError()
913
919
self._real_repository = repository
914
# If the _real_repository has _fallback_repositories, clear them out,
915
# because we want it to have the same set as this repository. This is
916
# reasonable to do because the fallbacks we clear here are from a
917
# "real" branch, and we're about to replace them with the equivalents
918
# from a RemoteBranch.
919
self._real_repository._fallback_repositories = []
920
# three code paths happen here:
921
# 1) old servers, RemoteBranch.open() calls _ensure_real before setting
922
# up stacking. In this case self._fallback_repositories is [], and the
923
# real repo is already setup. Preserve the real repo and
924
# RemoteRepository.add_fallback_repository will avoid adding
926
# 2) new servers, RemoteBranch.open() sets up stacking, and when
927
# ensure_real is triggered from a branch, the real repository to
928
# set already has a matching list with separate instances, but
929
# as they are also RemoteRepositories we don't worry about making the
930
# lists be identical.
931
# 3) new servers, RemoteRepository.ensure_real is triggered before
932
# RemoteBranch.ensure real, in this case we get a repo with no fallbacks
933
# and need to populate it.
934
if (self._fallback_repositories and
935
len(self._real_repository._fallback_repositories) !=
936
len(self._fallback_repositories)):
937
if len(self._real_repository._fallback_repositories):
938
raise AssertionError(
939
"cannot cleanly remove existing _fallback_repositories")
920
940
for fb in self._fallback_repositories:
921
941
self._real_repository.add_fallback_repository(fb)
922
942
if self._lock_mode == 'w':
1051
1071
# _real_branch had its get_stacked_on_url method called), then the
1052
1072
# repository to be added may already be in the _real_repositories list.
1053
1073
if self._real_repository is not None:
1054
if repository not in self._real_repository._fallback_repositories:
1074
fallback_locations = [repo.bzrdir.root_transport.base for repo in
1075
self._real_repository._fallback_repositories]
1076
if repository.bzrdir.root_transport.base not in fallback_locations:
1055
1077
self._real_repository.add_fallback_repository(repository)
1057
# They are also seen by the fallback repository. If it doesn't
1058
# exist yet they'll be added then. This implicitly copies them.
1061
1079
def add_inventory(self, revid, inv, parents):
1062
1080
self._ensure_real()
1261
1279
# We don't need to send ghosts back to the server as a position to
1263
1281
stop_keys.difference_update(self._unstacked_provider.missing_keys)
1282
key_count = len(parents_map)
1283
if (NULL_REVISION in result_parents
1284
and NULL_REVISION in self._unstacked_provider.missing_keys):
1285
# If we pruned NULL_REVISION from the stop_keys because it's also
1286
# in our cache of "missing" keys we need to increment our key count
1287
# by 1, because the reconsitituted SearchResult on the server will
1288
# still consider NULL_REVISION to be an included key.
1264
1290
included_keys = start_set.intersection(result_parents)
1265
1291
start_set.difference_update(included_keys)
1266
recipe = ('manual', start_set, stop_keys, len(parents_map))
1292
recipe = ('manual', start_set, stop_keys, key_count)
1267
1293
body = self._serialise_search_recipe(recipe)
1268
1294
path = self.bzrdir._path_for_remote_call(self._client)
1269
1295
for key in keys:
1926
1952
except (errors.NotStacked, errors.UnstackableBranchFormat,
1927
1953
errors.UnstackableRepositoryFormat), e:
1929
# it's relative to this branch...
1930
fallback_url = urlutils.join(self.base, fallback_url)
1931
transports = [self.bzrdir.root_transport]
1932
stacked_on = branch.Branch.open(fallback_url,
1933
possible_transports=transports)
1934
self.repository.add_fallback_repository(stacked_on.repository)
1955
self._activate_fallback_location(fallback_url)
1957
def _get_config(self):
1958
return RemoteBranchConfig(self)
1936
1960
def _get_real_transport(self):
1937
1961
# if we try vfs access, return the real branch's vfs transport
2279
2303
self._ensure_real()
2280
2304
return self._real_branch._set_parent_location(url)
2282
def set_stacked_on_url(self, stacked_location):
2283
"""Set the URL this branch is stacked against.
2285
:raises UnstackableBranchFormat: If the branch does not support
2287
:raises UnstackableRepositoryFormat: If the repository does not support
2291
return self._real_branch.set_stacked_on_url(stacked_location)
2293
2306
@needs_write_lock
2294
2307
def pull(self, source, overwrite=False, stop_revision=None,
2362
2375
return self._real_branch.set_push_location(location)
2378
class RemoteBranchConfig(object):
2379
"""A Config that reads from a smart branch and writes via smart methods.
2381
It is a low-level object that considers config data to be name/value pairs
2382
that may be associated with a section. Assigning meaning to the these
2383
values is done at higher levels like bzrlib.config.TreeConfig.
2386
def __init__(self, branch):
2387
self._branch = branch
2389
def get_option(self, name, section=None, default=None):
2390
"""Return the value associated with a named option.
2392
:param name: The name of the value
2393
:param section: The section the option is in (if any)
2394
:param default: The value to return if the value is not set
2395
:return: The value or default value
2397
configobj = self._get_configobj()
2399
section_obj = configobj
2402
section_obj = configobj[section]
2405
return section_obj.get(name, default)
2407
def _get_configobj(self):
2408
path = self._branch._remote_path()
2409
response = self._branch._client.call_expecting_body(
2410
'Branch.get_config_file', path)
2411
if response[0][0] != 'ok':
2412
raise UnexpectedSmartServerResponse(response)
2413
lines = response[1].read_body_bytes().splitlines()
2414
return config.ConfigObj(lines, encoding='utf-8')
2416
def set_option(self, value, name, section=None):
2417
"""Set the value associated with a named option.
2419
:param value: The value to set
2420
:param name: The name of the value to set
2421
:param section: The section the option is in (if any)
2423
medium = self._branch._client._medium
2424
if medium._is_remote_before((1, 14)):
2425
return self._vfs_set_option(value, name, section)
2427
path = self._branch._remote_path()
2428
response = self._branch._client.call('Branch.set_config_option',
2429
path, self._branch._lock_token, self._branch._repo_lock_token,
2430
value.encode('utf8'), name, section or '')
2431
except errors.UnknownSmartMethod:
2432
medium._remember_remote_is_before((1, 14))
2433
return self._vfs_set_option(value, name, section)
2435
raise errors.UnexpectedSmartServerResponse(response)
2437
def _vfs_set_option(self, value, name, section=None):
2438
self._branch._ensure_real()
2439
return self._branch._real_branch._get_config().set_option(
2440
value, name, section)
2365
2443
def _extract_tar(tar, to_dir):
2366
2444
"""Extract all the contents of a tarfile object.