30
repository as _mod_repository,
31
32
revision as _mod_revision,
34
from bzrlib.branch import BranchReferenceFormat
36
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
35
37
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
36
38
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
37
39
from bzrlib.errors import (
242
245
self._ensure_real()
243
246
self._real_bzrdir.destroy_repository()
245
def create_branch(self):
248
def create_branch(self, name=None):
246
249
# as per meta1 formats - just delegate to the format object which may
247
250
# be parameterised.
248
real_branch = self._format.get_branch_format().initialize(self)
251
real_branch = self._format.get_branch_format().initialize(self,
249
253
if not isinstance(real_branch, RemoteBranch):
250
result = RemoteBranch(self, self.find_repository(), real_branch)
254
result = RemoteBranch(self, self.find_repository(), real_branch,
252
257
result = real_branch
253
258
# BzrDir.clone_on_transport() uses the result of create_branch but does
259
264
self._next_open_branch_result = result
262
def destroy_branch(self):
267
def destroy_branch(self, name=None):
263
268
"""See BzrDir.destroy_branch"""
264
269
self._ensure_real()
265
self._real_bzrdir.destroy_branch()
270
self._real_bzrdir.destroy_branch(name=name)
266
271
self._next_open_branch_result = None
268
273
def create_workingtree(self, revision_id=None, from_branch=None):
269
274
raise errors.NotLocalUrl(self.transport.base)
271
def find_branch_format(self):
276
def find_branch_format(self, name=None):
272
277
"""Find the branch 'format' for this bzrdir.
274
279
This might be a synthetic object for e.g. RemoteBranch and SVN.
276
b = self.open_branch()
281
b = self.open_branch(name=name)
279
def get_branch_reference(self):
284
def get_branch_reference(self, name=None):
280
285
"""See BzrDir.get_branch_reference()."""
287
# XXX JRV20100304: Support opening colocated branches
288
raise errors.NoColocatedBranchSupport(self)
281
289
response = self._get_branch_reference()
282
290
if response[0] == 'ref':
283
291
return response[1]
314
322
raise errors.UnexpectedSmartServerResponse(response)
317
def _get_tree_branch(self):
325
def _get_tree_branch(self, name=None):
318
326
"""See BzrDir._get_tree_branch()."""
319
return None, self.open_branch()
327
return None, self.open_branch(name=name)
321
def open_branch(self, _unsupported=False, ignore_fallbacks=False):
329
def open_branch(self, name=None, unsupported=False,
330
ignore_fallbacks=False):
323
332
raise NotImplementedError('unsupported flag support not implemented yet.')
324
333
if self._next_open_branch_result is not None:
325
334
# See create_branch for details.
330
339
if response[0] == 'ref':
331
340
# a branch reference, use the existing BranchReference logic.
332
341
format = BranchReferenceFormat()
333
return format.open(self, _found=True, location=response[1],
334
ignore_fallbacks=ignore_fallbacks)
342
return format.open(self, name=name, _found=True,
343
location=response[1], ignore_fallbacks=ignore_fallbacks)
335
344
branch_format_name = response[1]
336
345
if not branch_format_name:
337
346
branch_format_name = None
338
347
format = RemoteBranchFormat(network_name=branch_format_name)
339
348
return RemoteBranch(self, self.find_repository(), format=format,
340
setup_stacking=not ignore_fallbacks)
349
setup_stacking=not ignore_fallbacks, name=name)
342
351
def _open_repo_v1(self, path):
343
352
verb = 'BzrDir.find_repository'
420
429
"""Return the path to be used for this bzrdir in a remote call."""
421
430
return client.remote_path_from_transport(self.root_transport)
423
def get_branch_transport(self, branch_format):
432
def get_branch_transport(self, branch_format, name=None):
424
433
self._ensure_real()
425
return self._real_bzrdir.get_branch_transport(branch_format)
434
return self._real_bzrdir.get_branch_transport(branch_format, name=name)
427
436
def get_repository_transport(self, repository_format):
428
437
self._ensure_real()
687
697
# Additional places to query for data.
688
698
self._fallback_repositories = []
701
def user_transport(self):
702
return self.bzrdir.user_transport
705
def control_transport(self):
706
# XXX: Normally you shouldn't directly get at the remote repository
707
# transport, but I'm not sure it's worth making this method
708
# optional -- mbp 2010-04-21
709
return self.bzrdir.get_repository_transport(None)
690
711
def __str__(self):
691
712
return "%s(%s)" % (self.__class__.__name__, self.base)
878
899
def _has_same_fallbacks(self, other_repo):
879
900
"""Returns true if the repositories have the same fallbacks."""
880
901
# XXX: copied from Repository; it should be unified into a base class
881
# <https://bugs.edge.launchpad.net/bzr/+bug/401622>
902
# <https://bugs.launchpad.net/bzr/+bug/401622>
882
903
my_fb = self._fallback_repositories
883
904
other_fb = other_repo._fallback_repositories
884
905
if len(my_fb) != len(other_fb):
900
921
parents_provider = self._make_parents_provider(other_repository)
901
922
return graph.Graph(parents_provider)
925
def get_known_graph_ancestry(self, revision_ids):
926
"""Return the known graph for a set of revision ids and their ancestors.
928
st = static_tuple.StaticTuple
929
revision_keys = [st(r_id).intern() for r_id in revision_ids]
930
known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
931
return graph.GraphThunkIdsToKeys(known_graph)
903
933
def gather_stats(self, revid=None, committers=None):
904
934
"""See Repository.gather_stats()."""
905
935
path = self.bzrdir._path_for_remote_call(self._client)
1214
1249
# state, so always add a lock here. If a caller passes us a locked
1215
1250
# repository, they are responsible for unlocking it later.
1216
1251
repository.lock_read()
1252
self._check_fallback_repository(repository)
1217
1253
self._fallback_repositories.append(repository)
1218
1254
# If self._real_repository was parameterised already (e.g. because a
1219
1255
# _real_branch had its get_stacked_on_url method called), then the
1220
1256
# repository to be added may already be in the _real_repositories list.
1221
1257
if self._real_repository is not None:
1222
fallback_locations = [repo.bzrdir.root_transport.base for repo in
1258
fallback_locations = [repo.user_url for repo in
1223
1259
self._real_repository._fallback_repositories]
1224
if repository.bzrdir.root_transport.base not in fallback_locations:
1260
if repository.user_url not in fallback_locations:
1225
1261
self._real_repository.add_fallback_repository(repository)
1263
def _check_fallback_repository(self, repository):
1264
"""Check that this repository can fallback to repository safely.
1266
Raise an error if not.
1268
:param repository: A repository to fallback to.
1270
return _mod_repository.InterRepository._assert_same_model(
1227
1273
def add_inventory(self, revid, inv, parents):
1228
1274
self._ensure_real()
1229
1275
return self._real_repository.add_inventory(revid, inv, parents)
1231
1277
def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1278
parents, basis_inv=None, propagate_caches=False):
1233
1279
self._ensure_real()
1234
1280
return self._real_repository.add_inventory_by_delta(basis_revision_id,
1235
delta, new_revision_id, parents)
1281
delta, new_revision_id, parents, basis_inv=basis_inv,
1282
propagate_caches=propagate_caches)
1237
1284
def add_revision(self, rev_id, rev, inv=None, config=None):
1238
1285
self._ensure_real()
1268
1315
return self._real_repository.make_working_trees()
1270
1317
def refresh_data(self):
1271
"""Re-read any data needed to to synchronise with disk.
1318
"""Re-read any data needed to synchronise with disk.
1273
1320
This method is intended to be called after another repository instance
1274
1321
(such as one used by a smart server) has inserted data into the
1275
repository. It may not be called during a write group, but may be
1276
called at any other time.
1322
repository. On all repositories this will work outside of write groups.
1323
Some repository formats (pack and newer for bzrlib native formats)
1324
support refresh_data inside write groups. If called inside a write
1325
group on a repository that does not support refreshing in a write group
1326
IsInWriteGroupError will be raised.
1278
if self.is_in_write_group():
1279
raise errors.InternalBzrError(
1280
"May not refresh_data while in a write group.")
1281
1328
if self._real_repository is not None:
1282
1329
self._real_repository.refresh_data()
1501
1548
self._ensure_real()
1502
1549
return self._real_repository._get_inventory_xml(revision_id)
1504
def _deserialise_inventory(self, revision_id, xml):
1506
return self._real_repository._deserialise_inventory(revision_id, xml)
1508
1551
def reconcile(self, other=None, thorough=False):
1509
1552
self._ensure_real()
1510
1553
return self._real_repository.reconcile(other=other, thorough=thorough)
1585
1628
return self._real_repository.inventories
1587
1630
@needs_write_lock
1588
def pack(self, hint=None):
1631
def pack(self, hint=None, clean_obsolete_packs=False):
1589
1632
"""Compress the data within the repository.
1591
1634
This is not currently implemented within the smart server.
1593
1636
self._ensure_real()
1594
return self._real_repository.pack(hint=hint)
1637
return self._real_repository.pack(hint=hint, clean_obsolete_packs=clean_obsolete_packs)
1597
1640
def revisions(self):
1937
1980
if response_tuple[0] != 'ok':
1938
1981
raise errors.UnexpectedSmartServerResponse(response_tuple)
1939
1982
byte_stream = response_handler.read_streamed_body()
1940
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
1983
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
1984
self._record_counter)
1941
1985
if src_format.network_name() != repo._format.network_name():
1942
1986
raise AssertionError(
1943
1987
"Mismatched RemoteRepository and stream src %r, %r" % (
2025
2069
def network_name(self):
2026
2070
return self._network_name
2028
def open(self, a_bzrdir, ignore_fallbacks=False):
2029
return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2072
def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
2073
return a_bzrdir.open_branch(name=name,
2074
ignore_fallbacks=ignore_fallbacks)
2031
def _vfs_initialize(self, a_bzrdir):
2076
def _vfs_initialize(self, a_bzrdir, name):
2032
2077
# Initialisation when using a local bzrdir object, or a non-vfs init
2033
2078
# method is not available on the server.
2034
2079
# self._custom_format is always set - the start of initialize ensures
2036
2081
if isinstance(a_bzrdir, RemoteBzrDir):
2037
2082
a_bzrdir._ensure_real()
2038
result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
2083
result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
2040
2086
# We assume the bzrdir is parameterised; it may not be.
2041
result = self._custom_format.initialize(a_bzrdir)
2087
result = self._custom_format.initialize(a_bzrdir, name)
2042
2088
if (isinstance(a_bzrdir, RemoteBzrDir) and
2043
2089
not isinstance(result, RemoteBranch)):
2044
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
2090
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
2047
def initialize(self, a_bzrdir):
2094
def initialize(self, a_bzrdir, name=None):
2048
2095
# 1) get the network name to use.
2049
2096
if self._custom_format:
2050
2097
network_name = self._custom_format.network_name()
2056
2103
network_name = reference_format.network_name()
2057
2104
# Being asked to create on a non RemoteBzrDir:
2058
2105
if not isinstance(a_bzrdir, RemoteBzrDir):
2059
return self._vfs_initialize(a_bzrdir)
2106
return self._vfs_initialize(a_bzrdir, name=name)
2060
2107
medium = a_bzrdir._client._medium
2061
2108
if medium._is_remote_before((1, 13)):
2062
return self._vfs_initialize(a_bzrdir)
2109
return self._vfs_initialize(a_bzrdir, name=name)
2063
2110
# Creating on a remote bzr dir.
2064
2111
# 2) try direct creation via RPC
2065
2112
path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
2113
if name is not None:
2114
# XXX JRV20100304: Support creating colocated branches
2115
raise errors.NoColocatedBranchSupport(self)
2066
2116
verb = 'BzrDir.create_branch'
2068
2118
response = a_bzrdir._call(verb, path, network_name)
2069
2119
except errors.UnknownSmartMethod:
2070
2120
# Fallback - use vfs methods
2071
2121
medium._remember_remote_is_before((1, 13))
2072
return self._vfs_initialize(a_bzrdir)
2122
return self._vfs_initialize(a_bzrdir, name=name)
2073
2123
if response[0] != 'ok':
2074
2124
raise errors.UnexpectedSmartServerResponse(response)
2075
2125
# Turn the response into a RemoteRepository object.
2083
2133
a_bzrdir._client)
2084
2134
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2085
2135
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2086
format=format, setup_stacking=False)
2136
format=format, setup_stacking=False, name=name)
2087
2137
# XXX: We know this is a new branch, so it must have revno 0, revid
2088
2138
# NULL_REVISION. Creating the branch locked would make this be unable
2089
2139
# to be wrong; here its simply very unlikely to be wrong. RBC 20090225
2118
2168
def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
2119
_client=None, format=None, setup_stacking=True):
2169
_client=None, format=None, setup_stacking=True, name=None):
2120
2170
"""Create a RemoteBranch instance.
2122
2172
:param real_branch: An optional local implementation of the branch
2223
2276
'to use vfs implementation')
2224
2277
self.bzrdir._ensure_real()
2225
2278
self._real_branch = self.bzrdir._real_bzrdir.open_branch(
2226
ignore_fallbacks=self._real_ignore_fallbacks)
2279
ignore_fallbacks=self._real_ignore_fallbacks, name=self._name)
2227
2280
if self.repository._real_repository is None:
2228
2281
# Give the remote repository the matching real repo.
2229
2282
real_repo = self._real_branch.repository
2353
2410
self._real_branch.lock_read()
2355
2412
self._lock_count += 1
2413
return lock.LogicalLockResult(self.unlock)
2357
2415
def _remote_lock_write(self, token):
2358
2416
if token is None:
2359
2417
branch_token = repo_token = ''
2361
2419
branch_token = token
2362
repo_token = self.repository.lock_write()
2420
repo_token = self.repository.lock_write().repository_token
2363
2421
self.repository.unlock()
2364
2422
err_context = {'token': token}
2365
response = self._call(
2366
'Branch.lock_write', self._remote_path(), branch_token,
2367
repo_token or '', **err_context)
2424
response = self._call(
2425
'Branch.lock_write', self._remote_path(), branch_token,
2426
repo_token or '', **err_context)
2427
except errors.LockContention, e:
2428
# The LockContention from the server doesn't have any
2429
# information about the lock_url. We re-raise LockContention
2430
# with valid lock_url.
2431
raise errors.LockContention('(remote lock)',
2432
self.repository.base.split('.bzr/')[0])
2368
2433
if response[0] != 'ok':
2369
2434
raise errors.UnexpectedSmartServerResponse(response)
2370
2435
ok, branch_token, repo_token = response
2402
2467
self._lock_count += 1
2403
2468
# Re-lock the repository too.
2404
2469
self.repository.lock_write(self._repo_lock_token)
2405
return self._lock_token or None
2470
return BranchWriteLockResult(self.unlock, self._lock_token or None)
2407
2472
def _unlock(self, branch_token, repo_token):
2408
2473
err_context = {'token': str((branch_token, repo_token))}
2731
2796
medium = self._branch._client._medium
2732
2797
if medium._is_remote_before((1, 14)):
2733
2798
return self._vfs_set_option(value, name, section)
2799
if isinstance(value, dict):
2800
if medium._is_remote_before((2, 2)):
2801
return self._vfs_set_option(value, name, section)
2802
return self._set_config_option_dict(value, name, section)
2804
return self._set_config_option(value, name, section)
2806
def _set_config_option(self, value, name, section):
2735
2808
path = self._branch._remote_path()
2736
2809
response = self._branch._client.call('Branch.set_config_option',
2737
2810
path, self._branch._lock_token, self._branch._repo_lock_token,
2738
2811
value.encode('utf8'), name, section or '')
2739
2812
except errors.UnknownSmartMethod:
2813
medium = self._branch._client._medium
2740
2814
medium._remember_remote_is_before((1, 14))
2741
2815
return self._vfs_set_option(value, name, section)
2742
2816
if response != ():
2743
2817
raise errors.UnexpectedSmartServerResponse(response)
2819
def _serialize_option_dict(self, option_dict):
2821
for key, value in option_dict.items():
2822
if isinstance(key, unicode):
2823
key = key.encode('utf8')
2824
if isinstance(value, unicode):
2825
value = value.encode('utf8')
2826
utf8_dict[key] = value
2827
return bencode.bencode(utf8_dict)
2829
def _set_config_option_dict(self, value, name, section):
2831
path = self._branch._remote_path()
2832
serialised_dict = self._serialize_option_dict(value)
2833
response = self._branch._client.call(
2834
'Branch.set_config_option_dict',
2835
path, self._branch._lock_token, self._branch._repo_lock_token,
2836
serialised_dict, name, section or '')
2837
except errors.UnknownSmartMethod:
2838
medium = self._branch._client._medium
2839
medium._remember_remote_is_before((2, 2))
2840
return self._vfs_set_option(value, name, section)
2842
raise errors.UnexpectedSmartServerResponse(response)
2745
2844
def _real_object(self):
2746
2845
self._branch._ensure_real()
2747
2846
return self._branch._real_branch