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)."""
59
self._bzrdir = BzrDir.open_from_transport(
60
self.transport_from_client_path(path))
61
except errors.NotBranchError:
62
return FailedSmartServerResponse(('nobranch', ))
63
return self.do_bzrdir_request(*args)
65
def _boolean_to_yes_no(self, a_boolean):
71
def _format_to_capabilities(self, repo_format):
72
rich_root = self._boolean_to_yes_no(repo_format.rich_root_data)
73
tree_ref = self._boolean_to_yes_no(
74
repo_format.supports_tree_reference)
75
external_lookup = self._boolean_to_yes_no(
76
repo_format.supports_external_lookups)
77
return rich_root, tree_ref, external_lookup
79
def _repo_relpath(self, current_transport, repository):
80
"""Get the relative path for repository from current_transport."""
81
# the relpath of the bzrdir in the found repository gives us the
82
# path segments to pop-out.
83
relpath = repository.bzrdir.root_transport.relpath(
84
current_transport.base)
86
segments = ['..'] * len(relpath.split('/'))
89
return '/'.join(segments)
92
class SmartServerBzrDirRequestCloningMetaDir(SmartServerRequestBzrDir):
94
def do_bzrdir_request(self, require_stacking):
95
"""Get the format that should be used when cloning from this dir."""
97
branch_ref = self._bzrdir.get_branch_reference()
98
except errors.NotBranchError:
100
if require_stacking == "True":
101
require_stacking = True
103
require_stacking = False
104
control_format = self._bzrdir.cloning_metadir(
105
require_stacking=require_stacking)
106
control_name = control_format.network_name()
107
# XXX: There should be a method that tells us that the format does/does not
109
if isinstance(control_format, BzrDirMetaFormat1):
110
if branch_ref is not None:
111
# If there's a branch reference, the client will have to resolve
112
# the branch reference to figure out the cloning metadir
113
branch_name = ('ref', branch_ref)
115
branch_name = ('branch',
116
control_format.get_branch_format().network_name())
117
repository_name = control_format.repository_format.network_name()
119
# Only MetaDir has delegated formats today.
120
branch_name = ('branch', '')
122
return SuccessfulSmartServerResponse((control_name, repository_name,
126
class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
128
def do(self, path, network_name):
129
"""Create a branch in the bzr dir at path.
131
This operates precisely like 'bzrdir.create_branch'.
133
If a bzrdir is not present, an exception is propogated
134
rather than 'no branch' because these are different conditions (and
135
this method should only be called after establishing that a bzr dir
138
This is the initial version of this method introduced to the smart
141
:param path: The path to the bzrdir.
142
:param network_name: The network name of the branch type to create.
143
:return: (ok, network_name)
145
bzrdir = BzrDir.open_from_transport(
146
self.transport_from_client_path(path))
147
format = branch.network_format_registry.get(network_name)
148
bzrdir.branch_format = format
149
result = format.initialize(bzrdir)
150
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
151
result.repository._format)
152
branch_format = result._format.network_name()
153
repo_format = result.repository._format.network_name()
154
repo_path = self._repo_relpath(bzrdir.root_transport,
156
# branch format, repo relpath, rich_root, tree_ref, external_lookup,
158
return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
159
rich_root, tree_ref, external_lookup, repo_format))
162
class SmartServerRequestCreateRepository(SmartServerRequestBzrDir):
164
def do(self, path, network_name, shared):
165
"""Create a repository in the bzr dir at path.
167
This operates precisely like 'bzrdir.create_repository'.
169
If a bzrdir is not present, an exception is propogated
170
rather than 'no branch' because these are different conditions (and
171
this method should only be called after establishing that a bzr dir
174
This is the initial version of this method introduced to the smart
177
:param path: The path to the bzrdir.
178
:param network_name: The network name of the repository type to create.
179
:param shared: The value to pass create_repository for the shared
181
:return: (ok, rich_root, tree_ref, external_lookup, network_name)
183
bzrdir = BzrDir.open_from_transport(
184
self.transport_from_client_path(path))
185
shared = shared == 'True'
186
format = repository.network_format_registry.get(network_name)
187
bzrdir.repository_format = format
188
result = format.initialize(bzrdir, shared=shared)
189
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
191
return SuccessfulSmartServerResponse(('ok', rich_root, tree_ref,
192
external_lookup, result._format.network_name()))
195
class SmartServerRequestFindRepository(SmartServerRequestBzrDir):
197
def _find(self, path):
198
"""try to find a repository from path upwards
200
This operates precisely like 'bzrdir.find_repository'.
202
:return: (relpath, rich_root, tree_ref, external_lookup, network_name).
203
All are strings, relpath is a / prefixed path, the next three are
204
either 'yes' or 'no', and the last is a repository format network
206
:raises errors.NoRepositoryPresent: When there is no repository
209
bzrdir = BzrDir.open_from_transport(
210
self.transport_from_client_path(path))
211
repository = bzrdir.find_repository()
212
path = self._repo_relpath(bzrdir.root_transport, repository)
213
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
215
network_name = repository._format.network_name()
216
return path, rich_root, tree_ref, external_lookup, network_name
219
class SmartServerRequestFindRepositoryV1(SmartServerRequestFindRepository):
222
"""try to find a repository from path upwards
224
This operates precisely like 'bzrdir.find_repository'.
226
If a bzrdir is not present, an exception is propogated
227
rather than 'no branch' because these are different conditions.
229
This is the initial version of this method introduced with the smart
230
server. Modern clients will try the V2 method that adds support for the
231
supports_external_lookups attribute.
233
:return: norepository or ok, relpath.
236
path, rich_root, tree_ref, external_lookup, name = self._find(path)
237
return SuccessfulSmartServerResponse(('ok', path, rich_root, tree_ref))
238
except errors.NoRepositoryPresent:
239
return FailedSmartServerResponse(('norepository', ))
242
class SmartServerRequestFindRepositoryV2(SmartServerRequestFindRepository):
245
"""try to find a repository from path upwards
247
This operates precisely like 'bzrdir.find_repository'.
249
If a bzrdir is not present, an exception is propogated
250
rather than 'no branch' because these are different conditions.
252
This is the second edition of this method introduced in bzr 1.3, which
253
returns information about the supports_external_lookups format
256
:return: norepository or ok, relpath, rich_root, tree_ref,
260
path, rich_root, tree_ref, external_lookup, name = self._find(path)
261
return SuccessfulSmartServerResponse(
262
('ok', path, rich_root, tree_ref, external_lookup))
263
except errors.NoRepositoryPresent:
264
return FailedSmartServerResponse(('norepository', ))
267
class SmartServerRequestFindRepositoryV3(SmartServerRequestFindRepository):
270
"""try to find a repository from path upwards
272
This operates precisely like 'bzrdir.find_repository'.
274
If a bzrdir is not present, an exception is propogated
275
rather than 'no branch' because these are different conditions.
277
This is the third edition of this method introduced in bzr 1.13, which
278
returns information about the network name of the repository format.
280
:return: norepository or ok, relpath, rich_root, tree_ref,
281
external_lookup, network_name.
284
path, rich_root, tree_ref, external_lookup, name = self._find(path)
285
return SuccessfulSmartServerResponse(
286
('ok', path, rich_root, tree_ref, external_lookup, name))
287
except errors.NoRepositoryPresent:
288
return FailedSmartServerResponse(('norepository', ))
291
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
294
"""Initialize a bzrdir at path.
296
The default format of the server is used.
297
:return: SmartServerResponse(('ok', ))
299
target_transport = self.transport_from_client_path(path)
300
BzrDirFormat.get_default_format().initialize_on_transport(target_transport)
301
return SuccessfulSmartServerResponse(('ok', ))
304
class SmartServerRequestOpenBranch(SmartServerRequestBzrDir):
306
def do_bzrdir_request(self):
307
"""open a branch at path and return the branch reference or branch."""
309
reference_url = self._bzrdir.get_branch_reference()
310
if reference_url is None:
311
return SuccessfulSmartServerResponse(('ok', ''))
313
return SuccessfulSmartServerResponse(('ok', reference_url))
314
except errors.NotBranchError:
315
return FailedSmartServerResponse(('nobranch', ))
318
class SmartServerRequestOpenBranchV2(SmartServerRequestBzrDir):
320
def do_bzrdir_request(self):
321
"""open a branch at path and return the reference or format."""
323
reference_url = self._bzrdir.get_branch_reference()
324
if reference_url is None:
325
format = self._bzrdir.open_branch()._format.network_name()
326
return SuccessfulSmartServerResponse(('branch', format))
328
return SuccessfulSmartServerResponse(('ref', reference_url))
329
except errors.NotBranchError:
330
return FailedSmartServerResponse(('nobranch', ))