17
17
"""Server-side bzrdir related request implmentations."""
19
from __future__ import absolute_import
31
from ..bzrdir import (
20
from bzrlib import branch, errors, repository, urlutils
21
from bzrlib.bzrdir import (
35
from ...controldir import (
36
25
network_format_registry,
38
from ...sixish import PY3
39
from .request import (
27
from bzrlib.smart.request import (
40
28
FailedSmartServerResponse,
41
29
SmartServerRequest,
42
30
SuccessfulSmartServerResponse,
54
42
# Ideally we'd return a FailedSmartServerResponse here rather than
55
43
# a "successful" negative, but we want to be compatibile with
56
44
# clients that don't anticipate errors from this method.
59
bzr_prober = BzrProber()
47
default_format = BzrDirFormat.get_default_format()
48
real_bzrdir = default_format.open(t, _found=True)
61
bzr_prober.probe_transport(t)
50
real_bzrdir._format.probe_transport(t)
62
51
except (errors.NotBranchError, errors.UnknownFormatError):
66
55
return SuccessfulSmartServerResponse((answer,))
78
67
except errors.PathNotChild:
79
68
# The client is trying to ask about a path that they have no access
81
return SuccessfulSmartServerResponse((b'no',))
70
return SuccessfulSmartServerResponse(('no',))
83
72
bd = BzrDir.open_from_transport(t)
84
73
except errors.NotBranchError:
88
77
if bd.has_workingtree():
92
81
return SuccessfulSmartServerResponse(answer)
95
84
class SmartServerRequestBzrDir(SmartServerRequest):
97
86
def do(self, path, *args):
98
"""Open a BzrDir at path, and return `self.do_bzrdir_request(*args)`."""
87
"""Open a BzrDir at path, and return self.do_bzrdir_request(*args)."""
100
89
self._bzrdir = BzrDir.open_from_transport(
101
90
self.transport_from_client_path(path))
102
except errors.NotBranchError as e:
103
return FailedSmartServerResponse((b'nobranch',))
91
except errors.NotBranchError, e:
92
return FailedSmartServerResponse(('nobranch',))
104
93
return self.do_bzrdir_request(*args)
106
95
def _boolean_to_yes_no(self, a_boolean):
112
101
def _format_to_capabilities(self, repo_format):
113
102
rich_root = self._boolean_to_yes_no(repo_format.rich_root_data)
130
119
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',))
181
122
class SmartServerBzrDirRequestCloningMetaDir(SmartServerRequestBzrDir):
183
124
def do_bzrdir_request(self, require_stacking):
184
125
"""Get the format that should be used when cloning from this dir.
188
129
:return: on success, a 3-tuple of network names for (control,
189
130
repository, branch) directories, where '' signifies "not present".
190
131
If this BzrDir contains a branch reference then this will fail with
199
140
# The server shouldn't try to resolve references, and it quite
200
141
# possibly can't reach them anyway. The client needs to resolve
201
142
# the branch reference to determine the cloning_metadir.
202
return FailedSmartServerResponse((b'BranchReference',))
203
if require_stacking == b"True":
143
return FailedSmartServerResponse(('BranchReference',))
144
if require_stacking == "True":
204
145
require_stacking = True
206
147
require_stacking = False
207
148
control_format = self._bzrdir.cloning_metadir(
208
149
require_stacking=require_stacking)
209
150
control_name = control_format.network_name()
210
if not control_format.fixed_components:
211
branch_name = (b'branch',
212
control_format.get_branch_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',
155
control_format.get_branch_format().network_name())
213
156
repository_name = control_format.repository_format.network_name()
215
158
# Only MetaDir has delegated formats today.
216
branch_name = (b'branch', b'')
217
repository_name = b''
159
branch_name = ('branch', '')
218
161
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))
257
165
class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
272
180
:param path: The path to the bzrdir.
273
181
:param network_name: The network name of the branch type to create.
274
:return: ('ok', branch_format, repo_path, rich_root, tree_ref,
275
external_lookup, repo_format)
182
:return: (ok, network_name)
277
184
bzrdir = BzrDir.open_from_transport(
278
185
self.transport_from_client_path(path))
279
186
format = branch.network_format_registry.get(network_name)
280
187
bzrdir.branch_format = format
281
result = format.initialize(bzrdir, name="")
188
result = format.initialize(bzrdir)
282
189
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
283
190
result.repository._format)
284
191
branch_format = result._format.network_name()
285
192
repo_format = result.repository._format.network_name()
286
193
repo_path = self._repo_relpath(bzrdir.root_transport,
288
195
# branch format, repo relpath, rich_root, tree_ref, external_lookup,
289
196
# repo_network_name
290
return SuccessfulSmartServerResponse((b'ok', branch_format, repo_path,
291
rich_root, tree_ref, external_lookup, repo_format))
197
return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
198
rich_root, tree_ref, external_lookup, repo_format))
294
201
class SmartServerRequestCreateRepository(SmartServerRequestBzrDir):
315
222
bzrdir = BzrDir.open_from_transport(
316
223
self.transport_from_client_path(path))
317
shared = shared == b'True'
224
shared = shared == 'True'
318
225
format = repository.network_format_registry.get(network_name)
319
226
bzrdir.repository_format = format
320
227
result = format.initialize(bzrdir, shared=shared)
321
228
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
323
return SuccessfulSmartServerResponse((b'ok', rich_root, tree_ref,
324
external_lookup, result._format.network_name()))
230
return SuccessfulSmartServerResponse(('ok', rich_root, tree_ref,
231
external_lookup, result._format.network_name()))
327
234
class SmartServerRequestFindRepository(SmartServerRequestBzrDir):
368
275
path, rich_root, tree_ref, external_lookup, name = self._find(path)
369
return SuccessfulSmartServerResponse((b'ok', path.encode('utf-8'), rich_root, tree_ref))
276
return SuccessfulSmartServerResponse(('ok', path, rich_root, tree_ref))
370
277
except errors.NoRepositoryPresent:
371
return FailedSmartServerResponse((b'norepository', ))
278
return FailedSmartServerResponse(('norepository', ))
374
281
class SmartServerRequestFindRepositoryV2(SmartServerRequestFindRepository):
392
299
path, rich_root, tree_ref, external_lookup, name = self._find(path)
393
300
return SuccessfulSmartServerResponse(
394
(b'ok', path.encode('utf-8'), rich_root, tree_ref, external_lookup))
301
('ok', path, rich_root, tree_ref, external_lookup))
395
302
except errors.NoRepositoryPresent:
396
return FailedSmartServerResponse((b'norepository', ))
303
return FailedSmartServerResponse(('norepository', ))
399
306
class SmartServerRequestFindRepositoryV3(SmartServerRequestFindRepository):
416
323
path, rich_root, tree_ref, external_lookup, name = self._find(path)
417
324
return SuccessfulSmartServerResponse(
418
(b'ok', path.encode('utf-8'), rich_root, tree_ref, external_lookup, name))
325
('ok', path, rich_root, tree_ref, external_lookup, name))
419
326
except errors.NoRepositoryPresent:
420
return FailedSmartServerResponse((b'norepository', ))
327
return FailedSmartServerResponse(('norepository', ))
423
330
class SmartServerBzrDirRequestConfigFile(SmartServerRequestBzrDir):
425
332
def do_bzrdir_request(self):
426
333
"""Get the configuration bytes for a config file in bzrdir.
428
335
The body is not utf8 decoded - it is the literal bytestream from disk.
430
337
config = self._bzrdir._get_config()
431
338
if config is None:
434
341
content = config._get_config_file().read()
435
342
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
branch_names = self._bzrdir.branch_names()
448
for name in branch_names:
451
branch_ref = self._bzrdir.get_branch_reference(name=name)
452
if branch_ref is not None:
453
branch_ref = urlutils.relative_url(self._bzrdir.user_url, branch_ref)
454
value = (b"ref", branch_ref.encode('utf-8'))
456
b = self._bzrdir.open_branch(name=name, ignore_fallbacks=True)
457
value = (b"branch", b._format.network_name())
458
ret[name.encode('utf-8')] = value
459
return SuccessfulSmartServerResponse(
460
(b"success", ), bencode.bencode(ret))
463
345
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
465
347
def do(self, path):
478
360
def parse_NoneTrueFalse(self, arg):
485
367
raise AssertionError("invalid arg %r" % arg)
487
def parse_NoneBytestring(self, arg):
369
def parse_NoneString(self, arg):
488
370
return arg or None
490
def parse_NoneString(self, arg):
494
return arg.decode('utf-8')
498
372
def _serialize_NoneTrueFalse(self, arg):
505
379
def do(self, bzrdir_network_name, path, use_existing_dir, create_prefix,
506
force_new_repo, stacked_on, stack_on_pwd, repo_format_name,
507
make_working_trees, shared_repo):
380
force_new_repo, stacked_on, stack_on_pwd, repo_format_name,
381
make_working_trees, shared_repo):
508
382
"""Initialize a bzrdir at path as per
509
383
BzrDirFormat.initialize_on_transport_ex.
525
399
stack_on_pwd = self.parse_NoneString(stack_on_pwd)
526
400
make_working_trees = self.parse_NoneTrueFalse(make_working_trees)
527
401
shared_repo = self.parse_NoneTrueFalse(shared_repo)
528
if stack_on_pwd == b'.':
529
stack_on_pwd = target_transport.base.encode('utf-8')
530
repo_format_name = self.parse_NoneBytestring(repo_format_name)
402
if stack_on_pwd == '.':
403
stack_on_pwd = target_transport.base
404
repo_format_name = self.parse_NoneString(repo_format_name)
531
405
repo, bzrdir, stacking, repository_policy = \
532
406
format.initialize_on_transport_ex(target_transport,
533
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
534
force_new_repo=force_new_repo, stacked_on=stacked_on,
535
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
536
make_working_trees=make_working_trees, shared_repo=shared_repo)
407
use_existing_dir=use_existing_dir, create_prefix=create_prefix,
408
force_new_repo=force_new_repo, stacked_on=stacked_on,
409
stack_on_pwd=stack_on_pwd, repo_format_name=repo_format_name,
410
make_working_trees=make_working_trees, shared_repo=shared_repo)
540
rich_root = tree_ref = external_lookup = b''
541
repo_bzrdir_name = b''
414
rich_root = tree_ref = external_lookup = ''
415
repo_bzrdir_name = ''
542
416
final_stack = None
543
417
final_stack_pwd = None
544
repo_lock_token = b''
546
420
repo_path = self._repo_relpath(bzrdir.root_transport, repo)
547
421
if repo_path == '':
549
423
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
551
425
repo_name = repo._format.network_name()
552
repo_bzrdir_name = repo.controldir._format.network_name()
426
repo_bzrdir_name = repo.bzrdir._format.network_name()
553
427
final_stack = repository_policy._stack_on
554
428
final_stack_pwd = repository_policy._stack_on_pwd
555
429
# It is returned locked, but we need to do the lock to get the lock
558
repo_lock_token = repo.lock_write().repository_token or b''
432
repo_lock_token = repo.lock_write().repository_token or ''
559
433
if repo_lock_token:
560
434
repo.leave_lock_in_place()
574
448
self._root_client_path, client_path)
575
449
final_stack_pwd = '.'
577
return SuccessfulSmartServerResponse((repo_path.encode('utf-8'),
578
rich_root, tree_ref, external_lookup, repo_name, repo_bzrdir_name,
579
bzrdir._format.network_name(),
580
self._serialize_NoneTrueFalse(
581
stacking), final_stack.encode('utf-8'),
582
final_stack_pwd.encode('utf-8'), repo_lock_token))
451
return SuccessfulSmartServerResponse((repo_path, rich_root, tree_ref,
452
external_lookup, repo_name, repo_bzrdir_name,
453
bzrdir._format.network_name(),
454
self._serialize_NoneTrueFalse(stacking), final_stack,
455
final_stack_pwd, repo_lock_token))
585
458
class SmartServerRequestOpenBranch(SmartServerRequestBzrDir):
590
463
reference_url = self._bzrdir.get_branch_reference()
591
464
if reference_url is None:
593
return SuccessfulSmartServerResponse((b'ok', reference_url.encode('utf-8')))
594
except errors.NotBranchError as e:
595
return FailedSmartServerResponse((b'nobranch',))
465
return SuccessfulSmartServerResponse(('ok', ''))
467
return SuccessfulSmartServerResponse(('ok', reference_url))
468
except errors.NotBranchError, e:
469
return FailedSmartServerResponse(('nobranch',))
598
472
class SmartServerRequestOpenBranchV2(SmartServerRequestBzrDir):
604
478
if reference_url is None:
605
479
br = self._bzrdir.open_branch(ignore_fallbacks=True)
606
480
format = br._format.network_name()
607
return SuccessfulSmartServerResponse((b'branch', format))
481
return SuccessfulSmartServerResponse(('branch', format))
609
return SuccessfulSmartServerResponse((b'ref', reference_url.encode('utf-8')))
610
except errors.NotBranchError as e:
611
return FailedSmartServerResponse((b'nobranch',))
483
return SuccessfulSmartServerResponse(('ref', reference_url))
484
except errors.NotBranchError, e:
485
return FailedSmartServerResponse(('nobranch',))
614
488
class SmartServerRequestOpenBranchV3(SmartServerRequestBzrDir):
616
490
def do_bzrdir_request(self):
617
491
"""Open a branch at path and return the reference or format.
619
493
This version introduced in 2.1.
621
495
Differences to SmartServerRequestOpenBranchV2:
628
502
if reference_url is None:
629
503
br = self._bzrdir.open_branch(ignore_fallbacks=True)
630
504
format = br._format.network_name()
631
return SuccessfulSmartServerResponse((b'branch', format))
505
return SuccessfulSmartServerResponse(('branch', format))
633
return SuccessfulSmartServerResponse((b'ref', reference_url.encode('utf-8')))
634
except errors.NotBranchError as e:
507
return SuccessfulSmartServerResponse(('ref', reference_url))
508
except errors.NotBranchError, e:
635
509
# Stringify the exception so that its .detail attribute will be
638
resp = (b'nobranch',)
639
513
detail = e.detail
641
515
if detail.startswith(': '):
642
516
detail = detail[2:]
643
resp += (detail.encode('utf-8'),)
644
518
return FailedSmartServerResponse(resp)