17
17
"""Server-side bzrdir related request implmentations."""
19
from __future__ import absolute_import
20
from bzrlib import branch, errors, repository, urlutils
21
from bzrlib.bzrdir import (
31
from ..bzrdir import (
35
from ...controldir import (
25
36
network_format_registry,
27
from bzrlib.smart.request import (
38
from ...sixish import PY3
39
from .request import (
28
40
FailedSmartServerResponse,
29
41
SmartServerRequest,
30
42
SuccessfulSmartServerResponse,
42
54
# Ideally we'd return a FailedSmartServerResponse here rather than
43
55
# a "successful" negative, but we want to be compatibile with
44
56
# clients that don't anticipate errors from this method.
47
default_format = BzrDirFormat.get_default_format()
48
real_bzrdir = default_format.open(t, _found=True)
59
bzr_prober = BzrProber()
50
real_bzrdir._format.probe_transport(t)
61
bzr_prober.probe_transport(t)
51
62
except (errors.NotBranchError, errors.UnknownFormatError):
55
66
return SuccessfulSmartServerResponse((answer,))
67
78
except errors.PathNotChild:
68
79
# The client is trying to ask about a path that they have no access
70
return SuccessfulSmartServerResponse(('no',))
81
return SuccessfulSmartServerResponse((b'no',))
72
83
bd = BzrDir.open_from_transport(t)
73
84
except errors.NotBranchError:
77
88
if bd.has_workingtree():
81
92
return SuccessfulSmartServerResponse(answer)
84
95
class SmartServerRequestBzrDir(SmartServerRequest):
86
97
def do(self, path, *args):
87
"""Open a BzrDir at path, and return self.do_bzrdir_request(*args)."""
98
"""Open a BzrDir at path, and return `self.do_bzrdir_request(*args)`."""
89
100
self._bzrdir = BzrDir.open_from_transport(
90
101
self.transport_from_client_path(path))
91
except errors.NotBranchError, e:
92
return FailedSmartServerResponse(('nobranch',))
102
except errors.NotBranchError as e:
103
return FailedSmartServerResponse((b'nobranch',))
93
104
return self.do_bzrdir_request(*args)
95
106
def _boolean_to_yes_no(self, a_boolean):
101
112
def _format_to_capabilities(self, repo_format):
102
113
rich_root = self._boolean_to_yes_no(repo_format.rich_root_data)
119
130
return '/'.join(segments)
133
class SmartServerBzrDirRequestDestroyBranch(SmartServerRequestBzrDir):
135
def do_bzrdir_request(self, name=None):
136
"""Destroy the branch with the specified name.
139
:return: On success, 'ok'.
142
self._bzrdir.destroy_branch(
143
name.decode('utf-8') if name is not None else None)
144
except errors.NotBranchError as e:
145
return FailedSmartServerResponse((b'nobranch',))
146
return SuccessfulSmartServerResponse((b'ok',))
149
class SmartServerBzrDirRequestHasWorkingTree(SmartServerRequestBzrDir):
151
def do_bzrdir_request(self, name=None):
152
"""Check whether there is a working tree present.
156
:return: If there is a working tree present, 'yes'.
159
if self._bzrdir.has_workingtree():
160
return SuccessfulSmartServerResponse((b'yes', ))
162
return SuccessfulSmartServerResponse((b'no', ))
165
class SmartServerBzrDirRequestDestroyRepository(SmartServerRequestBzrDir):
167
def do_bzrdir_request(self, name=None):
168
"""Destroy the repository.
172
:return: On success, 'ok'.
175
self._bzrdir.destroy_repository()
176
except errors.NoRepositoryPresent as e:
177
return FailedSmartServerResponse((b'norepository',))
178
return SuccessfulSmartServerResponse((b'ok',))
122
181
class SmartServerBzrDirRequestCloningMetaDir(SmartServerRequestBzrDir):
124
183
def do_bzrdir_request(self, require_stacking):
140
199
# The server shouldn't try to resolve references, and it quite
141
200
# possibly can't reach them anyway. The client needs to resolve
142
201
# the branch reference to determine the cloning_metadir.
143
return FailedSmartServerResponse(('BranchReference',))
144
if require_stacking == "True":
202
return FailedSmartServerResponse((b'BranchReference',))
203
if require_stacking == b"True":
145
204
require_stacking = True
147
206
require_stacking = False
148
207
control_format = self._bzrdir.cloning_metadir(
149
208
require_stacking=require_stacking)
150
209
control_name = control_format.network_name()
151
# XXX: There should be a method that tells us that the format does/does
152
# not have subformats.
153
if isinstance(control_format, BzrDirMetaFormat1):
154
branch_name = ('branch',
210
if not control_format.fixed_components:
211
branch_name = (b'branch',
155
212
control_format.get_branch_format().network_name())
156
213
repository_name = control_format.repository_format.network_name()
158
215
# Only MetaDir has delegated formats today.
159
branch_name = ('branch', '')
216
branch_name = (b'branch', b'')
217
repository_name = b''
161
218
return SuccessfulSmartServerResponse((control_name, repository_name,
222
class SmartServerBzrDirRequestCheckoutMetaDir(SmartServerRequestBzrDir):
223
"""Get the format to use for checkouts.
227
:return: on success, a 3-tuple of network names for (control,
228
repository, branch) directories, where '' signifies "not present".
229
If this BzrDir contains a branch reference then this will fail with
230
BranchReference; clients should resolve branch references before
231
calling this RPC (they should not try to create a checkout of a
235
def do_bzrdir_request(self):
237
branch_ref = self._bzrdir.get_branch_reference()
238
except errors.NotBranchError:
240
if branch_ref is not None:
241
# The server shouldn't try to resolve references, and it quite
242
# possibly can't reach them anyway. The client needs to resolve
243
# the branch reference to determine the cloning_metadir.
244
return FailedSmartServerResponse((b'BranchReference',))
245
control_format = self._bzrdir.checkout_metadir()
246
control_name = control_format.network_name()
247
if not control_format.fixed_components:
248
branch_name = control_format.get_branch_format().network_name()
249
repo_name = control_format.repository_format.network_name()
253
return SuccessfulSmartServerResponse(
254
(control_name, repo_name, branch_name))
165
257
class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
167
259
def do(self, path, network_name):
180
272
:param path: The path to the bzrdir.
181
273
:param network_name: The network name of the branch type to create.
182
:return: (ok, network_name)
274
:return: ('ok', branch_format, repo_path, rich_root, tree_ref,
275
external_lookup, repo_format)
184
277
bzrdir = BzrDir.open_from_transport(
185
278
self.transport_from_client_path(path))
186
279
format = branch.network_format_registry.get(network_name)
187
280
bzrdir.branch_format = format
188
result = format.initialize(bzrdir)
281
result = format.initialize(bzrdir, name="")
189
282
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
190
283
result.repository._format)
191
284
branch_format = result._format.network_name()
194
287
result.repository)
195
288
# branch format, repo relpath, rich_root, tree_ref, external_lookup,
196
289
# repo_network_name
197
return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
290
return SuccessfulSmartServerResponse((b'ok', branch_format, repo_path,
198
291
rich_root, tree_ref, external_lookup, repo_format))
222
315
bzrdir = BzrDir.open_from_transport(
223
316
self.transport_from_client_path(path))
224
shared = shared == 'True'
317
shared = shared == b'True'
225
318
format = repository.network_format_registry.get(network_name)
226
319
bzrdir.repository_format = format
227
320
result = format.initialize(bzrdir, shared=shared)
228
321
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
230
return SuccessfulSmartServerResponse(('ok', rich_root, tree_ref,
323
return SuccessfulSmartServerResponse((b'ok', rich_root, tree_ref,
231
324
external_lookup, result._format.network_name()))
275
368
path, rich_root, tree_ref, external_lookup, name = self._find(path)
276
return SuccessfulSmartServerResponse(('ok', path, rich_root, tree_ref))
369
return SuccessfulSmartServerResponse((b'ok', path.encode('utf-8'), rich_root, tree_ref))
277
370
except errors.NoRepositoryPresent:
278
return FailedSmartServerResponse(('norepository', ))
371
return FailedSmartServerResponse((b'norepository', ))
281
374
class SmartServerRequestFindRepositoryV2(SmartServerRequestFindRepository):
299
392
path, rich_root, tree_ref, external_lookup, name = self._find(path)
300
393
return SuccessfulSmartServerResponse(
301
('ok', path, rich_root, tree_ref, external_lookup))
394
(b'ok', path.encode('utf-8'), rich_root, tree_ref, external_lookup))
302
395
except errors.NoRepositoryPresent:
303
return FailedSmartServerResponse(('norepository', ))
396
return FailedSmartServerResponse((b'norepository', ))
306
399
class SmartServerRequestFindRepositoryV3(SmartServerRequestFindRepository):
323
416
path, rich_root, tree_ref, external_lookup, name = self._find(path)
324
417
return SuccessfulSmartServerResponse(
325
('ok', path, rich_root, tree_ref, external_lookup, name))
418
(b'ok', path.encode('utf-8'), rich_root, tree_ref, external_lookup, name))
326
419
except errors.NoRepositoryPresent:
327
return FailedSmartServerResponse(('norepository', ))
420
return FailedSmartServerResponse((b'norepository', ))
330
423
class SmartServerBzrDirRequestConfigFile(SmartServerRequestBzrDir):
332
425
def do_bzrdir_request(self):
333
426
"""Get the configuration bytes for a config file in bzrdir.
335
428
The body is not utf8 decoded - it is the literal bytestream from disk.
337
430
config = self._bzrdir._get_config()
338
431
if config is None:
341
434
content = config._get_config_file().read()
342
435
return SuccessfulSmartServerResponse((), content)
438
class SmartServerBzrDirRequestGetBranches(SmartServerRequestBzrDir):
440
def do_bzrdir_request(self):
441
"""Get the branches in a control directory.
443
The body is a bencoded dictionary, with values similar to the return
444
value of the open branch request.
446
branches = self._bzrdir.get_branches()
448
for name, b in branches.items():
451
ret[name.encode('utf-8')] = (b"branch", b._format.network_name())
452
return SuccessfulSmartServerResponse(
453
(b"success", ), bencode.bencode(ret))
345
456
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
347
458
def do(self, path):
360
471
def parse_NoneTrueFalse(self, arg):
367
478
raise AssertionError("invalid arg %r" % arg)
480
def parse_NoneBytestring(self, arg):
369
483
def parse_NoneString(self, arg):
487
return arg.decode('utf-8')
372
491
def _serialize_NoneTrueFalse(self, arg):
379
498
def do(self, bzrdir_network_name, path, use_existing_dir, create_prefix,
380
499
force_new_repo, stacked_on, stack_on_pwd, repo_format_name,
399
518
stack_on_pwd = self.parse_NoneString(stack_on_pwd)
400
519
make_working_trees = self.parse_NoneTrueFalse(make_working_trees)
401
520
shared_repo = self.parse_NoneTrueFalse(shared_repo)
402
if stack_on_pwd == '.':
403
stack_on_pwd = target_transport.base
404
repo_format_name = self.parse_NoneString(repo_format_name)
521
if stack_on_pwd == b'.':
522
stack_on_pwd = target_transport.base.encode('utf-8')
523
repo_format_name = self.parse_NoneBytestring(repo_format_name)
405
524
repo, bzrdir, stacking, repository_policy = \
406
525
format.initialize_on_transport_ex(target_transport,
407
526
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
423
542
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
425
544
repo_name = repo._format.network_name()
426
repo_bzrdir_name = repo.bzrdir._format.network_name()
545
repo_bzrdir_name = repo.controldir._format.network_name()
427
546
final_stack = repository_policy._stack_on
428
547
final_stack_pwd = repository_policy._stack_on_pwd
429
548
# It is returned locked, but we need to do the lock to get the lock
432
repo_lock_token = repo.lock_write() or ''
551
repo_lock_token = repo.lock_write().repository_token or b''
433
552
if repo_lock_token:
434
553
repo.leave_lock_in_place()
448
567
self._root_client_path, client_path)
449
568
final_stack_pwd = '.'
451
return SuccessfulSmartServerResponse((repo_path, rich_root, tree_ref,
452
external_lookup, repo_name, repo_bzrdir_name,
570
return SuccessfulSmartServerResponse((repo_path.encode('utf-8'),
571
rich_root, tree_ref, external_lookup, repo_name, repo_bzrdir_name,
453
572
bzrdir._format.network_name(),
454
self._serialize_NoneTrueFalse(stacking), final_stack,
455
final_stack_pwd, repo_lock_token))
573
self._serialize_NoneTrueFalse(stacking), final_stack.encode('utf-8'),
574
final_stack_pwd.encode('utf-8'), repo_lock_token))
458
577
class SmartServerRequestOpenBranch(SmartServerRequestBzrDir):
463
582
reference_url = self._bzrdir.get_branch_reference()
464
583
if reference_url is None:
465
return SuccessfulSmartServerResponse(('ok', ''))
467
return SuccessfulSmartServerResponse(('ok', reference_url))
468
except errors.NotBranchError, e:
469
return FailedSmartServerResponse(('nobranch',))
585
return SuccessfulSmartServerResponse((b'ok', reference_url.encode('utf-8')))
586
except errors.NotBranchError as e:
587
return FailedSmartServerResponse((b'nobranch',))
472
590
class SmartServerRequestOpenBranchV2(SmartServerRequestBzrDir):
478
596
if reference_url is None:
479
597
br = self._bzrdir.open_branch(ignore_fallbacks=True)
480
598
format = br._format.network_name()
481
return SuccessfulSmartServerResponse(('branch', format))
599
return SuccessfulSmartServerResponse((b'branch', format))
483
return SuccessfulSmartServerResponse(('ref', reference_url))
484
except errors.NotBranchError, e:
485
return FailedSmartServerResponse(('nobranch',))
601
return SuccessfulSmartServerResponse((b'ref', reference_url.encode('utf-8')))
602
except errors.NotBranchError as e:
603
return FailedSmartServerResponse((b'nobranch',))
488
606
class SmartServerRequestOpenBranchV3(SmartServerRequestBzrDir):
502
620
if reference_url is None:
503
621
br = self._bzrdir.open_branch(ignore_fallbacks=True)
504
622
format = br._format.network_name()
505
return SuccessfulSmartServerResponse(('branch', format))
623
return SuccessfulSmartServerResponse((b'branch', format))
507
return SuccessfulSmartServerResponse(('ref', reference_url))
508
except errors.NotBranchError, e:
625
return SuccessfulSmartServerResponse((b'ref', reference_url.encode('utf-8')))
626
except errors.NotBranchError as e:
509
627
# Stringify the exception so that its .detail attribute will be
630
resp = (b'nobranch',)
513
631
detail = e.detail
515
633
if detail.startswith(': '):
516
634
detail = detail[2:]
635
resp += (detail.encode('utf-8'),)
518
636
return FailedSmartServerResponse(resp)