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
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 _boolean_to_yes_no(self, a_boolean):
62
def _format_to_capabilities(self, repo_format):
63
rich_root = self._boolean_to_yes_no(repo_format.rich_root_data)
64
tree_ref = self._boolean_to_yes_no(
65
repo_format.supports_tree_reference)
66
external_lookup = self._boolean_to_yes_no(
67
repo_format.supports_external_lookups)
68
return rich_root, tree_ref, external_lookup
70
def _repo_relpath(self, current_transport, repository):
71
"""Get the relative path for repository from current_transport."""
72
# the relpath of the bzrdir in the found repository gives us the
73
# path segments to pop-out.
74
relpath = repository.bzrdir.root_transport.relpath(
75
current_transport.base)
77
segments = ['..'] * len(relpath.split('/'))
80
return '/'.join(segments)
83
class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
85
def do(self, path, network_name):
86
"""Create a branch in the bzr dir at path.
88
This operates precisely like 'bzrdir.create_branch'.
90
If a bzrdir is not present, an exception is propogated
91
rather than 'no branch' because these are different conditions (and
92
this method should only be called after establishing that a bzr dir
95
This is the initial version of this method introduced to the smart
98
:param path: The path to the bzrdir.
99
:param network_name: The network name of the branch type to create.
100
:return: (ok, network_name)
102
bzrdir = BzrDir.open_from_transport(
103
self.transport_from_client_path(path))
104
format = branch.network_format_registry.get(network_name)
105
bzrdir.branch_format = format
106
result = format.initialize(bzrdir)
107
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
108
result.repository._format)
109
branch_format = result._format.network_name()
110
repo_format = result.repository._format.network_name()
111
repo_path = self._repo_relpath(bzrdir.root_transport,
113
# branch format, repo relpath, rich_root, tree_ref, external_lookup,
115
return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
116
rich_root, tree_ref, external_lookup, repo_format))
119
class SmartServerRequestCreateRepository(SmartServerRequestBzrDir):
121
def do(self, path, network_name, shared):
122
"""Create a repository in the bzr dir at path.
124
This operates precisely like 'bzrdir.create_repository'.
126
If a bzrdir is not present, an exception is propogated
127
rather than 'no branch' because these are different conditions (and
128
this method should only be called after establishing that a bzr dir
131
This is the initial version of this method introduced to the smart
134
:param path: The path to the bzrdir.
135
:param network_name: The network name of the repository type to create.
136
:param shared: The value to pass create_repository for the shared
138
:return: (ok, rich_root, tree_ref, external_lookup, network_name)
140
bzrdir = BzrDir.open_from_transport(
141
self.transport_from_client_path(path))
142
shared = shared == 'True'
143
format = repository.network_format_registry.get(network_name)
144
bzrdir.repository_format = format
145
result = format.initialize(bzrdir, shared=shared)
146
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
148
return SuccessfulSmartServerResponse(('ok', rich_root, tree_ref,
149
external_lookup, result._format.network_name()))
152
class SmartServerRequestFindRepository(SmartServerRequestBzrDir):
154
def _find(self, path):
155
"""try to find a repository from path upwards
157
This operates precisely like 'bzrdir.find_repository'.
159
:return: (relpath, rich_root, tree_ref, external_lookup, network_name).
160
All are strings, relpath is a / prefixed path, the next three are
161
either 'yes' or 'no', and the last is a repository format network
163
:raises errors.NoRepositoryPresent: When there is no repository
166
bzrdir = BzrDir.open_from_transport(
167
self.transport_from_client_path(path))
168
repository = bzrdir.find_repository()
169
path = self._repo_relpath(bzrdir.root_transport, repository)
170
rich_root, tree_ref, external_lookup = self._format_to_capabilities(
172
network_name = repository._format.network_name()
173
return path, rich_root, tree_ref, external_lookup, network_name
176
class SmartServerRequestFindRepositoryV1(SmartServerRequestFindRepository):
179
"""try to find a repository from path upwards
181
This operates precisely like 'bzrdir.find_repository'.
183
If a bzrdir is not present, an exception is propogated
184
rather than 'no branch' because these are different conditions.
186
This is the initial version of this method introduced with the smart
187
server. Modern clients will try the V2 method that adds support for the
188
supports_external_lookups attribute.
190
:return: norepository or ok, relpath.
193
path, rich_root, tree_ref, external_lookup, name = self._find(path)
194
return SuccessfulSmartServerResponse(('ok', path, rich_root, tree_ref))
195
except errors.NoRepositoryPresent:
196
return FailedSmartServerResponse(('norepository', ))
199
class SmartServerRequestFindRepositoryV2(SmartServerRequestFindRepository):
202
"""try to find a repository from path upwards
204
This operates precisely like 'bzrdir.find_repository'.
206
If a bzrdir is not present, an exception is propogated
207
rather than 'no branch' because these are different conditions.
209
This is the second edition of this method introduced in bzr 1.3, which
210
returns information about the supports_external_lookups format
213
:return: norepository or ok, relpath, rich_root, tree_ref,
217
path, rich_root, tree_ref, external_lookup, name = self._find(path)
218
return SuccessfulSmartServerResponse(
219
('ok', path, rich_root, tree_ref, external_lookup))
220
except errors.NoRepositoryPresent:
221
return FailedSmartServerResponse(('norepository', ))
224
class SmartServerRequestFindRepositoryV3(SmartServerRequestFindRepository):
227
"""try to find a repository from path upwards
229
This operates precisely like 'bzrdir.find_repository'.
231
If a bzrdir is not present, an exception is propogated
232
rather than 'no branch' because these are different conditions.
234
This is the third edition of this method introduced in bzr 1.13, which
235
returns information about the network name of the repository format.
237
:return: norepository or ok, relpath, rich_root, tree_ref,
238
external_lookup, network_name.
241
path, rich_root, tree_ref, external_lookup, name = self._find(path)
242
return SuccessfulSmartServerResponse(
243
('ok', path, rich_root, tree_ref, external_lookup, name))
244
except errors.NoRepositoryPresent:
245
return FailedSmartServerResponse(('norepository', ))
248
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
251
"""Initialize a bzrdir at path.
253
The default format of the server is used.
254
:return: SmartServerResponse(('ok', ))
256
target_transport = self.transport_from_client_path(path)
257
BzrDirFormat.get_default_format().initialize_on_transport(target_transport)
258
return SuccessfulSmartServerResponse(('ok', ))
261
class SmartServerRequestOpenBranch(SmartServerRequest):
264
"""try to open a branch at path and return ok/nobranch.
266
If a bzrdir is not present, an exception is propogated
267
rather than 'no branch' because these are different conditions.
269
bzrdir = BzrDir.open_from_transport(
270
self.transport_from_client_path(path))
272
reference_url = bzrdir.get_branch_reference()
273
if reference_url is None:
274
return SuccessfulSmartServerResponse(('ok', ''))
276
return SuccessfulSmartServerResponse(('ok', reference_url))
277
except errors.NotBranchError:
278
return FailedSmartServerResponse(('nobranch', ))