1
# Copyright (C) 2006 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
"""Server-side bzrdir related request implmentations."""
20
from bzrlib import branch, errors, repository
21
from bzrlib.bzrdir import BzrDir, BzrDirFormat, BzrDirMetaFormat1
22
from bzrlib.smart.request import (
23
FailedSmartServerResponse,
25
SuccessfulSmartServerResponse,
29
class SmartServerRequestOpenBzrDir(SmartServerRequest):
32
from bzrlib.bzrdir import BzrDirFormat
34
t = self.transport_from_client_path(path)
35
except errors.PathNotChild:
36
# The client is trying to ask about a path that they have no access
38
# Ideally we'd return a FailedSmartServerResponse here rather than
39
# a "successful" negative, but we want to be compatibile with
40
# clients that don't anticipate errors from this method.
43
default_format = BzrDirFormat.get_default_format()
44
real_bzrdir = default_format.open(t, _found=True)
46
real_bzrdir._format.probe_transport(t)
47
except (errors.NotBranchError, errors.UnknownFormatError):
51
return SuccessfulSmartServerResponse((answer,))
54
class SmartServerRequestBzrDir(SmartServerRequest):
56
def do(self, path, *args):
57
"""Open a BzrDir at path, and return self.do_bzrdir_request(*args)."""
58
self._bzrdir = BzrDir.open_from_transport(
59
self.transport_from_client_path(path))
60
return self.do_bzrdir_request(*args)
62
def _boolean_to_yes_no(self, a_boolean):
68
def _format_to_capabilities(self, repo_format):
69
rich_root = self._boolean_to_yes_no(repo_format.rich_root_data)
70
tree_ref = self._boolean_to_yes_no(
71
repo_format.supports_tree_reference)
72
external_lookup = self._boolean_to_yes_no(
73
repo_format.supports_external_lookups)
74
return rich_root, tree_ref, external_lookup
76
def _repo_relpath(self, current_transport, repository):
77
"""Get the relative path for repository from current_transport."""
78
# the relpath of the bzrdir in the found repository gives us the
79
# path segments to pop-out.
80
relpath = repository.bzrdir.root_transport.relpath(
81
current_transport.base)
83
segments = ['..'] * len(relpath.split('/'))
86
return '/'.join(segments)
89
class SmartServerBzrDirRequestCloningMetaDir(SmartServerRequestBzrDir):
91
def do_bzrdir_request(self, require_stacking):
92
"""Get the format that should be used when cloning from this dir."""
94
branch_ref = self._bzrdir.get_branch_reference()
95
except errors.NotBranchError:
97
if require_stacking == "True":
98
require_stacking = True
100
require_stacking = False
101
control_format = self._bzrdir.cloning_metadir(
102
require_stacking=require_stacking)
103
control_name = control_format.network_name()
104
# XXX: There should be a method that tells us that the format does/does not
106
if isinstance(control_format, BzrDirMetaFormat1):
107
if branch_ref is not None:
108
# If there's a branch reference, the client will have to resolve
109
# the branch reference to figure out the cloning metadir
110
branch_name = ('reference', branch_ref)
113
'direct', control_format.get_branch_format().network_name())
114
repository_name = control_format.repository_format.network_name()
116
# Only MetaDir has delegated formats today.
119
return SuccessfulSmartServerResponse((control_name, repository_name,
123
class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
125
def do(self, path, network_name):
126
"""Create a branch in the bzr dir at path.
128
This operates precisely like 'bzrdir.create_branch'.
130
If a bzrdir is not present, an exception is propogated
131
rather than 'no branch' because these are different conditions (and
132
this method should only be called after establishing that a bzr dir
135
This is the initial version of this method introduced to the smart
138
:param path: The path to the bzrdir.
139
:param network_name: The network name of the branch type to create.
140
:return: (ok, network_name)
142
bzrdir = BzrDir.open_from_transport(
143
self.transport_from_client_path(path))
144
format = branch.network_format_registry.get(network_name)
145
bzrdir.branch_format = format
146
result = format.initialize(bzrdir)
147
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
148
result.repository._format)
149
branch_format = result._format.network_name()
150
repo_format = result.repository._format.network_name()
151
repo_path = self._repo_relpath(bzrdir.root_transport,
153
# branch format, repo relpath, rich_root, tree_ref, external_lookup,
155
return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
156
rich_root, tree_ref, external_lookup, repo_format))
159
class SmartServerRequestCreateRepository(SmartServerRequestBzrDir):
161
def do(self, path, network_name, shared):
162
"""Create a repository in the bzr dir at path.
164
This operates precisely like 'bzrdir.create_repository'.
166
If a bzrdir is not present, an exception is propogated
167
rather than 'no branch' because these are different conditions (and
168
this method should only be called after establishing that a bzr dir
171
This is the initial version of this method introduced to the smart
174
:param path: The path to the bzrdir.
175
:param network_name: The network name of the repository type to create.
176
:param shared: The value to pass create_repository for the shared
178
:return: (ok, rich_root, tree_ref, external_lookup, network_name)
180
bzrdir = BzrDir.open_from_transport(
181
self.transport_from_client_path(path))
182
shared = shared == 'True'
183
format = repository.network_format_registry.get(network_name)
184
bzrdir.repository_format = format
185
result = format.initialize(bzrdir, shared=shared)
186
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
188
return SuccessfulSmartServerResponse(('ok', rich_root, tree_ref,
189
external_lookup, result._format.network_name()))
192
class SmartServerRequestFindRepository(SmartServerRequestBzrDir):
194
def _find(self, path):
195
"""try to find a repository from path upwards
197
This operates precisely like 'bzrdir.find_repository'.
199
:return: (relpath, rich_root, tree_ref, external_lookup, network_name).
200
All are strings, relpath is a / prefixed path, the next three are
201
either 'yes' or 'no', and the last is a repository format network
203
:raises errors.NoRepositoryPresent: When there is no repository
206
bzrdir = BzrDir.open_from_transport(
207
self.transport_from_client_path(path))
208
repository = bzrdir.find_repository()
209
path = self._repo_relpath(bzrdir.root_transport, repository)
210
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
212
network_name = repository._format.network_name()
213
return path, rich_root, tree_ref, external_lookup, network_name
216
class SmartServerRequestFindRepositoryV1(SmartServerRequestFindRepository):
219
"""try to find a repository from path upwards
221
This operates precisely like 'bzrdir.find_repository'.
223
If a bzrdir is not present, an exception is propogated
224
rather than 'no branch' because these are different conditions.
226
This is the initial version of this method introduced with the smart
227
server. Modern clients will try the V2 method that adds support for the
228
supports_external_lookups attribute.
230
:return: norepository or ok, relpath.
233
path, rich_root, tree_ref, external_lookup, name = self._find(path)
234
return SuccessfulSmartServerResponse(('ok', path, rich_root, tree_ref))
235
except errors.NoRepositoryPresent:
236
return FailedSmartServerResponse(('norepository', ))
239
class SmartServerRequestFindRepositoryV2(SmartServerRequestFindRepository):
242
"""try to find a repository from path upwards
244
This operates precisely like 'bzrdir.find_repository'.
246
If a bzrdir is not present, an exception is propogated
247
rather than 'no branch' because these are different conditions.
249
This is the second edition of this method introduced in bzr 1.3, which
250
returns information about the supports_external_lookups format
253
:return: norepository or ok, relpath, rich_root, tree_ref,
257
path, rich_root, tree_ref, external_lookup, name = self._find(path)
258
return SuccessfulSmartServerResponse(
259
('ok', path, rich_root, tree_ref, external_lookup))
260
except errors.NoRepositoryPresent:
261
return FailedSmartServerResponse(('norepository', ))
264
class SmartServerRequestFindRepositoryV3(SmartServerRequestFindRepository):
267
"""try to find a repository from path upwards
269
This operates precisely like 'bzrdir.find_repository'.
271
If a bzrdir is not present, an exception is propogated
272
rather than 'no branch' because these are different conditions.
274
This is the third edition of this method introduced in bzr 1.13, which
275
returns information about the network name of the repository format.
277
:return: norepository or ok, relpath, rich_root, tree_ref,
278
external_lookup, network_name.
281
path, rich_root, tree_ref, external_lookup, name = self._find(path)
282
return SuccessfulSmartServerResponse(
283
('ok', path, rich_root, tree_ref, external_lookup, name))
284
except errors.NoRepositoryPresent:
285
return FailedSmartServerResponse(('norepository', ))
288
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
291
"""Initialize a bzrdir at path.
293
The default format of the server is used.
294
:return: SmartServerResponse(('ok', ))
296
target_transport = self.transport_from_client_path(path)
297
BzrDirFormat.get_default_format().initialize_on_transport(target_transport)
298
return SuccessfulSmartServerResponse(('ok', ))
301
class SmartServerRequestOpenBranch(SmartServerRequest):
304
"""try to open a branch at path and return ok/nobranch.
306
If a bzrdir is not present, an exception is propogated
307
rather than 'no branch' because these are different conditions.
309
bzrdir = BzrDir.open_from_transport(
310
self.transport_from_client_path(path))
312
reference_url = bzrdir.get_branch_reference()
313
if reference_url is None:
314
return SuccessfulSmartServerResponse(('ok', ''))
316
return SuccessfulSmartServerResponse(('ok', reference_url))
317
except errors.NotBranchError:
318
return FailedSmartServerResponse(('nobranch', ))