~bzr-pqm/bzr/bzr.dev

2018.5.157 by Andrew Bennetts
Remove unnecessary trivial divergences from bzr.dev.
1
# Copyright (C) 2006, 2007 Canonical Ltd
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
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
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
17
"""Basic server-side logic for dealing with requests.
18
19
**XXX**:
20
21
The class names are a little confusing: the protocol will instantiate a
22
SmartServerRequestHandler, whose dispatch_command method creates an instance of
23
a SmartServerRequest subclass.
24
25
The request_handlers registry tracks SmartServerRequest classes (rather than
26
SmartServerRequestHandler).
27
"""
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
28
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
29
import tempfile
30
2402.1.2 by Andrew Bennetts
Deal with review comments.
31
from bzrlib import (
32
    bzrdir,
33
    errors,
34
    registry,
35
    revision,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
36
    urlutils,
2402.1.2 by Andrew Bennetts
Deal with review comments.
37
    )
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
38
from bzrlib.bundle.serializer import write_bundle
39
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
40
41
class SmartServerRequest(object):
2692.1.10 by Andrew Bennetts
More docstring polish
42
    """Base class for request handlers.
43
    
44
    To define a new request, subclass this class and override the `do` method
45
    (and if appropriate, `do_body` as well).  Request implementors should take
46
    care to call `translate_client_path` and `transport_from_client_path` as
47
    appropriate when dealing with paths received from the client.
48
    """
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
49
    # XXX: rename this class to BaseSmartServerRequestHandler ?  A request
50
    # *handler* is a different concept to the request.
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
51
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
52
    def __init__(self, backing_transport, root_client_path='/'):
2402.1.2 by Andrew Bennetts
Deal with review comments.
53
        """Constructor.
54
55
        :param backing_transport: the base transport to be used when performing
56
            this request.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
57
        :param root_client_path: the client path that maps to the root of
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
58
            backing_transport.  This is used to interpret relpaths received
59
            from the client.  Clients will not be able to refer to paths above
2692.1.16 by Andrew Bennetts
Improve comments.
60
            this root.  If root_client_path is None, then no translation will
61
            be performed on client paths.  Default is '/'.
2402.1.2 by Andrew Bennetts
Deal with review comments.
62
        """
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
63
        self._backing_transport = backing_transport
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
64
        if root_client_path is not None:
65
            if not root_client_path.startswith('/'):
66
                root_client_path = '/' + root_client_path
67
            if not root_client_path.endswith('/'):
68
                root_client_path += '/'
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
69
        self._root_client_path = root_client_path
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
70
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
71
    def _check_enabled(self):
72
        """Raises DisabledMethod if this method is disabled."""
73
        pass
74
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
75
    def do(self, *args):
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
76
        """Mandatory extension point for SmartServerRequest subclasses.
77
        
78
        Subclasses must implement this.
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
79
        
80
        This should return a SmartServerResponse if this command expects to
81
        receive no body.
82
        """
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
83
        raise NotImplementedError(self.do)
84
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
85
    def execute(self, *args):
86
        """Public entry point to execute this request.
87
88
        It will return a SmartServerResponse if the command does not expect a
89
        body.
90
91
        :param *args: the arguments of the request.
92
        """
93
        self._check_enabled()
94
        return self.do(*args)
95
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
96
    def do_body(self, body_bytes):
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
97
        """Called if the client sends a body with the request.
3184.1.10 by Robert Collins
Change the smart server verb for Repository.stream_revisions_chunked to use SearchResults as the request mechanism for downloads.
98
99
        The do() method is still called, and must have returned None.
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
100
        
101
        Must return a SmartServerResponse.
102
        """
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
103
        raise NotImplementedError(self.do_body)
104
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
105
    def do_chunk(self, chunk_bytes):
106
        """Called with each body chunk if the request has a streamed body.
107
108
        The do() method is still called, and must have returned None.
109
        """
110
        raise NotImplementedError(self.do_chunk)
111
112
    def do_end(self):
113
        """Called when the end of the request has been received."""
114
        pass
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
115
    
116
    def translate_client_path(self, client_path):
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
117
        """Translate a path received from a network client into a local
118
        relpath.
119
120
        All paths received from the client *must* be translated.
121
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
122
        :param client_path: the path from the client.
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
123
        :returns: a relpath that may be used with self._backing_transport
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
124
            (unlike the untranslated client_path, which must not be used with
125
            the backing transport).
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
126
        """
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
127
        if self._root_client_path is None:
128
            # no translation necessary!
129
            return client_path
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
130
        if not client_path.startswith('/'):
131
            client_path = '/' + client_path
132
        if client_path.startswith(self._root_client_path):
133
            path = client_path[len(self._root_client_path):]
134
            relpath = urlutils.joinpath('/', path)
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
135
            if not relpath.startswith('/'):
136
                raise ValueError(relpath)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
137
            return '.' + relpath
138
        else:
139
            raise errors.PathNotChild(client_path, self._root_client_path)
140
141
    def transport_from_client_path(self, client_path):
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
142
        """Get a backing transport corresponding to the location referred to by
143
        a network client.
144
145
        :seealso: translate_client_path
146
        :returns: a transport cloned from self._backing_transport
147
        """
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
148
        relpath = self.translate_client_path(client_path)
2692.1.16 by Andrew Bennetts
Improve comments.
149
        return self._backing_transport.clone(relpath)
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
150
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
151
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
152
class SmartServerResponse(object):
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
153
    """A response to a client request.
154
    
155
    This base class should not be used. Instead use
156
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
157
    """
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
158
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
159
    def __init__(self, args, body=None, body_stream=None):
160
        """Constructor.
161
162
        :param args: tuple of response arguments.
163
        :param body: string of a response body.
164
        :param body_stream: iterable of bytestrings to be streamed to the
165
            client.
166
        """
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
167
        self.args = args
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
168
        if body is not None and body_stream is not None:
169
            raise errors.BzrError(
170
                "'body' and 'body_stream' are mutually exclusive.")
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
171
        self.body = body
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
172
        self.body_stream = body_stream
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
173
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
174
    def __eq__(self, other):
175
        if other is None:
176
            return False
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
177
        return (other.args == self.args and
178
                other.body == self.body and
179
                other.body_stream is self.body_stream)
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
180
181
    def __repr__(self):
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
182
        status = {True: 'OK', False: 'ERR'}[self.is_successful()]
183
        return "<SmartServerResponse status=%s args=%r body=%r>" % (status,
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
184
            self.args, self.body)
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
185
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
186
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
187
class FailedSmartServerResponse(SmartServerResponse):
188
    """A SmartServerResponse for a request which failed."""
189
190
    def is_successful(self):
191
        """FailedSmartServerResponse are not successful."""
192
        return False
193
194
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
195
class SuccessfulSmartServerResponse(SmartServerResponse):
196
    """A SmartServerResponse for a successfully completed request."""
197
198
    def is_successful(self):
199
        """SuccessfulSmartServerResponse are successful."""
200
        return True
201
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
202
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
203
class SmartServerRequestHandler(object):
204
    """Protocol logic for smart server.
205
    
206
    This doesn't handle serialization at all, it just processes requests and
207
    creates responses.
208
    """
209
210
    # IMPORTANT FOR IMPLEMENTORS: It is important that SmartServerRequestHandler
211
    # not contain encoding or decoding logic to allow the wire protocol to vary
212
    # from the object protocol: we will want to tweak the wire protocol separate
213
    # from the object model, and ideally we will be able to do that without
214
    # having a SmartServerRequestHandler subclass for each wire protocol, rather
215
    # just a Protocol subclass.
216
217
    # TODO: Better way of representing the body for commands that take it,
218
    # and allow it to be streamed into the server.
219
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
220
    def __init__(self, backing_transport, commands, root_client_path):
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
221
        """Constructor.
222
223
        :param backing_transport: a Transport to handle requests for.
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
224
        :param commands: a registry mapping command names to SmartServerRequest
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
225
            subclasses. e.g. bzrlib.transport.smart.vfs.vfs_commands.
226
        """
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
227
        self._backing_transport = backing_transport
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
228
        self._root_client_path = root_client_path
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
229
        self._commands = commands
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
230
        self._body_bytes = ''
231
        self.response = None
232
        self.finished_reading = False
233
        self._command = None
234
235
    def accept_body(self, bytes):
236
        """Accept body data."""
237
238
        # TODO: This should be overriden for each command that desired body data
239
        # to handle the right format of that data, i.e. plain bytes, a bundle,
240
        # etc.  The deserialisation into that format should be done in the
241
        # Protocol object.
242
243
        # default fallback is to accumulate bytes.
244
        self._body_bytes += bytes
245
        
246
    def end_of_body(self):
247
        """No more body data will be received."""
248
        self._run_handler_code(self._command.do_body, (self._body_bytes,), {})
249
        # cannot read after this.
250
        self.finished_reading = True
251
252
    def dispatch_command(self, cmd, args):
253
        """Deprecated compatibility method.""" # XXX XXX
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
254
        try:
255
            command = self._commands.get(cmd)
256
        except LookupError:
3245.4.29 by Andrew Bennetts
Add/tidy some comments, remove dud test_errors_are_logged test, add explicit UnknownSmartMethod to v3.
257
            raise errors.UnknownSmartMethod(cmd)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
258
        self._command = command(self._backing_transport, self._root_client_path)
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
259
        self._run_handler_code(self._command.execute, args, {})
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
260
261
    def _run_handler_code(self, callable, args, kwargs):
262
        """Run some handler specific code 'callable'.
263
264
        If a result is returned, it is considered to be the commands response,
265
        and finished_reading is set true, and its assigned to self.response.
266
267
        Any exceptions caught are translated and a response object created
268
        from them.
269
        """
270
        result = self._call_converting_errors(callable, args, kwargs)
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
271
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
272
        if result is not None:
273
            self.response = result
274
            self.finished_reading = True
275
276
    def _call_converting_errors(self, callable, args, kwargs):
277
        """Call callable converting errors to Response objects."""
278
        # XXX: most of this error conversion is VFS-related, and thus ought to
279
        # be in SmartServerVFSRequestHandler somewhere.
280
        try:
281
            return callable(*args, **kwargs)
282
        except errors.NoSuchFile, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
283
            return FailedSmartServerResponse(('NoSuchFile', e.path))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
284
        except errors.FileExists, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
285
            return FailedSmartServerResponse(('FileExists', e.path))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
286
        except errors.DirectoryNotEmpty, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
287
            return FailedSmartServerResponse(('DirectoryNotEmpty', e.path))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
288
        except errors.ShortReadvError, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
289
            return FailedSmartServerResponse(('ShortReadvError',
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
290
                e.path, str(e.offset), str(e.length), str(e.actual)))
291
        except UnicodeError, e:
292
            # If it is a DecodeError, than most likely we are starting
293
            # with a plain string
294
            str_or_unicode = e.object
295
            if isinstance(str_or_unicode, unicode):
296
                # XXX: UTF-8 might have \x01 (our seperator byte) in it.  We
297
                # should escape it somehow.
298
                val = 'u:' + str_or_unicode.encode('utf-8')
299
            else:
300
                val = 's:' + str_or_unicode.encode('base64')
301
            # This handles UnicodeEncodeError or UnicodeDecodeError
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
302
            return FailedSmartServerResponse((e.__class__.__name__,
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
303
                    e.encoding, val, str(e.start), str(e.end), e.reason))
304
        except errors.TransportNotPossible, e:
305
            if e.msg == "readonly transport":
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
306
                return FailedSmartServerResponse(('ReadOnlyError', ))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
307
            else:
308
                raise
309
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
310
    def headers_received(self, headers):
3245.4.33 by Andrew Bennetts
Remove unused no_body_received method on SmartServerRequestHandler.
311
        # Just a no-op at the moment.
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
312
        pass
313
314
    def args_received(self, args):
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
315
        cmd = args[0]
316
        args = args[1:]
317
        try:
318
            command = self._commands.get(cmd)
319
        except LookupError:
3245.4.48 by Andrew Bennetts
raise UnknownSmartMethod from dispatch_command.
320
            raise errors.UnknownSmartMethod(cmd)
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
321
        self._command = command(self._backing_transport)
322
        self._run_handler_code(self._command.execute, args, {})
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
323
324
    def prefixed_body_received(self, body_bytes):
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
325
        """No more body data will be received."""
326
        self._run_handler_code(self._command.do_body, (body_bytes,), {})
327
        # cannot read after this.
328
        self.finished_reading = True
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
329
330
    def body_chunk_received(self, chunk_bytes):
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
331
        self._run_handler_code(self._command.do_chunk, (chunk_bytes,), {})
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
332
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
333
    def end_received(self):
334
        self._run_handler_code(self._command.do_end, (), {})
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
335
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
336
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
337
class HelloRequest(SmartServerRequest):
2432.2.6 by Andrew Bennetts
Improve HelloRequest's docstring.
338
    """Answer a version request with the highest protocol version this server
339
    supports.
340
    """
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
341
342
    def do(self):
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
343
        return SuccessfulSmartServerResponse(('ok', '2'))
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
344
345
346
class GetBundleRequest(SmartServerRequest):
2402.1.2 by Andrew Bennetts
Deal with review comments.
347
    """Get a bundle of from the null revision to the specified revision."""
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
348
349
    def do(self, path, revision_id):
350
        # open transport relative to our base
2692.1.7 by Andrew Bennetts
Translate path in GetBundleRequest too.
351
        t = self.transport_from_client_path(path)
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
352
        control, extra_path = bzrdir.BzrDir.open_containing_from_transport(t)
353
        repo = control.open_repository()
354
        tmpf = tempfile.TemporaryFile()
355
        base_revision = revision.NULL_REVISION
356
        write_bundle(repo, revision_id, base_revision, tmpf)
357
        tmpf.seek(0)
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
358
        return SuccessfulSmartServerResponse((), tmpf.read())
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
359
360
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
361
class SmartServerIsReadonly(SmartServerRequest):
362
    # XXX: this request method belongs somewhere else.
363
364
    def do(self):
365
        if self._backing_transport.is_readonly():
366
            answer = 'yes'
367
        else:
368
            answer = 'no'
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
369
        return SuccessfulSmartServerResponse((answer,))
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
370
371
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
372
request_handlers = registry.Registry()
373
request_handlers.register_lazy(
374
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
375
request_handlers.register_lazy(
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
376
    'Branch.get_config_file', 'bzrlib.smart.branch', 'SmartServerBranchGetConfigFile')
377
request_handlers.register_lazy(
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
378
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
379
request_handlers.register_lazy(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
380
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
381
request_handlers.register_lazy(
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
382
    'Branch.revision_history', 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
383
request_handlers.register_lazy(
2018.5.77 by Wouter van Heyst
Fix typo in request_handlers registration of Branch.set_last_revision, and test that registration
384
    'Branch.set_last_revision', 'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
385
request_handlers.register_lazy(
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
386
    'Branch.set_last_revision_info', 'bzrlib.smart.branch',
387
    'SmartServerBranchRequestSetLastRevisionInfo')
388
request_handlers.register_lazy(
3441.5.25 by Andrew Bennetts
Rename Branch.set_last_revision_descendant verb to Branch.set_last_revision_ex. It's a cop out, but at least it's not misleading.
389
    'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
390
    'SmartServerBranchRequestSetLastRevisionEx')
3441.5.6 by Andrew Bennetts
Greatly simplify RemoteBranch.update_revisions. Still needs more tests.
391
request_handlers.register_lazy(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
392
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
393
request_handlers.register_lazy(
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
394
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV1')
395
request_handlers.register_lazy(
396
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV2')
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
397
request_handlers.register_lazy(
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
398
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir', 'SmartServerRequestInitializeBzrDir')
399
request_handlers.register_lazy(
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
400
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBranch')
401
request_handlers.register_lazy(
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
402
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
403
request_handlers.register_lazy(
404
    'get', 'bzrlib.smart.vfs', 'GetRequest')
405
request_handlers.register_lazy(
406
    'get_bundle', 'bzrlib.smart.request', 'GetBundleRequest')
407
request_handlers.register_lazy(
408
    'has', 'bzrlib.smart.vfs', 'HasRequest')
409
request_handlers.register_lazy(
410
    'hello', 'bzrlib.smart.request', 'HelloRequest')
411
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
412
    'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest')
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
413
request_handlers.register_lazy(
414
    'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest')
415
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
416
    'mkdir', 'bzrlib.smart.vfs', 'MkdirRequest')
417
request_handlers.register_lazy(
418
    'move', 'bzrlib.smart.vfs', 'MoveRequest')
419
request_handlers.register_lazy(
420
    'put', 'bzrlib.smart.vfs', 'PutRequest')
421
request_handlers.register_lazy(
422
    'put_non_atomic', 'bzrlib.smart.vfs', 'PutNonAtomicRequest')
423
request_handlers.register_lazy(
424
    'readv', 'bzrlib.smart.vfs', 'ReadvRequest')
425
request_handlers.register_lazy(
426
    'rename', 'bzrlib.smart.vfs', 'RenameRequest')
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
427
request_handlers.register_lazy('Repository.gather_stats',
428
                               'bzrlib.smart.repository',
429
                               'SmartServerRepositoryGatherStats')
3172.5.6 by Robert Collins
Create new smart server verb Repository.get_parent_map.
430
request_handlers.register_lazy('Repository.get_parent_map',
431
                               'bzrlib.smart.repository',
432
                               'SmartServerRepositoryGetParentMap')
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
433
request_handlers.register_lazy(
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
434
    'Repository.get_revision_graph', 'bzrlib.smart.repository', 'SmartServerRepositoryGetRevisionGraph')
435
request_handlers.register_lazy(
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
436
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
437
request_handlers.register_lazy(
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
438
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
439
request_handlers.register_lazy(
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
440
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
441
request_handlers.register_lazy(
442
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
443
request_handlers.register_lazy(
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
444
    'Repository.tarball', 'bzrlib.smart.repository',
445
    'SmartServerRepositoryTarball')
446
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
447
    'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest')
448
request_handlers.register_lazy(
449
    'stat', 'bzrlib.smart.vfs', 'StatRequest')
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
450
request_handlers.register_lazy(
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
451
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
452
request_handlers.register_lazy(
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
453
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')