31
repository as _mod_repository,
33
31
revision as _mod_revision,
37
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
34
from bzrlib.branch import BranchReferenceFormat
38
35
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
39
36
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
40
37
from bzrlib.errors import (
161
154
Used before calls to self._real_bzrdir.
163
156
if not self._real_bzrdir:
164
if 'hpssvfs' in debug.debug_flags:
166
warning('VFS BzrDir access triggered\n%s',
167
''.join(traceback.format_stack()))
168
157
self._real_bzrdir = BzrDir.open_from_transport(
169
158
self.root_transport, _server_formats=False)
170
159
self._format._network_name = \
246
235
self._ensure_real()
247
236
self._real_bzrdir.destroy_repository()
249
def create_branch(self, name=None):
238
def create_branch(self):
250
239
# as per meta1 formats - just delegate to the format object which may
251
240
# be parameterised.
252
real_branch = self._format.get_branch_format().initialize(self,
241
real_branch = self._format.get_branch_format().initialize(self)
254
242
if not isinstance(real_branch, RemoteBranch):
255
result = RemoteBranch(self, self.find_repository(), real_branch,
243
result = RemoteBranch(self, self.find_repository(), real_branch)
258
245
result = real_branch
259
246
# BzrDir.clone_on_transport() uses the result of create_branch but does
265
252
self._next_open_branch_result = result
268
def destroy_branch(self, name=None):
255
def destroy_branch(self):
269
256
"""See BzrDir.destroy_branch"""
270
257
self._ensure_real()
271
self._real_bzrdir.destroy_branch(name=name)
258
self._real_bzrdir.destroy_branch()
272
259
self._next_open_branch_result = None
274
261
def create_workingtree(self, revision_id=None, from_branch=None):
275
262
raise errors.NotLocalUrl(self.transport.base)
277
def find_branch_format(self, name=None):
264
def find_branch_format(self):
278
265
"""Find the branch 'format' for this bzrdir.
280
267
This might be a synthetic object for e.g. RemoteBranch and SVN.
282
b = self.open_branch(name=name)
269
b = self.open_branch()
285
def get_branch_reference(self, name=None):
272
def get_branch_reference(self):
286
273
"""See BzrDir.get_branch_reference()."""
288
# XXX JRV20100304: Support opening colocated branches
289
raise errors.NoColocatedBranchSupport(self)
290
274
response = self._get_branch_reference()
291
275
if response[0] == 'ref':
292
276
return response[1]
296
280
def _get_branch_reference(self):
297
281
path = self._path_for_remote_call(self._client)
298
282
medium = self._client._medium
300
('BzrDir.open_branchV3', (2, 1)),
301
('BzrDir.open_branchV2', (1, 13)),
302
('BzrDir.open_branch', None),
304
for verb, required_version in candidate_calls:
305
if required_version and medium._is_remote_before(required_version):
283
if not medium._is_remote_before((1, 13)):
308
response = self._call(verb, path)
285
response = self._call('BzrDir.open_branchV2', path)
286
if response[0] not in ('ref', 'branch'):
287
raise errors.UnexpectedSmartServerResponse(response)
309
289
except errors.UnknownSmartMethod:
310
if required_version is None:
312
medium._remember_remote_is_before(required_version)
315
if verb == 'BzrDir.open_branch':
316
if response[0] != 'ok':
317
raise errors.UnexpectedSmartServerResponse(response)
318
if response[1] != '':
319
return ('ref', response[1])
321
return ('branch', '')
322
if response[0] not in ('ref', 'branch'):
290
medium._remember_remote_is_before((1, 13))
291
response = self._call('BzrDir.open_branch', path)
292
if response[0] != 'ok':
323
293
raise errors.UnexpectedSmartServerResponse(response)
294
if response[1] != '':
295
return ('ref', response[1])
297
return ('branch', '')
326
def _get_tree_branch(self, name=None):
299
def _get_tree_branch(self):
327
300
"""See BzrDir._get_tree_branch()."""
328
return None, self.open_branch(name=name)
301
return None, self.open_branch()
330
def open_branch(self, name=None, unsupported=False,
331
ignore_fallbacks=False):
303
def open_branch(self, _unsupported=False, ignore_fallbacks=False):
333
305
raise NotImplementedError('unsupported flag support not implemented yet.')
334
306
if self._next_open_branch_result is not None:
335
307
# See create_branch for details.
340
312
if response[0] == 'ref':
341
313
# a branch reference, use the existing BranchReference logic.
342
314
format = BranchReferenceFormat()
343
return format.open(self, name=name, _found=True,
344
location=response[1], ignore_fallbacks=ignore_fallbacks)
315
return format.open(self, _found=True, location=response[1],
316
ignore_fallbacks=ignore_fallbacks)
345
317
branch_format_name = response[1]
346
318
if not branch_format_name:
347
319
branch_format_name = None
348
320
format = RemoteBranchFormat(network_name=branch_format_name)
349
321
return RemoteBranch(self, self.find_repository(), format=format,
350
setup_stacking=not ignore_fallbacks, name=name)
322
setup_stacking=not ignore_fallbacks)
352
324
def _open_repo_v1(self, path):
353
325
verb = 'BzrDir.find_repository'
430
402
"""Return the path to be used for this bzrdir in a remote call."""
431
403
return client.remote_path_from_transport(self.root_transport)
433
def get_branch_transport(self, branch_format, name=None):
405
def get_branch_transport(self, branch_format):
434
406
self._ensure_real()
435
return self._real_bzrdir.get_branch_transport(branch_format, name=name)
407
return self._real_bzrdir.get_branch_transport(branch_format)
437
409
def get_repository_transport(self, repository_format):
438
410
self._ensure_real()
698
668
# Additional places to query for data.
699
669
self._fallback_repositories = []
702
def user_transport(self):
703
return self.bzrdir.user_transport
706
def control_transport(self):
707
# XXX: Normally you shouldn't directly get at the remote repository
708
# transport, but I'm not sure it's worth making this method
709
# optional -- mbp 2010-04-21
710
return self.bzrdir.get_repository_transport(None)
712
671
def __str__(self):
713
672
return "%s(%s)" % (self.__class__.__name__, self.base)
900
859
def _has_same_fallbacks(self, other_repo):
901
860
"""Returns true if the repositories have the same fallbacks."""
902
861
# XXX: copied from Repository; it should be unified into a base class
903
# <https://bugs.launchpad.net/bzr/+bug/401622>
862
# <https://bugs.edge.launchpad.net/bzr/+bug/401622>
904
863
my_fb = self._fallback_repositories
905
864
other_fb = other_repo._fallback_repositories
906
865
if len(my_fb) != len(other_fb):
922
881
parents_provider = self._make_parents_provider(other_repository)
923
882
return graph.Graph(parents_provider)
926
def get_known_graph_ancestry(self, revision_ids):
927
"""Return the known graph for a set of revision ids and their ancestors.
929
st = static_tuple.StaticTuple
930
revision_keys = [st(r_id).intern() for r_id in revision_ids]
931
known_graph = self.revisions.get_known_graph_ancestry(revision_keys)
932
return graph.GraphThunkIdsToKeys(known_graph)
934
884
def gather_stats(self, revid=None, committers=None):
935
885
"""See Repository.gather_stats()."""
936
886
path = self.bzrdir._path_for_remote_call(self._client)
996
946
def is_write_locked(self):
997
947
return self._lock_mode == 'w'
999
def _warn_if_deprecated(self, branch=None):
1000
# If we have a real repository, the check will be done there, if we
1001
# don't the check will be done remotely.
1004
949
def lock_read(self):
1005
"""Lock the repository for read operations.
1007
:return: A bzrlib.lock.LogicalLockResult.
1009
950
# wrong eventually - want a local lock cache context
1010
951
if not self._lock_mode:
1011
952
self._note_lock('r')
1250
1190
# state, so always add a lock here. If a caller passes us a locked
1251
1191
# repository, they are responsible for unlocking it later.
1252
1192
repository.lock_read()
1253
self._check_fallback_repository(repository)
1254
1193
self._fallback_repositories.append(repository)
1255
1194
# If self._real_repository was parameterised already (e.g. because a
1256
1195
# _real_branch had its get_stacked_on_url method called), then the
1257
1196
# repository to be added may already be in the _real_repositories list.
1258
1197
if self._real_repository is not None:
1259
fallback_locations = [repo.user_url for repo in
1198
fallback_locations = [repo.bzrdir.root_transport.base for repo in
1260
1199
self._real_repository._fallback_repositories]
1261
if repository.user_url not in fallback_locations:
1200
if repository.bzrdir.root_transport.base not in fallback_locations:
1262
1201
self._real_repository.add_fallback_repository(repository)
1264
def _check_fallback_repository(self, repository):
1265
"""Check that this repository can fallback to repository safely.
1267
Raise an error if not.
1269
:param repository: A repository to fallback to.
1271
return _mod_repository.InterRepository._assert_same_model(
1274
1203
def add_inventory(self, revid, inv, parents):
1275
1204
self._ensure_real()
1276
1205
return self._real_repository.add_inventory(revid, inv, parents)
1278
1207
def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1279
parents, basis_inv=None, propagate_caches=False):
1280
1209
self._ensure_real()
1281
1210
return self._real_repository.add_inventory_by_delta(basis_revision_id,
1282
delta, new_revision_id, parents, basis_inv=basis_inv,
1283
propagate_caches=propagate_caches)
1211
delta, new_revision_id, parents)
1285
1213
def add_revision(self, rev_id, rev, inv=None, config=None):
1286
1214
self._ensure_real()
1316
1244
return self._real_repository.make_working_trees()
1318
1246
def refresh_data(self):
1319
"""Re-read any data needed to synchronise with disk.
1247
"""Re-read any data needed to to synchronise with disk.
1321
1249
This method is intended to be called after another repository instance
1322
1250
(such as one used by a smart server) has inserted data into the
1323
repository. On all repositories this will work outside of write groups.
1324
Some repository formats (pack and newer for bzrlib native formats)
1325
support refresh_data inside write groups. If called inside a write
1326
group on a repository that does not support refreshing in a write group
1327
IsInWriteGroupError will be raised.
1251
repository. It may not be called during a write group, but may be
1252
called at any other time.
1254
if self.is_in_write_group():
1255
raise errors.InternalBzrError(
1256
"May not refresh_data while in a write group.")
1329
1257
if self._real_repository is not None:
1330
1258
self._real_repository.refresh_data()
1545
1473
return self._real_repository.get_signature_text(revision_id)
1547
1475
@needs_read_lock
1548
def _get_inventory_xml(self, revision_id):
1550
return self._real_repository._get_inventory_xml(revision_id)
1476
def get_inventory_xml(self, revision_id):
1478
return self._real_repository.get_inventory_xml(revision_id)
1480
def deserialise_inventory(self, revision_id, xml):
1482
return self._real_repository.deserialise_inventory(revision_id, xml)
1552
1484
def reconcile(self, other=None, thorough=False):
1553
1485
self._ensure_real()
1629
1561
return self._real_repository.inventories
1631
1563
@needs_write_lock
1632
def pack(self, hint=None, clean_obsolete_packs=False):
1564
def pack(self, hint=None):
1633
1565
"""Compress the data within the repository.
1635
1567
This is not currently implemented within the smart server.
1637
1569
self._ensure_real()
1638
return self._real_repository.pack(hint=hint, clean_obsolete_packs=clean_obsolete_packs)
1570
return self._real_repository.pack(hint=hint)
1641
1573
def revisions(self):
1981
1913
if response_tuple[0] != 'ok':
1982
1914
raise errors.UnexpectedSmartServerResponse(response_tuple)
1983
1915
byte_stream = response_handler.read_streamed_body()
1984
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
1985
self._record_counter)
1916
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
1986
1917
if src_format.network_name() != repo._format.network_name():
1987
1918
raise AssertionError(
1988
1919
"Mismatched RemoteRepository and stream src %r, %r" % (
2064
1995
self._network_name)
2066
1997
def get_format_description(self):
2068
return 'Remote: ' + self._custom_format.get_format_description()
1998
return 'Remote BZR Branch'
2070
2000
def network_name(self):
2071
2001
return self._network_name
2073
def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
2074
return a_bzrdir.open_branch(name=name,
2075
ignore_fallbacks=ignore_fallbacks)
2003
def open(self, a_bzrdir, ignore_fallbacks=False):
2004
return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2077
def _vfs_initialize(self, a_bzrdir, name):
2006
def _vfs_initialize(self, a_bzrdir):
2078
2007
# Initialisation when using a local bzrdir object, or a non-vfs init
2079
2008
# method is not available on the server.
2080
2009
# self._custom_format is always set - the start of initialize ensures
2082
2011
if isinstance(a_bzrdir, RemoteBzrDir):
2083
2012
a_bzrdir._ensure_real()
2084
result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
2013
result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
2087
2015
# We assume the bzrdir is parameterised; it may not be.
2088
result = self._custom_format.initialize(a_bzrdir, name)
2016
result = self._custom_format.initialize(a_bzrdir)
2089
2017
if (isinstance(a_bzrdir, RemoteBzrDir) and
2090
2018
not isinstance(result, RemoteBranch)):
2091
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
2019
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
2095
def initialize(self, a_bzrdir, name=None):
2022
def initialize(self, a_bzrdir):
2096
2023
# 1) get the network name to use.
2097
2024
if self._custom_format:
2098
2025
network_name = self._custom_format.network_name()
2104
2031
network_name = reference_format.network_name()
2105
2032
# Being asked to create on a non RemoteBzrDir:
2106
2033
if not isinstance(a_bzrdir, RemoteBzrDir):
2107
return self._vfs_initialize(a_bzrdir, name=name)
2034
return self._vfs_initialize(a_bzrdir)
2108
2035
medium = a_bzrdir._client._medium
2109
2036
if medium._is_remote_before((1, 13)):
2110
return self._vfs_initialize(a_bzrdir, name=name)
2037
return self._vfs_initialize(a_bzrdir)
2111
2038
# Creating on a remote bzr dir.
2112
2039
# 2) try direct creation via RPC
2113
2040
path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
2114
if name is not None:
2115
# XXX JRV20100304: Support creating colocated branches
2116
raise errors.NoColocatedBranchSupport(self)
2117
2041
verb = 'BzrDir.create_branch'
2119
2043
response = a_bzrdir._call(verb, path, network_name)
2120
2044
except errors.UnknownSmartMethod:
2121
2045
# Fallback - use vfs methods
2122
2046
medium._remember_remote_is_before((1, 13))
2123
return self._vfs_initialize(a_bzrdir, name=name)
2047
return self._vfs_initialize(a_bzrdir)
2124
2048
if response[0] != 'ok':
2125
2049
raise errors.UnexpectedSmartServerResponse(response)
2126
2050
# Turn the response into a RemoteRepository object.
2134
2058
a_bzrdir._client)
2135
2059
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2136
2060
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2137
format=format, setup_stacking=False, name=name)
2061
format=format, setup_stacking=False)
2138
2062
# XXX: We know this is a new branch, so it must have revno 0, revid
2139
2063
# NULL_REVISION. Creating the branch locked would make this be unable
2140
2064
# to be wrong; here its simply very unlikely to be wrong. RBC 20090225
2169
2093
def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
2170
_client=None, format=None, setup_stacking=True, name=None):
2094
_client=None, format=None, setup_stacking=True):
2171
2095
"""Create a RemoteBranch instance.
2173
2097
:param real_branch: An optional local implementation of the branch
2277
2198
'to use vfs implementation')
2278
2199
self.bzrdir._ensure_real()
2279
2200
self._real_branch = self.bzrdir._real_bzrdir.open_branch(
2280
ignore_fallbacks=self._real_ignore_fallbacks, name=self._name)
2201
ignore_fallbacks=self._real_ignore_fallbacks)
2281
2202
if self.repository._real_repository is None:
2282
2203
# Give the remote repository the matching real repo.
2283
2204
real_repo = self._real_branch.repository
2411
2328
self._real_branch.lock_read()
2413
2330
self._lock_count += 1
2414
return lock.LogicalLockResult(self.unlock)
2416
2332
def _remote_lock_write(self, token):
2417
2333
if token is None:
2418
2334
branch_token = repo_token = ''
2420
2336
branch_token = token
2421
repo_token = self.repository.lock_write().repository_token
2337
repo_token = self.repository.lock_write()
2422
2338
self.repository.unlock()
2423
2339
err_context = {'token': token}
2425
response = self._call(
2426
'Branch.lock_write', self._remote_path(), branch_token,
2427
repo_token or '', **err_context)
2428
except errors.LockContention, e:
2429
# The LockContention from the server doesn't have any
2430
# information about the lock_url. We re-raise LockContention
2431
# with valid lock_url.
2432
raise errors.LockContention('(remote lock)',
2433
self.repository.base.split('.bzr/')[0])
2340
response = self._call(
2341
'Branch.lock_write', self._remote_path(), branch_token,
2342
repo_token or '', **err_context)
2434
2343
if response[0] != 'ok':
2435
2344
raise errors.UnexpectedSmartServerResponse(response)
2436
2345
ok, branch_token, repo_token = response
2468
2377
self._lock_count += 1
2469
2378
# Re-lock the repository too.
2470
2379
self.repository.lock_write(self._repo_lock_token)
2471
return BranchWriteLockResult(self.unlock, self._lock_token or None)
2380
return self._lock_token or None
2473
2382
def _unlock(self, branch_token, repo_token):
2474
2383
err_context = {'token': str((branch_token, repo_token))}
2797
2705
medium = self._branch._client._medium
2798
2706
if medium._is_remote_before((1, 14)):
2799
2707
return self._vfs_set_option(value, name, section)
2800
if isinstance(value, dict):
2801
if medium._is_remote_before((2, 2)):
2802
return self._vfs_set_option(value, name, section)
2803
return self._set_config_option_dict(value, name, section)
2805
return self._set_config_option(value, name, section)
2807
def _set_config_option(self, value, name, section):
2809
2709
path = self._branch._remote_path()
2810
2710
response = self._branch._client.call('Branch.set_config_option',
2811
2711
path, self._branch._lock_token, self._branch._repo_lock_token,
2812
2712
value.encode('utf8'), name, section or '')
2813
2713
except errors.UnknownSmartMethod:
2814
medium = self._branch._client._medium
2815
2714
medium._remember_remote_is_before((1, 14))
2816
2715
return self._vfs_set_option(value, name, section)
2817
2716
if response != ():
2818
2717
raise errors.UnexpectedSmartServerResponse(response)
2820
def _serialize_option_dict(self, option_dict):
2822
for key, value in option_dict.items():
2823
if isinstance(key, unicode):
2824
key = key.encode('utf8')
2825
if isinstance(value, unicode):
2826
value = value.encode('utf8')
2827
utf8_dict[key] = value
2828
return bencode.bencode(utf8_dict)
2830
def _set_config_option_dict(self, value, name, section):
2832
path = self._branch._remote_path()
2833
serialised_dict = self._serialize_option_dict(value)
2834
response = self._branch._client.call(
2835
'Branch.set_config_option_dict',
2836
path, self._branch._lock_token, self._branch._repo_lock_token,
2837
serialised_dict, name, section or '')
2838
except errors.UnknownSmartMethod:
2839
medium = self._branch._client._medium
2840
medium._remember_remote_is_before((2, 2))
2841
return self._vfs_set_option(value, name, section)
2843
raise errors.UnexpectedSmartServerResponse(response)
2845
2719
def _real_object(self):
2846
2720
self._branch._ensure_real()
2847
2721
return self._branch._real_branch
2937
2811
raise NoSuchRevision(find('branch'), err.error_args[0])
2938
2812
elif err.error_verb == 'nosuchrevision':
2939
2813
raise NoSuchRevision(find('repository'), err.error_args[0])
2940
elif err.error_verb == 'nobranch':
2941
if len(err.error_args) >= 1:
2942
extra = err.error_args[0]
2945
raise errors.NotBranchError(path=find('bzrdir').root_transport.base,
2814
elif err.error_tuple == ('nobranch',):
2815
raise errors.NotBranchError(path=find('bzrdir').root_transport.base)
2947
2816
elif err.error_verb == 'norepository':
2948
2817
raise errors.NoRepositoryPresent(find('bzrdir'))
2949
2818
elif err.error_verb == 'LockContention':