30
repository as _mod_repository,
32
31
revision as _mod_revision,
36
from bzrlib.branch import BranchReferenceFormat, BranchWriteLockResult
34
from bzrlib.branch import BranchReferenceFormat
37
35
from bzrlib.bzrdir import BzrDir, RemoteBzrDirFormat
38
36
from bzrlib.decorators import needs_read_lock, needs_write_lock, only_raises
39
37
from bzrlib.errors import (
43
41
from bzrlib.lockable_files import LockableFiles
44
42
from bzrlib.smart import client, vfs, repository as smart_repo
45
43
from bzrlib.revision import ensure_null, NULL_REVISION
46
from bzrlib.repository import RepositoryWriteLockResult
47
44
from bzrlib.trace import mutter, note, warning
246
243
self._real_bzrdir.destroy_repository()
248
245
def create_branch(self, name=None):
247
raise errors.NoColocatedBranchSupport(self)
249
248
# as per meta1 formats - just delegate to the format object which may
250
249
# be parameterised.
251
real_branch = self._format.get_branch_format().initialize(self,
250
real_branch = self._format.get_branch_format().initialize(self)
253
251
if not isinstance(real_branch, RemoteBranch):
254
result = RemoteBranch(self, self.find_repository(), real_branch,
252
result = RemoteBranch(self, self.find_repository(), real_branch)
257
254
result = real_branch
258
255
# BzrDir.clone_on_transport() uses the result of create_branch but does
273
270
def create_workingtree(self, revision_id=None, from_branch=None):
274
271
raise errors.NotLocalUrl(self.transport.base)
276
def find_branch_format(self, name=None):
273
def find_branch_format(self):
277
274
"""Find the branch 'format' for this bzrdir.
279
276
This might be a synthetic object for e.g. RemoteBranch and SVN.
281
b = self.open_branch(name=name)
278
b = self.open_branch()
284
def get_branch_reference(self, name=None):
281
def get_branch_reference(self):
285
282
"""See BzrDir.get_branch_reference()."""
287
# XXX JRV20100304: Support opening colocated branches
288
raise errors.NoColocatedBranchSupport(self)
289
283
response = self._get_branch_reference()
290
284
if response[0] == 'ref':
291
285
return response[1]
322
316
raise errors.UnexpectedSmartServerResponse(response)
325
def _get_tree_branch(self, name=None):
319
def _get_tree_branch(self):
326
320
"""See BzrDir._get_tree_branch()."""
327
return None, self.open_branch(name=name)
321
return None, self.open_branch()
329
323
def open_branch(self, name=None, unsupported=False,
330
324
ignore_fallbacks=False):
332
326
raise NotImplementedError('unsupported flag support not implemented yet.')
328
raise errors.NoColocatedBranchSupport(self)
333
329
if self._next_open_branch_result is not None:
334
330
# See create_branch for details.
335
331
result = self._next_open_branch_result
339
335
if response[0] == 'ref':
340
336
# a branch reference, use the existing BranchReference logic.
341
337
format = BranchReferenceFormat()
342
return format.open(self, name=name, _found=True,
343
location=response[1], ignore_fallbacks=ignore_fallbacks)
338
return format.open(self, _found=True, location=response[1],
339
ignore_fallbacks=ignore_fallbacks)
344
340
branch_format_name = response[1]
345
341
if not branch_format_name:
346
342
branch_format_name = None
347
343
format = RemoteBranchFormat(network_name=branch_format_name)
348
344
return RemoteBranch(self, self.find_repository(), format=format,
349
setup_stacking=not ignore_fallbacks, name=name)
345
setup_stacking=not ignore_fallbacks)
351
347
def _open_repo_v1(self, path):
352
348
verb = 'BzrDir.find_repository'
429
425
"""Return the path to be used for this bzrdir in a remote call."""
430
426
return client.remote_path_from_transport(self.root_transport)
432
def get_branch_transport(self, branch_format, name=None):
428
def get_branch_transport(self, branch_format):
433
429
self._ensure_real()
434
return self._real_bzrdir.get_branch_transport(branch_format, name=name)
430
return self._real_bzrdir.get_branch_transport(branch_format)
436
432
def get_repository_transport(self, repository_format):
437
433
self._ensure_real()
647
643
return self._custom_format._serializer
650
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin,
651
bzrdir.ControlComponent):
646
class RemoteRepository(_RpcHelper, lock._RelockDebugMixin):
652
647
"""Repository accessed over rpc.
654
649
For the moment most operations are performed using local transport-backed
697
692
# Additional places to query for data.
698
693
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)
711
695
def __str__(self):
712
696
return "%s(%s)" % (self.__class__.__name__, self.base)
921
905
parents_provider = self._make_parents_provider(other_repository)
922
906
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)
933
908
def gather_stats(self, revid=None, committers=None):
934
909
"""See Repository.gather_stats()."""
935
910
path = self.bzrdir._path_for_remote_call(self._client)
1249
1219
# state, so always add a lock here. If a caller passes us a locked
1250
1220
# repository, they are responsible for unlocking it later.
1251
1221
repository.lock_read()
1252
self._check_fallback_repository(repository)
1253
1222
self._fallback_repositories.append(repository)
1254
1223
# If self._real_repository was parameterised already (e.g. because a
1255
1224
# _real_branch had its get_stacked_on_url method called), then the
1256
1225
# repository to be added may already be in the _real_repositories list.
1257
1226
if self._real_repository is not None:
1258
fallback_locations = [repo.user_url for repo in
1227
fallback_locations = [repo.bzrdir.root_transport.base for repo in
1259
1228
self._real_repository._fallback_repositories]
1260
if repository.user_url not in fallback_locations:
1229
if repository.bzrdir.root_transport.base not in fallback_locations:
1261
1230
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(
1273
1232
def add_inventory(self, revid, inv, parents):
1274
1233
self._ensure_real()
1275
1234
return self._real_repository.add_inventory(revid, inv, parents)
1277
1236
def add_inventory_by_delta(self, basis_revision_id, delta, new_revision_id,
1278
parents, basis_inv=None, propagate_caches=False):
1279
1238
self._ensure_real()
1280
1239
return self._real_repository.add_inventory_by_delta(basis_revision_id,
1281
delta, new_revision_id, parents, basis_inv=basis_inv,
1282
propagate_caches=propagate_caches)
1240
delta, new_revision_id, parents)
1284
1242
def add_revision(self, rev_id, rev, inv=None, config=None):
1285
1243
self._ensure_real()
1315
1273
return self._real_repository.make_working_trees()
1317
1275
def refresh_data(self):
1318
"""Re-read any data needed to synchronise with disk.
1276
"""Re-read any data needed to to synchronise with disk.
1320
1278
This method is intended to be called after another repository instance
1321
1279
(such as one used by a smart server) has inserted data into the
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.
1280
repository. It may not be called during a write group, but may be
1281
called at any other time.
1283
if self.is_in_write_group():
1284
raise errors.InternalBzrError(
1285
"May not refresh_data while in a write group.")
1328
1286
if self._real_repository is not None:
1329
1287
self._real_repository.refresh_data()
1628
1586
return self._real_repository.inventories
1630
1588
@needs_write_lock
1631
def pack(self, hint=None, clean_obsolete_packs=False):
1589
def pack(self, hint=None):
1632
1590
"""Compress the data within the repository.
1634
1592
This is not currently implemented within the smart server.
1636
1594
self._ensure_real()
1637
return self._real_repository.pack(hint=hint, clean_obsolete_packs=clean_obsolete_packs)
1595
return self._real_repository.pack(hint=hint)
1640
1598
def revisions(self):
2068
2026
def network_name(self):
2069
2027
return self._network_name
2071
def open(self, a_bzrdir, name=None, ignore_fallbacks=False):
2072
return a_bzrdir.open_branch(name=name,
2073
ignore_fallbacks=ignore_fallbacks)
2029
def open(self, a_bzrdir, ignore_fallbacks=False):
2030
return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
2075
def _vfs_initialize(self, a_bzrdir, name):
2032
def _vfs_initialize(self, a_bzrdir):
2076
2033
# Initialisation when using a local bzrdir object, or a non-vfs init
2077
2034
# method is not available on the server.
2078
2035
# self._custom_format is always set - the start of initialize ensures
2080
2037
if isinstance(a_bzrdir, RemoteBzrDir):
2081
2038
a_bzrdir._ensure_real()
2082
result = self._custom_format.initialize(a_bzrdir._real_bzrdir,
2039
result = self._custom_format.initialize(a_bzrdir._real_bzrdir)
2085
2041
# We assume the bzrdir is parameterised; it may not be.
2086
result = self._custom_format.initialize(a_bzrdir, name)
2042
result = self._custom_format.initialize(a_bzrdir)
2087
2043
if (isinstance(a_bzrdir, RemoteBzrDir) and
2088
2044
not isinstance(result, RemoteBranch)):
2089
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result,
2045
result = RemoteBranch(a_bzrdir, a_bzrdir.find_repository(), result)
2093
def initialize(self, a_bzrdir, name=None):
2048
def initialize(self, a_bzrdir):
2094
2049
# 1) get the network name to use.
2095
2050
if self._custom_format:
2096
2051
network_name = self._custom_format.network_name()
2102
2057
network_name = reference_format.network_name()
2103
2058
# Being asked to create on a non RemoteBzrDir:
2104
2059
if not isinstance(a_bzrdir, RemoteBzrDir):
2105
return self._vfs_initialize(a_bzrdir, name=name)
2060
return self._vfs_initialize(a_bzrdir)
2106
2061
medium = a_bzrdir._client._medium
2107
2062
if medium._is_remote_before((1, 13)):
2108
return self._vfs_initialize(a_bzrdir, name=name)
2063
return self._vfs_initialize(a_bzrdir)
2109
2064
# Creating on a remote bzr dir.
2110
2065
# 2) try direct creation via RPC
2111
2066
path = a_bzrdir._path_for_remote_call(a_bzrdir._client)
2112
if name is not None:
2113
# XXX JRV20100304: Support creating colocated branches
2114
raise errors.NoColocatedBranchSupport(self)
2115
2067
verb = 'BzrDir.create_branch'
2117
2069
response = a_bzrdir._call(verb, path, network_name)
2118
2070
except errors.UnknownSmartMethod:
2119
2071
# Fallback - use vfs methods
2120
2072
medium._remember_remote_is_before((1, 13))
2121
return self._vfs_initialize(a_bzrdir, name=name)
2073
return self._vfs_initialize(a_bzrdir)
2122
2074
if response[0] != 'ok':
2123
2075
raise errors.UnexpectedSmartServerResponse(response)
2124
2076
# Turn the response into a RemoteRepository object.
2132
2084
a_bzrdir._client)
2133
2085
remote_repo = RemoteRepository(repo_bzrdir, repo_format)
2134
2086
remote_branch = RemoteBranch(a_bzrdir, remote_repo,
2135
format=format, setup_stacking=False, name=name)
2087
format=format, setup_stacking=False)
2136
2088
# XXX: We know this is a new branch, so it must have revno 0, revid
2137
2089
# NULL_REVISION. Creating the branch locked would make this be unable
2138
2090
# to be wrong; here its simply very unlikely to be wrong. RBC 20090225
2167
2119
def __init__(self, remote_bzrdir, remote_repository, real_branch=None,
2168
_client=None, format=None, setup_stacking=True, name=None):
2120
_client=None, format=None, setup_stacking=True):
2169
2121
"""Create a RemoteBranch instance.
2171
2123
:param real_branch: An optional local implementation of the branch
2177
2129
:param setup_stacking: If True make an RPC call to determine the
2178
2130
stacked (or not) status of the branch. If False assume the branch
2179
2131
is not stacked.
2180
:param name: Colocated branch name
2182
2133
# We intentionally don't call the parent class's __init__, because it
2183
2134
# will try to assign to self.tags, which is a property in this subclass.
2202
2153
self._real_branch = None
2203
2154
# Fill out expected attributes of branch for bzrlib API users.
2204
2155
self._clear_cached_state()
2205
# TODO: deprecate self.base in favor of user_url
2206
self.base = self.bzrdir.user_url
2156
self.base = self.bzrdir.root_transport.base
2208
2157
self._control_files = None
2209
2158
self._lock_mode = None
2210
2159
self._lock_token = None
2275
2224
'to use vfs implementation')
2276
2225
self.bzrdir._ensure_real()
2277
2226
self._real_branch = self.bzrdir._real_bzrdir.open_branch(
2278
ignore_fallbacks=self._real_ignore_fallbacks, name=self._name)
2227
ignore_fallbacks=self._real_ignore_fallbacks)
2279
2228
if self.repository._real_repository is None:
2280
2229
# Give the remote repository the matching real repo.
2281
2230
real_repo = self._real_branch.repository
2409
2354
self._real_branch.lock_read()
2411
2356
self._lock_count += 1
2412
return lock.LogicalLockResult(self.unlock)
2414
2358
def _remote_lock_write(self, token):
2415
2359
if token is None:
2416
2360
branch_token = repo_token = ''
2418
2362
branch_token = token
2419
repo_token = self.repository.lock_write().repository_token
2363
repo_token = self.repository.lock_write()
2420
2364
self.repository.unlock()
2421
2365
err_context = {'token': token}
2422
2366
response = self._call(
2459
2403
self._lock_count += 1
2460
2404
# Re-lock the repository too.
2461
2405
self.repository.lock_write(self._repo_lock_token)
2462
return BranchWriteLockResult(self.unlock, self._lock_token or None)
2406
return self._lock_token or None
2464
2408
def _unlock(self, branch_token, repo_token):
2465
2409
err_context = {'token': str((branch_token, repo_token))}