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 .request import (
27
from bzrlib.smart.request import (
39
28
FailedSmartServerResponse,
40
29
SmartServerRequest,
41
30
SuccessfulSmartServerResponse,
53
42
# Ideally we'd return a FailedSmartServerResponse here rather than
54
43
# a "successful" negative, but we want to be compatibile with
55
44
# clients that don't anticipate errors from this method.
58
bzr_prober = BzrProber()
47
default_format = BzrDirFormat.get_default_format()
48
real_bzrdir = default_format.open(t, _found=True)
60
bzr_prober.probe_transport(t)
50
real_bzrdir._format.probe_transport(t)
61
51
except (errors.NotBranchError, errors.UnknownFormatError):
65
55
return SuccessfulSmartServerResponse((answer,))
77
67
except errors.PathNotChild:
78
68
# The client is trying to ask about a path that they have no access
80
return SuccessfulSmartServerResponse((b'no',))
70
return SuccessfulSmartServerResponse(('no',))
82
72
bd = BzrDir.open_from_transport(t)
83
73
except errors.NotBranchError:
87
77
if bd.has_workingtree():
91
81
return SuccessfulSmartServerResponse(answer)
94
84
class SmartServerRequestBzrDir(SmartServerRequest):
96
86
def do(self, path, *args):
97
"""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)."""
99
89
self._bzrdir = BzrDir.open_from_transport(
100
90
self.transport_from_client_path(path))
101
except errors.NotBranchError as e:
102
return FailedSmartServerResponse((b'nobranch',))
91
except errors.NotBranchError, e:
92
return FailedSmartServerResponse(('nobranch',))
103
93
return self.do_bzrdir_request(*args)
105
95
def _boolean_to_yes_no(self, a_boolean):
111
101
def _format_to_capabilities(self, repo_format):
112
102
rich_root = self._boolean_to_yes_no(repo_format.rich_root_data)
129
119
return '/'.join(segments)
132
class SmartServerBzrDirRequestDestroyBranch(SmartServerRequestBzrDir):
134
def do_bzrdir_request(self, name=None):
135
"""Destroy the branch with the specified name.
138
:return: On success, 'ok'.
141
self._bzrdir.destroy_branch(
142
name.decode('utf-8') if name is not None else None)
143
except errors.NotBranchError as e:
144
return FailedSmartServerResponse((b'nobranch',))
145
return SuccessfulSmartServerResponse((b'ok',))
148
class SmartServerBzrDirRequestHasWorkingTree(SmartServerRequestBzrDir):
150
def do_bzrdir_request(self, name=None):
151
"""Check whether there is a working tree present.
155
:return: If there is a working tree present, 'yes'.
158
if self._bzrdir.has_workingtree():
159
return SuccessfulSmartServerResponse((b'yes', ))
161
return SuccessfulSmartServerResponse((b'no', ))
164
class SmartServerBzrDirRequestDestroyRepository(SmartServerRequestBzrDir):
166
def do_bzrdir_request(self, name=None):
167
"""Destroy the repository.
171
:return: On success, 'ok'.
174
self._bzrdir.destroy_repository()
175
except errors.NoRepositoryPresent as e:
176
return FailedSmartServerResponse((b'norepository',))
177
return SuccessfulSmartServerResponse((b'ok',))
180
122
class SmartServerBzrDirRequestCloningMetaDir(SmartServerRequestBzrDir):
182
124
def do_bzrdir_request(self, require_stacking):
198
140
# The server shouldn't try to resolve references, and it quite
199
141
# possibly can't reach them anyway. The client needs to resolve
200
142
# the branch reference to determine the cloning_metadir.
201
return FailedSmartServerResponse((b'BranchReference',))
202
if require_stacking == b"True":
143
return FailedSmartServerResponse(('BranchReference',))
144
if require_stacking == "True":
203
145
require_stacking = True
205
147
require_stacking = False
206
148
control_format = self._bzrdir.cloning_metadir(
207
149
require_stacking=require_stacking)
208
150
control_name = control_format.network_name()
209
if not control_format.fixed_components:
210
branch_name = (b'branch',
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',
211
155
control_format.get_branch_format().network_name())
212
156
repository_name = control_format.repository_format.network_name()
214
158
# Only MetaDir has delegated formats today.
215
branch_name = (b'branch', b'')
216
repository_name = b''
159
branch_name = ('branch', '')
217
161
return SuccessfulSmartServerResponse((control_name, repository_name,
221
class SmartServerBzrDirRequestCheckoutMetaDir(SmartServerRequestBzrDir):
222
"""Get the format to use for checkouts.
226
:return: on success, a 3-tuple of network names for (control,
227
repository, branch) directories, where '' signifies "not present".
228
If this BzrDir contains a branch reference then this will fail with
229
BranchReference; clients should resolve branch references before
230
calling this RPC (they should not try to create a checkout of a
234
def do_bzrdir_request(self):
236
branch_ref = self._bzrdir.get_branch_reference()
237
except errors.NotBranchError:
239
if branch_ref is not None:
240
# The server shouldn't try to resolve references, and it quite
241
# possibly can't reach them anyway. The client needs to resolve
242
# the branch reference to determine the cloning_metadir.
243
return FailedSmartServerResponse((b'BranchReference',))
244
control_format = self._bzrdir.checkout_metadir()
245
control_name = control_format.network_name()
246
if not control_format.fixed_components:
247
branch_name = control_format.get_branch_format().network_name()
248
repo_name = control_format.repository_format.network_name()
252
return SuccessfulSmartServerResponse(
253
(control_name, repo_name, branch_name))
256
165
class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
258
167
def do(self, path, network_name):
271
180
:param path: The path to the bzrdir.
272
181
:param network_name: The network name of the branch type to create.
273
:return: ('ok', branch_format, repo_path, rich_root, tree_ref,
274
external_lookup, repo_format)
182
:return: (ok, network_name)
276
184
bzrdir = BzrDir.open_from_transport(
277
185
self.transport_from_client_path(path))
278
186
format = branch.network_format_registry.get(network_name)
279
187
bzrdir.branch_format = format
280
result = format.initialize(bzrdir, name="")
188
result = format.initialize(bzrdir)
281
189
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
282
190
result.repository._format)
283
191
branch_format = result._format.network_name()
286
194
result.repository)
287
195
# branch format, repo relpath, rich_root, tree_ref, external_lookup,
288
196
# repo_network_name
289
return SuccessfulSmartServerResponse((b'ok', branch_format, repo_path,
197
return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
290
198
rich_root, tree_ref, external_lookup, repo_format))
314
222
bzrdir = BzrDir.open_from_transport(
315
223
self.transport_from_client_path(path))
316
shared = shared == b'True'
224
shared = shared == 'True'
317
225
format = repository.network_format_registry.get(network_name)
318
226
bzrdir.repository_format = format
319
227
result = format.initialize(bzrdir, shared=shared)
320
228
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
322
return SuccessfulSmartServerResponse((b'ok', rich_root, tree_ref,
230
return SuccessfulSmartServerResponse(('ok', rich_root, tree_ref,
323
231
external_lookup, result._format.network_name()))
367
275
path, rich_root, tree_ref, external_lookup, name = self._find(path)
368
return SuccessfulSmartServerResponse((b'ok', path.encode('utf-8'), rich_root, tree_ref))
276
return SuccessfulSmartServerResponse(('ok', path, rich_root, tree_ref))
369
277
except errors.NoRepositoryPresent:
370
return FailedSmartServerResponse((b'norepository', ))
278
return FailedSmartServerResponse(('norepository', ))
373
281
class SmartServerRequestFindRepositoryV2(SmartServerRequestFindRepository):
391
299
path, rich_root, tree_ref, external_lookup, name = self._find(path)
392
300
return SuccessfulSmartServerResponse(
393
(b'ok', path.encode('utf-8'), rich_root, tree_ref, external_lookup))
301
('ok', path, rich_root, tree_ref, external_lookup))
394
302
except errors.NoRepositoryPresent:
395
return FailedSmartServerResponse((b'norepository', ))
303
return FailedSmartServerResponse(('norepository', ))
398
306
class SmartServerRequestFindRepositoryV3(SmartServerRequestFindRepository):
415
323
path, rich_root, tree_ref, external_lookup, name = self._find(path)
416
324
return SuccessfulSmartServerResponse(
417
(b'ok', path.encode('utf-8'), rich_root, tree_ref, external_lookup, name))
325
('ok', path, rich_root, tree_ref, external_lookup, name))
418
326
except errors.NoRepositoryPresent:
419
return FailedSmartServerResponse((b'norepository', ))
327
return FailedSmartServerResponse(('norepository', ))
422
330
class SmartServerBzrDirRequestConfigFile(SmartServerRequestBzrDir):
424
332
def do_bzrdir_request(self):
425
333
"""Get the configuration bytes for a config file in bzrdir.
427
335
The body is not utf8 decoded - it is the literal bytestream from disk.
429
337
config = self._bzrdir._get_config()
430
338
if config is None:
433
341
content = config._get_config_file().read()
434
342
return SuccessfulSmartServerResponse((), content)
437
class SmartServerBzrDirRequestGetBranches(SmartServerRequestBzrDir):
439
def do_bzrdir_request(self):
440
"""Get the branches in a control directory.
442
The body is a bencoded dictionary, with values similar to the return
443
value of the open branch request.
445
branches = self._bzrdir.get_branches()
447
for name, b in branches.items():
450
ret[name.encode('utf-8')] = (b"branch", b._format.network_name())
451
return SuccessfulSmartServerResponse(
452
(b"success", ), bencode.bencode(ret))
455
345
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
457
347
def do(self, path):
509
399
stack_on_pwd = self.parse_NoneString(stack_on_pwd)
510
400
make_working_trees = self.parse_NoneTrueFalse(make_working_trees)
511
401
shared_repo = self.parse_NoneTrueFalse(shared_repo)
512
if stack_on_pwd == b'.':
513
stack_on_pwd = target_transport.base.encode('utf-8')
402
if stack_on_pwd == '.':
403
stack_on_pwd = target_transport.base
514
404
repo_format_name = self.parse_NoneString(repo_format_name)
515
405
repo, bzrdir, stacking, repository_policy = \
516
406
format.initialize_on_transport_ex(target_transport,
533
423
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
535
425
repo_name = repo._format.network_name()
536
repo_bzrdir_name = repo.controldir._format.network_name()
426
repo_bzrdir_name = repo.bzrdir._format.network_name()
537
427
final_stack = repository_policy._stack_on
538
428
final_stack_pwd = repository_policy._stack_on_pwd
539
429
# It is returned locked, but we need to do the lock to get the lock
542
repo_lock_token = repo.lock_write().repository_token or b''
432
repo_lock_token = repo.lock_write() or ''
543
433
if repo_lock_token:
544
434
repo.leave_lock_in_place()
558
448
self._root_client_path, client_path)
559
449
final_stack_pwd = '.'
561
return SuccessfulSmartServerResponse((repo_path.encode('utf-8'),
562
rich_root, tree_ref, external_lookup, repo_name, repo_bzrdir_name,
451
return SuccessfulSmartServerResponse((repo_path, rich_root, tree_ref,
452
external_lookup, repo_name, repo_bzrdir_name,
563
453
bzrdir._format.network_name(),
564
self._serialize_NoneTrueFalse(stacking), final_stack.encode('utf-8'),
565
final_stack_pwd.encode('utf-8'), repo_lock_token))
454
self._serialize_NoneTrueFalse(stacking), final_stack,
455
final_stack_pwd, repo_lock_token))
568
458
class SmartServerRequestOpenBranch(SmartServerRequestBzrDir):
573
463
reference_url = self._bzrdir.get_branch_reference()
574
464
if reference_url is None:
576
return SuccessfulSmartServerResponse((b'ok', reference_url.encode('utf-8')))
577
except errors.NotBranchError as e:
578
return FailedSmartServerResponse((b'nobranch',))
465
return SuccessfulSmartServerResponse(('ok', ''))
467
return SuccessfulSmartServerResponse(('ok', reference_url))
468
except errors.NotBranchError, e:
469
return FailedSmartServerResponse(('nobranch',))
581
472
class SmartServerRequestOpenBranchV2(SmartServerRequestBzrDir):
587
478
if reference_url is None:
588
479
br = self._bzrdir.open_branch(ignore_fallbacks=True)
589
480
format = br._format.network_name()
590
return SuccessfulSmartServerResponse((b'branch', format))
481
return SuccessfulSmartServerResponse(('branch', format))
592
return SuccessfulSmartServerResponse((b'ref', reference_url.encode('utf-8')))
593
except errors.NotBranchError as e:
594
return FailedSmartServerResponse((b'nobranch',))
483
return SuccessfulSmartServerResponse(('ref', reference_url))
484
except errors.NotBranchError, e:
485
return FailedSmartServerResponse(('nobranch',))
597
488
class SmartServerRequestOpenBranchV3(SmartServerRequestBzrDir):
611
502
if reference_url is None:
612
503
br = self._bzrdir.open_branch(ignore_fallbacks=True)
613
504
format = br._format.network_name()
614
return SuccessfulSmartServerResponse((b'branch', format))
505
return SuccessfulSmartServerResponse(('branch', format))
616
return SuccessfulSmartServerResponse((b'ref', reference_url.encode('utf-8')))
617
except errors.NotBranchError as e:
507
return SuccessfulSmartServerResponse(('ref', reference_url))
508
except errors.NotBranchError, e:
618
509
# Stringify the exception so that its .detail attribute will be
621
resp = (b'nobranch',)
622
513
detail = e.detail
624
515
if detail.startswith(': '):
625
516
detail = detail[2:]
626
resp += (detail.encode('utf-8'),)
627
518
return FailedSmartServerResponse(resp)