31
repository as _mod_repository,
31
33
revision as _mod_revision,
34
from bzrlib.branch import BranchReferenceFormat
37
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
35
38
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
36
39
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
37
40
from bzrlib.errors import (
242
246
self._ensure_real()
243
247
self._real_bzrdir.destroy_repository()
245
def create_branch(self):
249
def create_branch(self, name=None):
246
250
# as per meta1 formats - just delegate to the format object which may
247
251
# be parameterised.
248
real_branch = self._format.get_branch_format().initialize(self)
252
real_branch = self._format.get_branch_format().initialize(self,
249
254
if not isinstance(real_branch, RemoteBranch):
250
result = RemoteBranch(self, self.find_repository(), real_branch)
255
result = RemoteBranch(self, self.find_repository(), real_branch,
252
258
result = real_branch
253
259
# BzrDir.clone_on_transport() uses the result of create_branch but does
259
265
self._next_open_branch_result = result
262
def destroy_branch(self):
268
def destroy_branch(self, name=None):
263
269
"""See BzrDir.destroy_branch"""
264
270
self._ensure_real()
265
self._real_bzrdir.destroy_branch()
271
self._real_bzrdir.destroy_branch(name=name)
266
272
self._next_open_branch_result = None
268
274
def create_workingtree(self, revision_id=None, from_branch=None,
269
275
accelerator_tree=None, hardlink=False):
270
276
raise errors.NotLocalUrl(self.transport.base)
272
def find_branch_format(self):
278
def find_branch_format(self, name=None):
273
279
"""Find the branch 'format' for this bzrdir.
275
281
This might be a synthetic object for e.g. RemoteBranch and SVN.
277
b = self.open_branch()
283
b = self.open_branch(name=name)
280
def get_branch_reference(self):
286
def get_branch_reference(self, name=None):
281
287
"""See BzrDir.get_branch_reference()."""
289
# XXX JRV20100304: Support opening colocated branches
290
raise errors.NoColocatedBranchSupport(self)
282
291
response = self._get_branch_reference()
283
292
if response[0] == 'ref':
284
293
return response[1]
315
324
raise errors.UnexpectedSmartServerResponse(response)
318
def _get_tree_branch(self):
327
def _get_tree_branch(self, name=None):
319
328
"""See BzrDir._get_tree_branch()."""
320
return None, self.open_branch()
329
return None, self.open_branch(name=name)
322
def open_branch(self, _unsupported=False, ignore_fallbacks=False):
331
def open_branch(self, name=None, unsupported=False,
332
ignore_fallbacks=False):
324
334
raise NotImplementedError('unsupported flag support not implemented yet.')
325
335
if self._next_open_branch_result is not None:
326
336
# See create_branch for details.
331
341
if response[0] == 'ref':
332
342
# a branch reference, use the existing BranchReference logic.
333
343
format = BranchReferenceFormat()
334
return format.open(self, _found=True, location=response[1],
335
ignore_fallbacks=ignore_fallbacks)
344
return format.open(self, name=name, _found=True,
345
location=response[1], ignore_fallbacks=ignore_fallbacks)
336
346
branch_format_name = response[1]
337
347
if not branch_format_name:
338
348
branch_format_name = None
339
349
format = RemoteBranchFormat(network_name=branch_format_name)
340
350
return RemoteBranch(self, self.find_repository(), format=format,
341
setup_stacking=not ignore_fallbacks)
351
setup_stacking=not ignore_fallbacks, name=name)
343
353
def _open_repo_v1(self, path):
344
354
verb = 'BzrDir.find_repository'
421
431
"""Return the path to be used for this bzrdir in a remote call."""
422
432
return client.remote_path_from_transport(self.root_transport)
424
def get_branch_transport(self, branch_format):
434
def get_branch_transport(self, branch_format, name=None):
425
435
self._ensure_real()
426
return self._real_bzrdir.get_branch_transport(branch_format)
436
return self._real_bzrdir.get_branch_transport(branch_format, name=name)
428
438
def get_repository_transport(self, repository_format):
429
439
self._ensure_real()
688
699
# Additional places to query for data.
689
700
self._fallback_repositories = []
703
def user_transport(self):
704
return self.bzrdir.user_transport
707
def control_transport(self):
708
# XXX: Normally you shouldn't directly get at the remote repository
709
# transport, but I'm not sure it's worth making this method
710
# optional -- mbp 2010-04-21
711
return self.bzrdir.get_repository_transport(None)
691
713
def __str__(self):
692
714
return "%s(%s)" % (self.__class__.__name__, self.base)
879
901
def _has_same_fallbacks(self, other_repo):
880
902
"""Returns true if the repositories have the same fallbacks."""
881
903
# XXX: copied from Repository; it should be unified into a base class
882
# <https://bugs.edge.launchpad.net/bzr/+bug/401622>
904
# <https://bugs.launchpad.net/bzr/+bug/401622>
883
905
my_fb = self._fallback_repositories
884
906
other_fb = other_repo._fallback_repositories
885
907
if len(my_fb) != len(other_fb):
901
923
parents_provider = self._make_parents_provider(other_repository)
902
924
return graph.Graph(parents_provider)
927
def get_known_graph_ancestry(self, revision_ids):
928
"""Return the known graph for a set of revision ids and their ancestors.
930
st = static_tuple.StaticTuple
931
revision_keys = [st(r_id).intern() for r_id in revision_ids]
932
known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
933
return graph.GraphThunkIdsToKeys(known_graph)
904
935
def gather_stats(self, revid=None, committers=None):
905
936
"""See Repository.gather_stats()."""
906
937
path = self.bzrdir._path_for_remote_call(self._client)
1215
1251
# state, so always add a lock here. If a caller passes us a locked
1216
1252
# repository, they are responsible for unlocking it later.
1217
1253
repository.lock_read()
1254
self._check_fallback_repository(repository)
1218
1255
self._fallback_repositories.append(repository)
1219
1256
# If self._real_repository was parameterised already (e.g. because a
1220
1257
# _real_branch had its get_stacked_on_url method called), then the
1221
1258
# repository to be added may already be in the _real_repositories list.
1222
1259
if self._real_repository is not None:
1223
fallback_locations = [repo.bzrdir.root_transport.base for repo in
1260
fallback_locations = [repo.user_url for repo in
1224
1261
self._real_repository._fallback_repositories]
1225
if repository.bzrdir.root_transport.base not in fallback_locations:
1262
if repository.user_url not in fallback_locations:
1226
1263
self._real_repository.add_fallback_repository(repository)
1265
def _check_fallback_repository(self, repository):
1266
"""Check that this repository can fallback to repository safely.
1268
Raise an error if not.
1270
:param repository: A repository to fallback to.
1272
return _mod_repository.InterRepository._assert_same_model(
1228
1275
def add_inventory(self, revid, inv, parents):
1229
1276
self._ensure_real()
1230
1277
return self._real_repository.add_inventory(revid, inv, parents)
1232
1279
def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1280
parents, basis_inv=None, propagate_caches=False):
1234
1281
self._ensure_real()
1235
1282
return self._real_repository.add_inventory_by_delta(basis_revision_id,
1236
delta, new_revision_id, parents)
1283
delta, new_revision_id, parents, basis_inv=basis_inv,
1284
propagate_caches=propagate_caches)
1238
1286
def add_revision(self, rev_id, rev, inv=None, config=None):
1239
1287
self._ensure_real()
1269
1317
return self._real_repository.make_working_trees()
1271
1319
def refresh_data(self):
1272
"""Re-read any data needed to to synchronise with disk.
1320
"""Re-read any data needed to synchronise with disk.
1274
1322
This method is intended to be called after another repository instance
1275
1323
(such as one used by a smart server) has inserted data into the
1276
repository. It may not be called during a write group, but may be
1277
called at any other time.
1324
repository. On all repositories this will work outside of write groups.
1325
Some repository formats (pack and newer for bzrlib native formats)
1326
support refresh_data inside write groups. If called inside a write
1327
group on a repository that does not support refreshing in a write group
1328
IsInWriteGroupError will be raised.
1279
if self.is_in_write_group():
1280
raise errors.InternalBzrError(
1281
"May not refresh_data while in a write group.")
1282
1330
if self._real_repository is not None:
1283
1331
self._real_repository.refresh_data()
1582
1630
return self._real_repository.inventories
1584
1632
@needs_write_lock
1585
def pack(self, hint=None):
1633
def pack(self, hint=None, clean_obsolete_packs=False):
1586
1634
"""Compress the data within the repository.
1588
1636
This is not currently implemented within the smart server.
1590
1638
self._ensure_real()
1591
return self._real_repository.pack(hint=hint)
1639
return self._real_repository.pack(hint=hint, clean_obsolete_packs=clean_obsolete_packs)
1594
1642
def revisions(self):
1934
1982
if response_tuple[0] != 'ok':
1935
1983
raise errors.UnexpectedSmartServerResponse(response_tuple)
1936
1984
byte_stream = response_handler.read_streamed_body()
1937
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
1985
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
1986
self._record_counter)
1938
1987
if src_format.network_name() != repo._format.network_name():
1939
1988
raise AssertionError(
1940
1989
"Mismatched RemoteRepository and stream src %r, %r" % (
2022
2071
def network_name(self):
2023
2072
return self._network_name
2025
def open(self, a_bzrdir, ignore_fallbacks=False):
2026
return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2074
def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
2075
return a_bzrdir.open_branch(name=name,
2076
ignore_fallbacks=ignore_fallbacks)
2028
def _vfs_initialize(self, a_bzrdir):
2078
def _vfs_initialize(self, a_bzrdir, name):
2029
2079
# Initialisation when using a local bzrdir object, or a non-vfs init
2030
2080
# method is not available on the server.
2031
2081
# self._custom_format is always set - the start of initialize ensures
2033
2083
if isinstance(a_bzrdir, RemoteBzrDir):
2034
2084
a_bzrdir._ensure_real()
2035
result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
2085
result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
2037
2088
# We assume the bzrdir is parameterised; it may not be.
2038
result = self._custom_format.initialize(a_bzrdir)
2089
result = self._custom_format.initialize(a_bzrdir, name)
2039
2090
if (isinstance(a_bzrdir, RemoteBzrDir) and
2040
2091
not isinstance(result, RemoteBranch)):
2041
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
2092
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
2044
def initialize(self, a_bzrdir):
2096
def initialize(self, a_bzrdir, name=None):
2045
2097
# 1) get the network name to use.
2046
2098
if self._custom_format:
2047
2099
network_name = self._custom_format.network_name()
2053
2105
network_name = reference_format.network_name()
2054
2106
# Being asked to create on a non RemoteBzrDir:
2055
2107
if not isinstance(a_bzrdir, RemoteBzrDir):
2056
return self._vfs_initialize(a_bzrdir)
2108
return self._vfs_initialize(a_bzrdir, name=name)
2057
2109
medium = a_bzrdir._client._medium
2058
2110
if medium._is_remote_before((1, 13)):
2059
return self._vfs_initialize(a_bzrdir)
2111
return self._vfs_initialize(a_bzrdir, name=name)
2060
2112
# Creating on a remote bzr dir.
2061
2113
# 2) try direct creation via RPC
2062
2114
path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
2115
if name is not None:
2116
# XXX JRV20100304: Support creating colocated branches
2117
raise errors.NoColocatedBranchSupport(self)
2063
2118
verb = 'BzrDir.create_branch'
2065
2120
response = a_bzrdir._call(verb, path, network_name)
2066
2121
except errors.UnknownSmartMethod:
2067
2122
# Fallback - use vfs methods
2068
2123
medium._remember_remote_is_before((1, 13))
2069
return self._vfs_initialize(a_bzrdir)
2124
return self._vfs_initialize(a_bzrdir, name=name)
2070
2125
if response[0] != 'ok':
2071
2126
raise errors.UnexpectedSmartServerResponse(response)
2072
2127
# Turn the response into a RemoteRepository object.
2080
2135
a_bzrdir._client)
2081
2136
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2082
2137
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2083
format=format, setup_stacking=False)
2138
format=format, setup_stacking=False, name=name)
2084
2139
# XXX: We know this is a new branch, so it must have revno 0, revid
2085
2140
# NULL_REVISION. Creating the branch locked would make this be unable
2086
2141
# to be wrong; here its simply very unlikely to be wrong. RBC 20090225
2115
2170
def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
2116
_client=None, format=None, setup_stacking=True):
2171
_client=None, format=None, setup_stacking=True, name=None):
2117
2172
"""Create a RemoteBranch instance.
2119
2174
:param real_branch: An optional local implementation of the branch
2220
2278
'to use vfs implementation')
2221
2279
self.bzrdir._ensure_real()
2222
2280
self._real_branch = self.bzrdir._real_bzrdir.open_branch(
2223
ignore_fallbacks=self._real_ignore_fallbacks)
2281
ignore_fallbacks=self._real_ignore_fallbacks, name=self._name)
2224
2282
if self.repository._real_repository is None:
2225
2283
# Give the remote repository the matching real repo.
2226
2284
real_repo = self._real_branch.repository
2350
2412
self._real_branch.lock_read()
2352
2414
self._lock_count += 1
2415
return lock.LogicalLockResult(self.unlock)
2354
2417
def _remote_lock_write(self, token):
2355
2418
if token is None:
2356
2419
branch_token = repo_token = ''
2358
2421
branch_token = token
2359
repo_token = self.repository.lock_write()
2422
repo_token = self.repository.lock_write().repository_token
2360
2423
self.repository.unlock()
2361
2424
err_context = {'token': token}
2362
response = self._call(
2363
'Branch.lock_write', self._remote_path(), branch_token,
2364
repo_token or '', **err_context)
2426
response = self._call(
2427
'Branch.lock_write', self._remote_path(), branch_token,
2428
repo_token or '', **err_context)
2429
except errors.LockContention, e:
2430
# The LockContention from the server doesn't have any
2431
# information about the lock_url. We re-raise LockContention
2432
# with valid lock_url.
2433
raise errors.LockContention('(remote lock)',
2434
self.repository.base.split('.bzr/')[0])
2365
2435
if response[0] != 'ok':
2366
2436
raise errors.UnexpectedSmartServerResponse(response)
2367
2437
ok, branch_token, repo_token = response
2399
2469
self._lock_count += 1
2400
2470
# Re-lock the repository too.
2401
2471
self.repository.lock_write(self._repo_lock_token)
2402
return self._lock_token or None
2472
return BranchWriteLockResult(self.unlock, self._lock_token or None)
2404
2474
def _unlock(self, branch_token, repo_token):
2405
2475
err_context = {'token': str((branch_token, repo_token))}
2728
2798
medium = self._branch._client._medium
2729
2799
if medium._is_remote_before((1, 14)):
2730
2800
return self._vfs_set_option(value, name, section)
2801
if isinstance(value, dict):
2802
if medium._is_remote_before((2, 2)):
2803
return self._vfs_set_option(value, name, section)
2804
return self._set_config_option_dict(value, name, section)
2806
return self._set_config_option(value, name, section)
2808
def _set_config_option(self, value, name, section):
2732
2810
path = self._branch._remote_path()
2733
2811
response = self._branch._client.call('Branch.set_config_option',
2734
2812
path, self._branch._lock_token, self._branch._repo_lock_token,
2735
2813
value.encode('utf8'), name, section or '')
2736
2814
except errors.UnknownSmartMethod:
2815
medium = self._branch._client._medium
2737
2816
medium._remember_remote_is_before((1, 14))
2738
2817
return self._vfs_set_option(value, name, section)
2739
2818
if response != ():
2740
2819
raise errors.UnexpectedSmartServerResponse(response)
2821
def _serialize_option_dict(self, option_dict):
2823
for key, value in option_dict.items():
2824
if isinstance(key, unicode):
2825
key = key.encode('utf8')
2826
if isinstance(value, unicode):
2827
value = value.encode('utf8')
2828
utf8_dict[key] = value
2829
return bencode.bencode(utf8_dict)
2831
def _set_config_option_dict(self, value, name, section):
2833
path = self._branch._remote_path()
2834
serialised_dict = self._serialize_option_dict(value)
2835
response = self._branch._client.call(
2836
'Branch.set_config_option_dict',
2837
path, self._branch._lock_token, self._branch._repo_lock_token,
2838
serialised_dict, name, section or '')
2839
except errors.UnknownSmartMethod:
2840
medium = self._branch._client._medium
2841
medium._remember_remote_is_before((2, 2))
2842
return self._vfs_set_option(value, name, section)
2844
raise errors.UnexpectedSmartServerResponse(response)
2742
2846
def _real_object(self):
2743
2847
self._branch._ensure_real()
2744
2848
return self._branch._real_branch