~bzr-pqm/bzr/bzr.dev

2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
1
# Copyright (C) 2006 Canonical Ltd
2
#
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.
7
#
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.
12
#
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
16
17
"""Server-side bzrdir related request implmentations."""
18
19
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
20
from bzrlib import branch, errors, repository
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
21
from bzrlib.bzrdir import BzrDir, BzrDirFormat, BzrDirMetaFormat1
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
22
from bzrlib.smart.request import (
23
    FailedSmartServerResponse,
24
    SmartServerRequest,
25
    SuccessfulSmartServerResponse,
26
    )
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
27
28
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
29
class SmartServerRequestOpenBzrDir(SmartServerRequest):
30
31
    def do(self, path):
32
        from bzrlib.bzrdir import BzrDirFormat
33
        try:
2692.1.11 by Andrew Bennetts
Improve test coverage by making SmartTCPServer_for_testing by default create a server that does not serve the backing transport's root at its own root. This mirrors the way most HTTP smart servers are configured.
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
37
            # to.
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.
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
41
            answer = 'no'
42
        else:
2692.1.11 by Andrew Bennetts
Improve test coverage by making SmartTCPServer_for_testing by default create a server that does not serve the backing transport's root at its own root. This mirrors the way most HTTP smart servers are configured.
43
            default_format = BzrDirFormat.get_default_format()
44
            real_bzrdir = default_format.open(t, _found=True)
45
            try:
46
                real_bzrdir._format.probe_transport(t)
47
            except (errors.NotBranchError, errors.UnknownFormatError):
48
                answer = 'no'
49
            else:
50
                answer = 'yes'
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
51
        return SuccessfulSmartServerResponse((answer,))
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
52
53
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
54
class SmartServerRequestBzrDir(SmartServerRequest):
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
55
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
56
    def do(self, path, *args):
57
        """Open a BzrDir at path, and return self.do_bzrdir_request(*args)."""
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
58
        try:
59
            self._bzrdir = BzrDir.open_from_transport(
60
                self.transport_from_client_path(path))
61
        except errors.NotBranchError:
62
            return FailedSmartServerResponse(('nobranch', ))
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
63
        return self.do_bzrdir_request(*args)
64
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
65
    def _boolean_to_yes_no(self, a_boolean):
66
        if a_boolean:
67
            return 'yes'
68
        else:
69
            return 'no'
70
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
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
78
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
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)
85
        if len(relpath):
86
            segments = ['..'] * len(relpath.split('/'))
87
        else:
88
            segments = []
89
        return '/'.join(segments)
90
91
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
92
class SmartServerBzrDirRequestCloningMetaDir(SmartServerRequestBzrDir):
93
94
    def do_bzrdir_request(self, require_stacking):
95
        """Get the format that should be used when cloning from this dir."""
4070.7.4 by Andrew Bennetts
Deal with branch references better in BzrDir.cloning_metadir RPC (changes protocol).
96
        try:
97
            branch_ref = self._bzrdir.get_branch_reference()
98
        except errors.NotBranchError:
99
            branch_ref = None
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
100
        if require_stacking == "True":
101
            require_stacking = True
102
        else:
103
            require_stacking = False
104
        control_format = self._bzrdir.cloning_metadir(
105
            require_stacking=require_stacking)
106
        control_name = control_format.network_name()
4070.2.4 by Robert Collins
Review feedback.
107
        # XXX: There should be a method that tells us that the format does/does not
108
        # have subformats.
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
109
        if isinstance(control_format, BzrDirMetaFormat1):
4070.7.4 by Andrew Bennetts
Deal with branch references better in BzrDir.cloning_metadir RPC (changes protocol).
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
4084.2.2 by Robert Collins
Review feedback.
113
                branch_name = ('ref', branch_ref)
4070.7.4 by Andrew Bennetts
Deal with branch references better in BzrDir.cloning_metadir RPC (changes protocol).
114
            else:
4084.2.2 by Robert Collins
Review feedback.
115
                branch_name = ('branch',
116
                    control_format.get_branch_format().network_name())
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
117
            repository_name = control_format.repository_format.network_name()
118
        else:
119
            # Only MetaDir has delegated formats today.
4084.2.2 by Robert Collins
Review feedback.
120
            branch_name = ('branch', '')
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
121
            repository_name = ''
122
        return SuccessfulSmartServerResponse((control_name, repository_name,
123
            branch_name))
124
125
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
126
class SmartServerRequestCreateBranch(SmartServerRequestBzrDir):
127
128
    def do(self, path, network_name):
129
        """Create a branch in the bzr dir at path.
130
131
        This operates precisely like 'bzrdir.create_branch'.
132
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
136
        exists anyway).
137
138
        This is the initial version of this method introduced to the smart
139
        server for 1.13.
140
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)
144
        """
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,
155
            result.repository)
156
        # branch format, repo relpath, rich_root, tree_ref, external_lookup,
157
        # repo_network_name
158
        return SuccessfulSmartServerResponse(('ok', branch_format, repo_path,
159
            rich_root, tree_ref, external_lookup, repo_format))
160
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
161
162
class SmartServerRequestCreateRepository(SmartServerRequestBzrDir):
163
164
    def do(self, path, network_name, shared):
165
        """Create a repository in the bzr dir at path.
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
166
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
167
        This operates precisely like 'bzrdir.create_repository'.
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
168
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
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
172
        exists anyway).
173
174
        This is the initial version of this method introduced to the smart
175
        server for 1.13.
176
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
180
            parameter.
181
        :return: (ok, rich_root, tree_ref, external_lookup, network_name)
182
        """
183
        bzrdir = BzrDir.open_from_transport(
184
            self.transport_from_client_path(path))
185
        shared = shared == 'True'
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
186
        format = repository.network_format_registry.get(network_name)
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
187
        bzrdir.repository_format = format
188
        result = format.initialize(bzrdir, shared=shared)
189
        rich_root, tree_ref, external_lookup = self._format_to_capabilities(
190
            result._format)
191
        return SuccessfulSmartServerResponse(('ok', rich_root, tree_ref,
192
            external_lookup, result._format.network_name()))
193
194
195
class SmartServerRequestFindRepository(SmartServerRequestBzrDir):
196
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
197
    def _find(self, path):
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
198
        """try to find a repository from path upwards
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
199
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
200
        This operates precisely like 'bzrdir.find_repository'.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
201
4053.1.2 by Robert Collins
Actually make this branch work.
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
205
            name.
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
206
        :raises errors.NoRepositoryPresent: When there is no repository
207
            present.
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
208
        """
2692.1.6 by Andrew Bennetts
Fix some >80 columns violations.
209
        bzrdir = BzrDir.open_from_transport(
210
            self.transport_from_client_path(path))
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
211
        repository = bzrdir.find_repository()
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
212
        path = self._repo_relpath(bzrdir.root_transport, repository)
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
213
        rich_root, tree_ref, external_lookup = self._format_to_capabilities(
214
            repository._format)
4053.1.2 by Robert Collins
Actually make this branch work.
215
        network_name = repository._format.network_name()
216
        return path, rich_root, tree_ref, external_lookup, network_name
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
217
218
219
class SmartServerRequestFindRepositoryV1(SmartServerRequestFindRepository):
220
221
    def do(self, path):
222
        """try to find a repository from path upwards
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
223
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
224
        This operates precisely like 'bzrdir.find_repository'.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
225
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
226
        If a bzrdir is not present, an exception is propogated
227
        rather than 'no branch' because these are different conditions.
228
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.
232
233
        :return: norepository or ok, relpath.
234
        """
235
        try:
4053.1.2 by Robert Collins
Actually make this branch work.
236
            path, rich_root, tree_ref, external_lookup, name = self._find(path)
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
237
            return SuccessfulSmartServerResponse(('ok', path, rich_root, tree_ref))
238
        except errors.NoRepositoryPresent:
239
            return FailedSmartServerResponse(('norepository', ))
240
241
242
class SmartServerRequestFindRepositoryV2(SmartServerRequestFindRepository):
243
244
    def do(self, path):
245
        """try to find a repository from path upwards
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
246
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
247
        This operates precisely like 'bzrdir.find_repository'.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
248
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
249
        If a bzrdir is not present, an exception is propogated
250
        rather than 'no branch' because these are different conditions.
251
3221.3.3 by Robert Collins
* Hook up the new remote method ``RemoteBzrDir.find_repositoryV2`` so
252
        This is the second edition of this method introduced in bzr 1.3, which
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
253
        returns information about the supports_external_lookups format
254
        attribute too.
255
4053.1.1 by Robert Collins
New version of the BzrDir.find_repository verb supporting _network_name to support removing more _ensure_real calls.
256
        :return: norepository or ok, relpath, rich_root, tree_ref,
257
            external_lookup.
258
        """
259
        try:
4053.1.2 by Robert Collins
Actually make this branch work.
260
            path, rich_root, tree_ref, external_lookup, name = self._find(path)
4053.1.1 by Robert Collins
New version of the BzrDir.find_repository verb supporting _network_name to support removing more _ensure_real calls.
261
            return SuccessfulSmartServerResponse(
262
                ('ok', path, rich_root, tree_ref, external_lookup))
263
        except errors.NoRepositoryPresent:
264
            return FailedSmartServerResponse(('norepository', ))
265
266
267
class SmartServerRequestFindRepositoryV3(SmartServerRequestFindRepository):
268
269
    def do(self, path):
270
        """try to find a repository from path upwards
271
272
        This operates precisely like 'bzrdir.find_repository'.
273
274
        If a bzrdir is not present, an exception is propogated
275
        rather than 'no branch' because these are different conditions.
276
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.
279
280
        :return: norepository or ok, relpath, rich_root, tree_ref,
281
            external_lookup, network_name.
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
282
        """
283
        try:
4053.1.2 by Robert Collins
Actually make this branch work.
284
            path, rich_root, tree_ref, external_lookup, name = self._find(path)
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
285
            return SuccessfulSmartServerResponse(
4053.1.2 by Robert Collins
Actually make this branch work.
286
                ('ok', path, rich_root, tree_ref, external_lookup, name))
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
287
        except errors.NoRepositoryPresent:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
288
            return FailedSmartServerResponse(('norepository', ))
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
289
290
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
291
class SmartServerRequestInitializeBzrDir(SmartServerRequest):
292
293
    def do(self, path):
294
        """Initialize a bzrdir at path.
295
296
        The default format of the server is used.
297
        :return: SmartServerResponse(('ok', ))
298
        """
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
299
        target_transport = self.transport_from_client_path(path)
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
300
        BzrDirFormat.get_default_format().initialize_on_transport(target_transport)
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
301
        return SuccessfulSmartServerResponse(('ok', ))
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
302
303
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
304
class SmartServerRequestOpenBranch(SmartServerRequestBzrDir):
305
306
    def do_bzrdir_request(self):
307
        """open a branch at path and return the branch reference or branch."""
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
308
        try:
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
309
            reference_url = self._bzrdir.get_branch_reference()
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
310
            if reference_url is None:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
311
                return SuccessfulSmartServerResponse(('ok', ''))
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
312
            else:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
313
                return SuccessfulSmartServerResponse(('ok', reference_url))
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
314
        except errors.NotBranchError:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
315
            return FailedSmartServerResponse(('nobranch', ))
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
316
317
318
class SmartServerRequestOpenBranchV2(SmartServerRequestBzrDir):
319
320
    def do_bzrdir_request(self):
321
        """open a branch at path and return the reference or format."""
322
        try:
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))
327
            else:
328
                return SuccessfulSmartServerResponse(('ref', reference_url))
329
        except errors.NotBranchError:
330
            return FailedSmartServerResponse(('nobranch', ))