~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
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
17
"""Basic server-side logic for dealing with requests."""
18
19
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
20
import tempfile
21
2402.1.2 by Andrew Bennetts
Deal with review comments.
22
from bzrlib import (
23
    bzrdir,
24
    errors,
25
    registry,
26
    revision,
27
    )
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
28
from bzrlib.bundle.serializer import write_bundle
29
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.
30
31
class SmartServerRequest(object):
2402.1.2 by Andrew Bennetts
Deal with review comments.
32
    """Base class for request handlers."""
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.
33
34
    def __init__(self, backing_transport):
2402.1.2 by Andrew Bennetts
Deal with review comments.
35
        """Constructor.
36
37
        :param backing_transport: the base transport to be used when performing
38
            this request.
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
        self._backing_transport = backing_transport
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
41
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)
42
    def _check_enabled(self):
43
        """Raises DisabledMethod if this method is disabled."""
44
        pass
45
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
46
    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)
47
        """Mandatory extension point for SmartServerRequest subclasses.
48
        
49
        Subclasses must implement this.
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
50
        
51
        This should return a SmartServerResponse if this command expects to
52
        receive no body.
53
        """
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
54
        raise NotImplementedError(self.do)
55
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)
56
    def execute(self, *args):
57
        """Public entry point to execute this request.
58
59
        It will return a SmartServerResponse if the command does not expect a
60
        body.
61
62
        :param *args: the arguments of the request.
63
        """
64
        self._check_enabled()
65
        return self.do(*args)
66
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
67
    def do_body(self, body_bytes):
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
68
        """Called if the client sends a body with the request.
69
        
70
        Must return a SmartServerResponse.
71
        """
72
        # TODO: if a client erroneously sends a request that shouldn't have a
73
        # body, what to do?  Probably SmartServerRequestHandler should catch
74
        # this NotImplementedError and translate it into a 'bad request' error
75
        # to send to the client.
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.
76
        raise NotImplementedError(self.do_body)
77
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
78
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
79
class SmartServerResponse(object):
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
80
    """A response to a client request.
81
    
82
    This base class should not be used. Instead use
83
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
84
    """
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
85
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
86
    def __init__(self, args, body=None, body_stream=None):
87
        """Constructor.
88
89
        :param args: tuple of response arguments.
90
        :param body: string of a response body.
91
        :param body_stream: iterable of bytestrings to be streamed to the
92
            client.
93
        """
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
94
        self.args = args
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
95
        if body is not None and body_stream is not None:
96
            raise errors.BzrError(
97
                "'body' and 'body_stream' are mutually exclusive.")
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
98
        self.body = body
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
99
        self.body_stream = body_stream
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
100
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
101
    def __eq__(self, other):
102
        if other is None:
103
            return False
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
104
        return (other.args == self.args and
105
                other.body == self.body and
106
                other.body_stream is self.body_stream)
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
107
108
    def __repr__(self):
2748.4.13 by Andrew Bennetts
Merge bzr.dev.
109
        return "<SmartServerResponse %r args=%r body=%r>" % (
110
            self.is_successful(), self.args, self.body)
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
111
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
112
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
113
class FailedSmartServerResponse(SmartServerResponse):
114
    """A SmartServerResponse for a request which failed."""
115
116
    def is_successful(self):
117
        """FailedSmartServerResponse are not successful."""
118
        return False
119
120
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
121
class SuccessfulSmartServerResponse(SmartServerResponse):
122
    """A SmartServerResponse for a successfully completed request."""
123
124
    def is_successful(self):
125
        """SuccessfulSmartServerResponse are successful."""
126
        return True
127
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
128
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
129
class SmartServerRequestHandler(object):
130
    """Protocol logic for smart server.
131
    
132
    This doesn't handle serialization at all, it just processes requests and
133
    creates responses.
134
    """
135
136
    # IMPORTANT FOR IMPLEMENTORS: It is important that SmartServerRequestHandler
137
    # not contain encoding or decoding logic to allow the wire protocol to vary
138
    # from the object protocol: we will want to tweak the wire protocol separate
139
    # from the object model, and ideally we will be able to do that without
140
    # having a SmartServerRequestHandler subclass for each wire protocol, rather
141
    # just a Protocol subclass.
142
143
    # TODO: Better way of representing the body for commands that take it,
144
    # and allow it to be streamed into the server.
145
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
146
    def __init__(self, backing_transport, commands):
147
        """Constructor.
148
149
        :param backing_transport: a Transport to handle requests for.
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
150
        :param commands: a registry mapping command names to SmartServerRequest
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
151
            subclasses. e.g. bzrlib.transport.smart.vfs.vfs_commands.
152
        """
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
153
        self._backing_transport = backing_transport
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
154
        self._commands = commands
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
155
        self._body_bytes = ''
156
        self.response = None
157
        self.finished_reading = False
158
        self._command = None
159
160
    def accept_body(self, bytes):
161
        """Accept body data."""
162
163
        # TODO: This should be overriden for each command that desired body data
164
        # to handle the right format of that data, i.e. plain bytes, a bundle,
165
        # etc.  The deserialisation into that format should be done in the
166
        # Protocol object.
167
168
        # default fallback is to accumulate bytes.
169
        self._body_bytes += bytes
170
        
171
    def end_of_body(self):
172
        """No more body data will be received."""
173
        self._run_handler_code(self._command.do_body, (self._body_bytes,), {})
174
        # cannot read after this.
175
        self.finished_reading = True
176
177
    def dispatch_command(self, cmd, args):
178
        """Deprecated compatibility method.""" # XXX XXX
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
179
        try:
180
            command = self._commands.get(cmd)
181
        except LookupError:
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
182
            raise errors.SmartProtocolError("bad request %r" % (cmd,))
183
        self._command = command(self._backing_transport)
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)
184
        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.
185
186
    def _run_handler_code(self, callable, args, kwargs):
187
        """Run some handler specific code 'callable'.
188
189
        If a result is returned, it is considered to be the commands response,
190
        and finished_reading is set true, and its assigned to self.response.
191
192
        Any exceptions caught are translated and a response object created
193
        from them.
194
        """
195
        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.
196
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
197
        if result is not None:
198
            self.response = result
199
            self.finished_reading = True
200
201
    def _call_converting_errors(self, callable, args, kwargs):
202
        """Call callable converting errors to Response objects."""
203
        # XXX: most of this error conversion is VFS-related, and thus ought to
204
        # be in SmartServerVFSRequestHandler somewhere.
205
        try:
206
            return callable(*args, **kwargs)
207
        except errors.NoSuchFile, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
208
            return FailedSmartServerResponse(('NoSuchFile', e.path))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
209
        except errors.FileExists, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
210
            return FailedSmartServerResponse(('FileExists', e.path))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
211
        except errors.DirectoryNotEmpty, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
212
            return FailedSmartServerResponse(('DirectoryNotEmpty', e.path))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
213
        except errors.ShortReadvError, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
214
            return FailedSmartServerResponse(('ShortReadvError',
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
215
                e.path, str(e.offset), str(e.length), str(e.actual)))
216
        except UnicodeError, e:
217
            # If it is a DecodeError, than most likely we are starting
218
            # with a plain string
219
            str_or_unicode = e.object
220
            if isinstance(str_or_unicode, unicode):
221
                # XXX: UTF-8 might have \x01 (our seperator byte) in it.  We
222
                # should escape it somehow.
223
                val = 'u:' + str_or_unicode.encode('utf-8')
224
            else:
225
                val = 's:' + str_or_unicode.encode('base64')
226
            # This handles UnicodeEncodeError or UnicodeDecodeError
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
227
            return FailedSmartServerResponse((e.__class__.__name__,
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
228
                    e.encoding, val, str(e.start), str(e.end), e.reason))
229
        except errors.TransportNotPossible, e:
230
            if e.msg == "readonly transport":
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
231
                return FailedSmartServerResponse(('ReadOnlyError', ))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
232
            else:
233
                raise
234
235
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
236
class HelloRequest(SmartServerRequest):
2432.2.6 by Andrew Bennetts
Improve HelloRequest's docstring.
237
    """Answer a version request with the highest protocol version this server
238
    supports.
239
    """
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
240
241
    def do(self):
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
242
        return SuccessfulSmartServerResponse(('ok', '2'))
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
243
244
245
class GetBundleRequest(SmartServerRequest):
2402.1.2 by Andrew Bennetts
Deal with review comments.
246
    """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.
247
248
    def do(self, path, revision_id):
249
        # open transport relative to our base
250
        t = self._backing_transport.clone(path)
251
        control, extra_path = bzrdir.BzrDir.open_containing_from_transport(t)
252
        repo = control.open_repository()
253
        tmpf = tempfile.TemporaryFile()
254
        base_revision = revision.NULL_REVISION
255
        write_bundle(repo, revision_id, base_revision, tmpf)
256
        tmpf.seek(0)
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
257
        return SuccessfulSmartServerResponse((), tmpf.read())
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
258
259
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.
260
class SmartServerIsReadonly(SmartServerRequest):
261
    # XXX: this request method belongs somewhere else.
262
263
    def do(self):
264
        if self._backing_transport.is_readonly():
265
            answer = 'yes'
266
        else:
267
            answer = 'no'
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
268
        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.
269
270
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
271
request_handlers = registry.Registry()
272
request_handlers.register_lazy(
273
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
274
request_handlers.register_lazy(
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
275
    'Branch.get_config_file', 'bzrlib.smart.branch', 'SmartServerBranchGetConfigFile')
276
request_handlers.register_lazy(
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
277
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
278
request_handlers.register_lazy(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
279
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
280
request_handlers.register_lazy(
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
281
    'Branch.revision_history', 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
282
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
283
    '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.
284
request_handlers.register_lazy(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
285
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
286
request_handlers.register_lazy(
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
287
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepository')
288
request_handlers.register_lazy(
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
289
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir', 'SmartServerRequestInitializeBzrDir')
290
request_handlers.register_lazy(
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
291
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBranch')
292
request_handlers.register_lazy(
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
293
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
294
request_handlers.register_lazy(
295
    'get', 'bzrlib.smart.vfs', 'GetRequest')
296
request_handlers.register_lazy(
297
    'get_bundle', 'bzrlib.smart.request', 'GetBundleRequest')
298
request_handlers.register_lazy(
299
    'has', 'bzrlib.smart.vfs', 'HasRequest')
300
request_handlers.register_lazy(
301
    'hello', 'bzrlib.smart.request', 'HelloRequest')
302
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
303
    'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest')
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
304
request_handlers.register_lazy(
305
    'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest')
306
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
307
    'mkdir', 'bzrlib.smart.vfs', 'MkdirRequest')
308
request_handlers.register_lazy(
309
    'move', 'bzrlib.smart.vfs', 'MoveRequest')
310
request_handlers.register_lazy(
311
    'put', 'bzrlib.smart.vfs', 'PutRequest')
312
request_handlers.register_lazy(
313
    'put_non_atomic', 'bzrlib.smart.vfs', 'PutNonAtomicRequest')
314
request_handlers.register_lazy(
315
    'readv', 'bzrlib.smart.vfs', 'ReadvRequest')
316
request_handlers.register_lazy(
317
    'rename', 'bzrlib.smart.vfs', 'RenameRequest')
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
318
request_handlers.register_lazy('Repository.gather_stats',
319
                               'bzrlib.smart.repository',
320
                               'SmartServerRepositoryGatherStats')
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
321
request_handlers.register_lazy(
2535.3.62 by Andrew Bennetts
Cosmetic changes.
322
    'Repository.stream_knit_data_for_revisions', 'bzrlib.smart.repository',
323
    'SmartServerRepositoryStreamKnitDataForRevisions')
2535.3.17 by Andrew Bennetts
[broken] Closer to a working Repository.fetch_revisions smart request.
324
request_handlers.register_lazy(
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
325
    'Repository.get_revision_graph', 'bzrlib.smart.repository', 'SmartServerRepositoryGetRevisionGraph')
326
request_handlers.register_lazy(
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
327
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
328
request_handlers.register_lazy(
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
329
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
330
request_handlers.register_lazy(
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
331
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
332
request_handlers.register_lazy(
333
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
334
request_handlers.register_lazy(
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
335
    'Repository.tarball', 'bzrlib.smart.repository',
336
    'SmartServerRepositoryTarball')
337
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
338
    'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest')
339
request_handlers.register_lazy(
340
    '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.
341
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.
342
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
343
request_handlers.register_lazy(
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
344
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')