33
32
revision as _mod_revision,
38
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
36
from bzrlib.branch import BranchReferenceFormat
39
37
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
40
38
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
41
39
from bzrlib.errors import (
247
244
self._ensure_real()
248
245
self._real_bzrdir.destroy_repository()
250
def create_branch(self, name=None, repository=None):
247
def create_branch(self, name=None):
251
248
# as per meta1 formats - just delegate to the format object which may
252
249
# be parameterised.
253
250
real_branch = self._format.get_branch_format().initialize(self,
254
name=name, repository=repository)
255
252
if not isinstance(real_branch, RemoteBranch):
256
if not isinstance(repository, RemoteRepository):
257
raise AssertionError(
258
'need a RemoteRepository to use with RemoteBranch, got %r'
260
result = RemoteBranch(self, repository, real_branch, name=name)
253
result = RemoteBranch(self, self.find_repository(), real_branch,
262
256
result = real_branch
263
257
# BzrDir.clone_on_transport() uses the result of create_branch but does
275
269
self._real_bzrdir.destroy_branch(name=name)
276
270
self._next_open_branch_result = None
278
def create_workingtree(self, revision_id=None, from_branch=None,
279
accelerator_tree=None, hardlink=False):
272
def create_workingtree(self, revision_id=None, from_branch=None):
280
273
raise errors.NotLocalUrl(self.transport.base)
282
def find_branch_format(self, name=None):
275
def find_branch_format(self):
283
276
"""Find the branch 'format' for this bzrdir.
285
278
This might be a synthetic object for e.g. RemoteBranch and SVN.
287
b = self.open_branch(name=name)
280
b = self.open_branch()
290
def get_branch_reference(self, name=None):
283
def get_branch_reference(self):
291
284
"""See BzrDir.get_branch_reference()."""
293
# XXX JRV20100304: Support opening colocated branches
294
raise errors.NoColocatedBranchSupport(self)
295
285
response = self._get_branch_reference()
296
286
if response[0] == 'ref':
297
287
return response[1]
328
318
raise errors.UnexpectedSmartServerResponse(response)
331
def _get_tree_branch(self, name=None):
321
def _get_tree_branch(self):
332
322
"""See BzrDir._get_tree_branch()."""
333
return None, self.open_branch(name=name)
323
return None, self.open_branch()
335
325
def open_branch(self, name=None, unsupported=False,
336
326
ignore_fallbacks=False):
905
895
def _has_same_fallbacks(self, other_repo):
906
896
"""Returns true if the repositories have the same fallbacks."""
907
897
# XXX: copied from Repository; it should be unified into a base class
908
# <https://bugs.launchpad.net/bzr/+bug/401622>
898
# <https://bugs.edge.launchpad.net/bzr/+bug/401622>
909
899
my_fb = self._fallback_repositories
910
900
other_fb = other_repo._fallback_repositories
911
901
if len(my_fb) != len(other_fb):
1321
1306
return self._real_repository.make_working_trees()
1323
1308
def refresh_data(self):
1324
"""Re-read any data needed to synchronise with disk.
1309
"""Re-read any data needed to to synchronise with disk.
1326
1311
This method is intended to be called after another repository instance
1327
1312
(such as one used by a smart server) has inserted data into the
1328
repository. On all repositories this will work outside of write groups.
1329
Some repository formats (pack and newer for bzrlib native formats)
1330
support refresh_data inside write groups. If called inside a write
1331
group on a repository that does not support refreshing in a write group
1332
IsInWriteGroupError will be raised.
1313
repository. It may not be called during a write group, but may be
1314
called at any other time.
1316
if self.is_in_write_group():
1317
raise errors.InternalBzrError(
1318
"May not refresh_data while in a write group.")
1334
1319
if self._real_repository is not None:
1335
1320
self._real_repository.refresh_data()
1350
1335
@needs_read_lock
1351
def search_missing_revision_ids(self, other,
1352
revision_id=symbol_versioning.DEPRECATED_PARAMETER,
1353
find_ghosts=True, revision_ids=None, if_present_ids=None):
1336
def search_missing_revision_ids(self, other, revision_id=None, find_ghosts=True):
1354
1337
"""Return the revision ids that other has that this does not.
1356
1339
These are returned in topological order.
1358
1341
revision_id: only return revision ids included by revision_id.
1360
if symbol_versioning.deprecated_passed(revision_id):
1361
symbol_versioning.warn(
1362
'search_missing_revision_ids(revision_id=...) was '
1363
'deprecated in 2.4. Use revision_ids=[...] instead.',
1364
DeprecationWarning, stacklevel=2)
1365
if revision_ids is not None:
1366
raise AssertionError(
1367
'revision_ids is mutually exclusive with revision_id')
1368
if revision_id is not None:
1369
revision_ids = [revision_id]
1370
inter_repo = repository.InterRepository.get(other, self)
1371
return inter_repo.search_missing_revision_ids(
1372
find_ghosts=find_ghosts, revision_ids=revision_ids,
1373
if_present_ids=if_present_ids)
1343
return repository.InterRepository.get(
1344
other, self).search_missing_revision_ids(revision_id, find_ghosts)
1375
1346
def fetch(self, source, revision_id=None, pb=None, find_ghosts=False,
1376
1347
fetch_spec=None):
1777
1748
return '\n'.join((start_keys, stop_keys, count))
1779
1750
def _serialise_search_result(self, search_result):
1780
parts = search_result.get_network_struct()
1751
if isinstance(search_result, graph.PendingAncestryResult):
1752
parts = ['ancestry-of']
1753
parts.extend(search_result.heads)
1755
recipe = search_result.get_recipe()
1756
parts = [recipe[0], self._serialise_search_recipe(recipe)]
1781
1757
return '\n'.join(parts)
1783
1759
def autopack(self):
1987
1962
verb, args, search_bytes)
1988
1963
except errors.UnknownSmartMethod:
1989
1964
medium._remember_remote_is_before(version)
1990
except errors.UnknownErrorFromSmartServer, e:
1991
if isinstance(search, graph.EverythingResult):
1992
error_verb = e.error_from_smart_server.error_verb
1993
if error_verb == 'BadSearch':
1994
# Pre-2.4 servers don't support this sort of search.
1995
# XXX: perhaps falling back to VFS on BadSearch is a
1996
# good idea in general? It might provide a little bit
1997
# of protection against client-side bugs.
1998
medium._remember_remote_is_before((2, 4))
2002
1966
response_tuple, response_handler = response
2003
1967
found_verb = True
2007
1971
if response_tuple[0] != 'ok':
2008
1972
raise errors.UnexpectedSmartServerResponse(response_tuple)
2009
1973
byte_stream = response_handler.read_streamed_body()
2010
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream,
2011
self._record_counter)
1974
src_format, stream = smart_repo._byte_stream_to_stream(byte_stream)
2012
1975
if src_format.network_name() != repo._format.network_name():
2013
1976
raise AssertionError(
2014
1977
"Mismatched RemoteRepository and stream src %r, %r" % (
2152
2115
# Turn the response into a RemoteRepository object.
2153
2116
format = RemoteBranchFormat(network_name=response[1])
2154
2117
repo_format = response_tuple_to_repo_format(response[3:])
2155
repo_path = response[2]
2156
if repository is not None:
2157
remote_repo_url = urlutils.join(medium.base, repo_path)
2158
url_diff = urlutils.relative_url(repository.user_url,
2161
raise AssertionError(
2162
'repository.user_url %r does not match URL from server '
2163
'response (%r + %r)'
2164
% (repository.user_url, medium.base, repo_path))
2165
remote_repo = repository
2118
if response[2] == '':
2119
repo_bzrdir = a_bzrdir
2168
repo_bzrdir = a_bzrdir
2170
repo_bzrdir = RemoteBzrDir(
2171
a_bzrdir.root_transport.clone(repo_path), a_bzrdir._format,
2173
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2121
repo_bzrdir = RemoteBzrDir(
2122
a_bzrdir.root_transport.clone(response[2]), a_bzrdir._format,
2124
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2174
2125
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2175
2126
format=format, setup_stacking=False, name=name)
2176
2127
# XXX: We know this is a new branch, so it must have revno 0, revid
2406
2357
self._ensure_real()
2407
2358
return self._real_branch._get_tags_bytes()
2410
2360
def _get_tags_bytes(self):
2411
if self._tags_bytes is None:
2412
self._tags_bytes = self._get_tags_bytes_via_hpss()
2413
return self._tags_bytes
2415
def _get_tags_bytes_via_hpss(self):
2416
2361
medium = self._client._medium
2417
2362
if medium._is_remote_before((1, 13)):
2418
2363
return self._vfs_get_tags_bytes()
2457
2396
self._real_branch.lock_read()
2459
2398
self._lock_count += 1
2460
return lock.LogicalLockResult(self.unlock)
2462
2400
def _remote_lock_write(self, token):
2463
2401
if token is None:
2464
2402
branch_token = repo_token = ''
2466
2404
branch_token = token
2467
repo_token = self.repository.lock_write().repository_token
2405
repo_token = self.repository.lock_write()
2468
2406
self.repository.unlock()
2469
2407
err_context = {'token': token}
2471
response = self._call(
2472
'Branch.lock_write', self._remote_path(), branch_token,
2473
repo_token or '', **err_context)
2474
except errors.LockContention, e:
2475
# The LockContention from the server doesn't have any
2476
# information about the lock_url. We re-raise LockContention
2477
# with valid lock_url.
2478
raise errors.LockContention('(remote lock)',
2479
self.repository.base.split('.bzr/')[0])
2408
response = self._call(
2409
'Branch.lock_write', self._remote_path(), branch_token,
2410
repo_token or '', **err_context)
2480
2411
if response[0] != 'ok':
2481
2412
raise errors.UnexpectedSmartServerResponse(response)
2482
2413
ok, branch_token, repo_token = response
2514
2445
self._lock_count += 1
2515
2446
# Re-lock the repository too.
2516
2447
self.repository.lock_write(self._repo_lock_token)
2517
return BranchWriteLockResult(self.unlock, self._lock_token or None)
2448
return self._lock_token or None
2519
2450
def _unlock(self, branch_token, repo_token):
2520
2451
err_context = {'token': str((branch_token, repo_token))}
2843
2774
medium = self._branch._client._medium
2844
2775
if medium._is_remote_before((1, 14)):
2845
2776
return self._vfs_set_option(value, name, section)
2846
if isinstance(value, dict):
2847
if medium._is_remote_before((2, 2)):
2848
return self._vfs_set_option(value, name, section)
2849
return self._set_config_option_dict(value, name, section)
2851
return self._set_config_option(value, name, section)
2853
def _set_config_option(self, value, name, section):
2855
2778
path = self._branch._remote_path()
2856
2779
response = self._branch._client.call('Branch.set_config_option',
2857
2780
path, self._branch._lock_token, self._branch._repo_lock_token,
2858
2781
value.encode('utf8'), name, section or '')
2859
2782
except errors.UnknownSmartMethod:
2860
medium = self._branch._client._medium
2861
2783
medium._remember_remote_is_before((1, 14))
2862
2784
return self._vfs_set_option(value, name, section)
2863
2785
if response != ():
2864
2786
raise errors.UnexpectedSmartServerResponse(response)
2866
def _serialize_option_dict(self, option_dict):
2868
for key, value in option_dict.items():
2869
if isinstance(key, unicode):
2870
key = key.encode('utf8')
2871
if isinstance(value, unicode):
2872
value = value.encode('utf8')
2873
utf8_dict[key] = value
2874
return bencode.bencode(utf8_dict)
2876
def _set_config_option_dict(self, value, name, section):
2878
path = self._branch._remote_path()
2879
serialised_dict = self._serialize_option_dict(value)
2880
response = self._branch._client.call(
2881
'Branch.set_config_option_dict',
2882
path, self._branch._lock_token, self._branch._repo_lock_token,
2883
serialised_dict, name, section or '')
2884
except errors.UnknownSmartMethod:
2885
medium = self._branch._client._medium
2886
medium._remember_remote_is_before((2, 2))
2887
return self._vfs_set_option(value, name, section)
2889
raise errors.UnexpectedSmartServerResponse(response)
2891
2788
def _real_object(self):
2892
2789
self._branch._ensure_real()
2893
2790
return self._branch._real_branch