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."""
93
if require_stacking == "True":
94
require_stacking = True
96
require_stacking = False
97
control_format = self._bzrdir.cloning_metadir(
98
require_stacking=require_stacking)
99
control_name = control_format.network_name()
100
# XXX: Should be a method that tells us this, or delegated to the
101
# format, or something.
102
if isinstance(control_format, BzrDirMetaFormat1):
103
branch_name = control_format.get_branch_format().network_name()
104
repository_name = control_format.repository_format.network_name()
106
# Only MetaDir has delegated formats today.
109
return SuccessfulSmartServerResponse((control_name, repository_name,
113
class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
115
def do(self, path, network_name):
116
"""Create a branch in the bzr dir at path.
118
This operates precisely like 'bzrdir.create_branch'.
120
If a bzrdir is not present, an exception is propogated
121
rather than 'no branch' because these are different conditions (and
122
this method should only be called after establishing that a bzr dir
125
This is the initial version of this method introduced to the smart
128
:param path: The path to the bzrdir.
129
:param network_name: The network name of the branch type to create.
130
:return: (ok, network_name)
132
bzrdir = BzrDir.open_from_transport(
133
self.transport_from_client_path(path))
134
format = branch.network_format_registry.get(network_name)
135
bzrdir.branch_format = format
136
result = format.initialize(bzrdir)
137
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
138
result.repository._format)
139
branch_format = result._format.network_name()
140
repo_format = result.repository._format.network_name()
141
repo_path = self._repo_relpath(bzrdir.root_transport,
143
# branch format, repo relpath, rich_root, tree_ref, external_lookup,
145
return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
146
rich_root, tree_ref, external_lookup, repo_format))
149
class SmartServerRequestCreateRepository(SmartServerRequestBzrDir):
151
def do(self, path, network_name, shared):
152
"""Create a repository in the bzr dir at path.
154
This operates precisely like 'bzrdir.create_repository'.
156
If a bzrdir is not present, an exception is propogated
157
rather than 'no branch' because these are different conditions (and
158
this method should only be called after establishing that a bzr dir
161
This is the initial version of this method introduced to the smart
164
:param path: The path to the bzrdir.
165
:param network_name: The network name of the repository type to create.
166
:param shared: The value to pass create_repository for the shared
168
:return: (ok, rich_root, tree_ref, external_lookup, network_name)
170
bzrdir = BzrDir.open_from_transport(
171
self.transport_from_client_path(path))
172
shared = shared == 'True'
173
format = repository.network_format_registry.get(network_name)
174
bzrdir.repository_format = format
175
result = format.initialize(bzrdir, shared=shared)
176
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
178
return SuccessfulSmartServerResponse(('ok', rich_root, tree_ref,
179
external_lookup, result._format.network_name()))
182
class SmartServerRequestFindRepository(SmartServerRequestBzrDir):
184
def _find(self, path):
185
"""try to find a repository from path upwards
187
This operates precisely like 'bzrdir.find_repository'.
189
:return: (relpath, rich_root, tree_ref, external_lookup, network_name).
190
All are strings, relpath is a / prefixed path, the next three are
191
either 'yes' or 'no', and the last is a repository format network
193
:raises errors.NoRepositoryPresent: When there is no repository
196
bzrdir = BzrDir.open_from_transport(
197
self.transport_from_client_path(path))
198
repository = bzrdir.find_repository()
199
path = self._repo_relpath(bzrdir.root_transport, repository)
200
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
202
network_name = repository._format.network_name()
203
return path, rich_root, tree_ref, external_lookup, network_name
206
class SmartServerRequestFindRepositoryV1(SmartServerRequestFindRepository):
209
"""try to find a repository from path upwards
211
This operates precisely like 'bzrdir.find_repository'.
213
If a bzrdir is not present, an exception is propogated
214
rather than 'no branch' because these are different conditions.
216
This is the initial version of this method introduced with the smart
217
server. Modern clients will try the V2 method that adds support for the
218
supports_external_lookups attribute.
220
:return: norepository or ok, relpath.
223
path, rich_root, tree_ref, external_lookup, name = self._find(path)
224
return SuccessfulSmartServerResponse(('ok', path, rich_root, tree_ref))
225
except errors.NoRepositoryPresent:
226
return FailedSmartServerResponse(('norepository', ))
229
class SmartServerRequestFindRepositoryV2(SmartServerRequestFindRepository):
232
"""try to find a repository from path upwards
234
This operates precisely like 'bzrdir.find_repository'.
236
If a bzrdir is not present, an exception is propogated
237
rather than 'no branch' because these are different conditions.
239
This is the second edition of this method introduced in bzr 1.3, which
240
returns information about the supports_external_lookups format
243
:return: norepository or ok, relpath, rich_root, tree_ref,
247
path, rich_root, tree_ref, external_lookup, name = self._find(path)
248
return SuccessfulSmartServerResponse(
249
('ok', path, rich_root, tree_ref, external_lookup))
250
except errors.NoRepositoryPresent:
251
return FailedSmartServerResponse(('norepository', ))
254
class SmartServerRequestFindRepositoryV3(SmartServerRequestFindRepository):
257
"""try to find a repository from path upwards
259
This operates precisely like 'bzrdir.find_repository'.
261
If a bzrdir is not present, an exception is propogated
262
rather than 'no branch' because these are different conditions.
264
This is the third edition of this method introduced in bzr 1.13, which
265
returns information about the network name of the repository format.
267
:return: norepository or ok, relpath, rich_root, tree_ref,
268
external_lookup, network_name.
271
path, rich_root, tree_ref, external_lookup, name = self._find(path)
272
return SuccessfulSmartServerResponse(
273
('ok', path, rich_root, tree_ref, external_lookup, name))
274
except errors.NoRepositoryPresent:
275
return FailedSmartServerResponse(('norepository', ))
278
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
281
"""Initialize a bzrdir at path.
283
The default format of the server is used.
284
:return: SmartServerResponse(('ok', ))
286
target_transport = self.transport_from_client_path(path)
287
BzrDirFormat.get_default_format().initialize_on_transport(target_transport)
288
return SuccessfulSmartServerResponse(('ok', ))
291
class SmartServerRequestOpenBranch(SmartServerRequest):
294
"""try to open a branch at path and return ok/nobranch.
296
If a bzrdir is not present, an exception is propogated
297
rather than 'no branch' because these are different conditions.
299
bzrdir = BzrDir.open_from_transport(
300
self.transport_from_client_path(path))
302
reference_url = bzrdir.get_branch_reference()
303
if reference_url is None:
304
return SuccessfulSmartServerResponse(('ok', ''))
306
return SuccessfulSmartServerResponse(('ok', reference_url))
307
except errors.NotBranchError:
308
return FailedSmartServerResponse(('nobranch', ))