~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/request.py

  • Committer: Patch Queue Manager
  • Date: 2016-04-21 04:10:52 UTC
  • mfrom: (6616.1.1 fix-en-user-guide)
  • Revision ID: pqm@pqm.ubuntu.com-20160421041052-clcye7ns1qcl2n7w
(richard-wilbur) Ensure build of English use guide always uses English text
 even when user's locale specifies a different language. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
"""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).
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Infrastructure for server-side request handlers.
 
18
 
 
19
Interesting module attributes:
 
20
    * The request_handlers registry maps verb names to SmartServerRequest
 
21
      classes.
 
22
    * The jail_info threading.local() object is used to prevent accidental
 
23
      opening of BzrDirs outside of the backing transport, or any other
 
24
      transports placed in jail_info.transports.  The jail_info is reset on
 
25
      every call into a request handler (which can happen an arbitrary number
 
26
      of times during a request).
27
27
"""
28
28
 
29
 
import tempfile
 
29
from __future__ import absolute_import
 
30
 
 
31
# XXX: The class names are a little confusing: the protocol will instantiate a
 
32
# SmartServerRequestHandler, whose dispatch_command method creates an instance
 
33
# of a SmartServerRequest subclass.
 
34
 
 
35
 
 
36
import threading
30
37
 
31
38
from bzrlib import (
32
 
    bzrdir,
 
39
    debug,
33
40
    errors,
 
41
    osutils,
34
42
    registry,
35
43
    revision,
 
44
    trace,
36
45
    urlutils,
37
46
    )
38
 
from bzrlib.bundle.serializer import write_bundle
 
47
from bzrlib.lazy_import import lazy_import
 
48
lazy_import(globals(), """
 
49
from bzrlib import bzrdir
 
50
from bzrlib.bundle import serializer
 
51
 
 
52
import tempfile
 
53
import thread
 
54
""")
 
55
 
 
56
 
 
57
jail_info = threading.local()
 
58
jail_info.transports = None
 
59
 
 
60
 
 
61
def _install_hook():
 
62
    bzrdir.BzrDir.hooks.install_named_hook(
 
63
        'pre_open', _pre_open_hook, 'checking server jail')
 
64
 
 
65
 
 
66
def _pre_open_hook(transport):
 
67
    allowed_transports = getattr(jail_info, 'transports', None)
 
68
    if allowed_transports is None:
 
69
        return
 
70
    abspath = transport.base
 
71
    for allowed_transport in allowed_transports:
 
72
        try:
 
73
            allowed_transport.relpath(abspath)
 
74
        except errors.PathNotChild:
 
75
            continue
 
76
        else:
 
77
            return
 
78
    raise errors.JailBreak(abspath)
 
79
 
 
80
 
 
81
_install_hook()
39
82
 
40
83
 
41
84
class SmartServerRequest(object):
42
85
    """Base class for request handlers.
43
 
    
 
86
 
44
87
    To define a new request, subclass this class and override the `do` method
45
88
    (and if appropriate, `do_body` as well).  Request implementors should take
46
89
    care to call `translate_client_path` and `transport_from_client_path` as
49
92
    # XXX: rename this class to BaseSmartServerRequestHandler ?  A request
50
93
    # *handler* is a different concept to the request.
51
94
 
52
 
    def __init__(self, backing_transport, root_client_path='/'):
 
95
    def __init__(self, backing_transport, root_client_path='/', jail_root=None):
53
96
        """Constructor.
54
97
 
55
98
        :param backing_transport: the base transport to be used when performing
59
102
            from the client.  Clients will not be able to refer to paths above
60
103
            this root.  If root_client_path is None, then no translation will
61
104
            be performed on client paths.  Default is '/'.
 
105
        :param jail_root: if specified, the root of the BzrDir.open jail to use
 
106
            instead of backing_transport.
62
107
        """
63
108
        self._backing_transport = backing_transport
 
109
        if jail_root is None:
 
110
            jail_root = backing_transport
 
111
        self._jail_root = jail_root
64
112
        if root_client_path is not None:
65
113
            if not root_client_path.startswith('/'):
66
114
                root_client_path = '/' + root_client_path
67
115
            if not root_client_path.endswith('/'):
68
116
                root_client_path += '/'
69
117
        self._root_client_path = root_client_path
 
118
        self._body_chunks = []
70
119
 
71
120
    def _check_enabled(self):
72
121
        """Raises DisabledMethod if this method is disabled."""
74
123
 
75
124
    def do(self, *args):
76
125
        """Mandatory extension point for SmartServerRequest subclasses.
77
 
        
 
126
 
78
127
        Subclasses must implement this.
79
 
        
 
128
 
80
129
        This should return a SmartServerResponse if this command expects to
81
130
        receive no body.
82
131
        """
88
137
        It will return a SmartServerResponse if the command does not expect a
89
138
        body.
90
139
 
91
 
        :param *args: the arguments of the request.
 
140
        :param args: the arguments of the request.
92
141
        """
93
142
        self._check_enabled()
94
143
        return self.do(*args)
97
146
        """Called if the client sends a body with the request.
98
147
 
99
148
        The do() method is still called, and must have returned None.
100
 
        
 
149
 
101
150
        Must return a SmartServerResponse.
102
151
        """
103
 
        raise NotImplementedError(self.do_body)
 
152
        if body_bytes != '':
 
153
            raise errors.SmartProtocolError('Request does not expect a body')
104
154
 
105
155
    def do_chunk(self, chunk_bytes):
106
156
        """Called with each body chunk if the request has a streamed body.
107
157
 
108
158
        The do() method is still called, and must have returned None.
109
159
        """
110
 
        raise NotImplementedError(self.do_chunk)
 
160
        self._body_chunks.append(chunk_bytes)
111
161
 
112
162
    def do_end(self):
113
163
        """Called when the end of the request has been received."""
114
 
        pass
115
 
    
 
164
        body_bytes = ''.join(self._body_chunks)
 
165
        self._body_chunks = None
 
166
        return self.do_body(body_bytes)
 
167
 
 
168
    def setup_jail(self):
 
169
        jail_info.transports = [self._jail_root]
 
170
 
 
171
    def teardown_jail(self):
 
172
        jail_info.transports = None
 
173
 
116
174
    def translate_client_path(self, client_path):
117
175
        """Translate a path received from a network client into a local
118
176
        relpath.
129
187
            return client_path
130
188
        if not client_path.startswith('/'):
131
189
            client_path = '/' + client_path
 
190
        if client_path + '/' == self._root_client_path:
 
191
            return '.'
132
192
        if client_path.startswith(self._root_client_path):
133
193
            path = client_path[len(self._root_client_path):]
134
194
            relpath = urlutils.joinpath('/', path)
135
195
            if not relpath.startswith('/'):
136
196
                raise ValueError(relpath)
137
 
            return '.' + relpath
 
197
            return urlutils.escape('.' + relpath)
138
198
        else:
139
199
            raise errors.PathNotChild(client_path, self._root_client_path)
140
200
 
151
211
 
152
212
class SmartServerResponse(object):
153
213
    """A response to a client request.
154
 
    
 
214
 
155
215
    This base class should not be used. Instead use
156
216
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
157
217
    """
179
239
                other.body_stream is self.body_stream)
180
240
 
181
241
    def __repr__(self):
182
 
        status = {True: 'OK', False: 'ERR'}[self.is_successful()]
183
 
        return "<SmartServerResponse status=%s args=%r body=%r>" % (status,
 
242
        return "<%s args=%r body=%r>" % (self.__class__.__name__,
184
243
            self.args, self.body)
185
244
 
186
245
 
202
261
 
203
262
class SmartServerRequestHandler(object):
204
263
    """Protocol logic for smart server.
205
 
    
 
264
 
206
265
    This doesn't handle serialization at all, it just processes requests and
207
266
    creates responses.
208
267
    """
217
276
    # TODO: Better way of representing the body for commands that take it,
218
277
    # and allow it to be streamed into the server.
219
278
 
220
 
    def __init__(self, backing_transport, commands, root_client_path):
 
279
    def __init__(self, backing_transport, commands, root_client_path,
 
280
        jail_root=None):
221
281
        """Constructor.
222
282
 
223
283
        :param backing_transport: a Transport to handle requests for.
227
287
        self._backing_transport = backing_transport
228
288
        self._root_client_path = root_client_path
229
289
        self._commands = commands
230
 
        self._body_bytes = ''
 
290
        if jail_root is None:
 
291
            jail_root = backing_transport
 
292
        self._jail_root = jail_root
231
293
        self.response = None
232
294
        self.finished_reading = False
233
295
        self._command = None
 
296
        if 'hpss' in debug.debug_flags:
 
297
            self._request_start_time = osutils.timer_func()
 
298
            self._thread_id = thread.get_ident()
 
299
 
 
300
    def _trace(self, action, message, extra_bytes=None, include_time=False):
 
301
        # It is a bit of a shame that this functionality overlaps with that of 
 
302
        # ProtocolThreeRequester._trace. However, there is enough difference
 
303
        # that just putting it in a helper doesn't help a lot. And some state
 
304
        # is taken from the instance.
 
305
        if include_time:
 
306
            t = '%5.3fs ' % (osutils.timer_func() - self._request_start_time)
 
307
        else:
 
308
            t = ''
 
309
        if extra_bytes is None:
 
310
            extra = ''
 
311
        else:
 
312
            extra = ' ' + repr(extra_bytes[:40])
 
313
            if len(extra) > 33:
 
314
                extra = extra[:29] + extra[-1] + '...'
 
315
        trace.mutter('%12s: [%s] %s%s%s'
 
316
                     % (action, self._thread_id, t, message, extra))
234
317
 
235
318
    def accept_body(self, bytes):
236
319
        """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
 
        
 
320
        if self._command is None:
 
321
            # no active command object, so ignore the event.
 
322
            return
 
323
        self._run_handler_code(self._command.do_chunk, (bytes,), {})
 
324
        if 'hpss' in debug.debug_flags:
 
325
            self._trace('accept body',
 
326
                        '%d bytes' % (len(bytes),), bytes)
 
327
 
246
328
    def end_of_body(self):
247
329
        """No more body data will be received."""
248
 
        self._run_handler_code(self._command.do_body, (self._body_bytes,), {})
 
330
        self._run_handler_code(self._command.do_end, (), {})
249
331
        # cannot read after this.
250
332
        self.finished_reading = True
251
 
 
252
 
    def dispatch_command(self, cmd, args):
253
 
        """Deprecated compatibility method.""" # XXX XXX
254
 
        try:
255
 
            command = self._commands.get(cmd)
256
 
        except LookupError:
257
 
            raise errors.UnknownSmartMethod(cmd)
258
 
        self._command = command(self._backing_transport, self._root_client_path)
259
 
        self._run_handler_code(self._command.execute, args, {})
 
333
        if 'hpss' in debug.debug_flags:
 
334
            self._trace('end of body', '', include_time=True)
260
335
 
261
336
    def _run_handler_code(self, callable, args, kwargs):
262
337
        """Run some handler specific code 'callable'.
278
353
        # XXX: most of this error conversion is VFS-related, and thus ought to
279
354
        # be in SmartServerVFSRequestHandler somewhere.
280
355
        try:
281
 
            return callable(*args, **kwargs)
282
 
        except errors.NoSuchFile, e:
283
 
            return FailedSmartServerResponse(('NoSuchFile', e.path))
284
 
        except errors.FileExists, e:
285
 
            return FailedSmartServerResponse(('FileExists', e.path))
286
 
        except errors.DirectoryNotEmpty, e:
287
 
            return FailedSmartServerResponse(('DirectoryNotEmpty', e.path))
288
 
        except errors.ShortReadvError, e:
289
 
            return FailedSmartServerResponse(('ShortReadvError',
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
302
 
            return FailedSmartServerResponse((e.__class__.__name__,
303
 
                    e.encoding, val, str(e.start), str(e.end), e.reason))
304
 
        except errors.TransportNotPossible, e:
305
 
            if e.msg == "readonly transport":
306
 
                return FailedSmartServerResponse(('ReadOnlyError', ))
307
 
            else:
308
 
                raise
 
356
            self._command.setup_jail()
 
357
            try:
 
358
                return callable(*args, **kwargs)
 
359
            finally:
 
360
                self._command.teardown_jail()
 
361
        except (KeyboardInterrupt, SystemExit):
 
362
            raise
 
363
        except Exception, err:
 
364
            err_struct = _translate_error(err)
 
365
            return FailedSmartServerResponse(err_struct)
309
366
 
310
367
    def headers_received(self, headers):
311
368
        # Just a no-op at the moment.
312
 
        pass
 
369
        if 'hpss' in debug.debug_flags:
 
370
            self._trace('headers', repr(headers))
313
371
 
314
372
    def args_received(self, args):
315
373
        cmd = args[0]
317
375
        try:
318
376
            command = self._commands.get(cmd)
319
377
        except LookupError:
 
378
            if 'hpss' in debug.debug_flags:
 
379
                self._trace('hpss unknown request', 
 
380
                            cmd, repr(args)[1:-1])
320
381
            raise errors.UnknownSmartMethod(cmd)
321
 
        self._command = command(self._backing_transport)
 
382
        if 'hpss' in debug.debug_flags:
 
383
            from bzrlib.smart import vfs
 
384
            if issubclass(command, vfs.VfsRequest):
 
385
                action = 'hpss vfs req'
 
386
            else:
 
387
                action = 'hpss request'
 
388
            self._trace(action, 
 
389
                        '%s %s' % (cmd, repr(args)[1:-1]))
 
390
        self._command = command(
 
391
            self._backing_transport, self._root_client_path, self._jail_root)
322
392
        self._run_handler_code(self._command.execute, args, {})
323
393
 
324
 
    def prefixed_body_received(self, body_bytes):
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
329
 
 
330
 
    def body_chunk_received(self, chunk_bytes):
331
 
        self._run_handler_code(self._command.do_chunk, (chunk_bytes,), {})
332
 
 
333
394
    def end_received(self):
 
395
        if self._command is None:
 
396
            # no active command object, so ignore the event.
 
397
            return
334
398
        self._run_handler_code(self._command.do_end, (), {})
 
399
        if 'hpss' in debug.debug_flags:
 
400
            self._trace('end', '', include_time=True)
 
401
 
 
402
    def post_body_error_received(self, error_args):
 
403
        # Just a no-op at the moment.
 
404
        pass
 
405
 
 
406
 
 
407
def _translate_error(err):
 
408
    if isinstance(err, errors.NoSuchFile):
 
409
        return ('NoSuchFile', err.path)
 
410
    elif isinstance(err, errors.FileExists):
 
411
        return ('FileExists', err.path)
 
412
    elif isinstance(err, errors.DirectoryNotEmpty):
 
413
        return ('DirectoryNotEmpty', err.path)
 
414
    elif isinstance(err, errors.IncompatibleRepositories):
 
415
        return ('IncompatibleRepositories', str(err.source), str(err.target),
 
416
            str(err.details))
 
417
    elif isinstance(err, errors.ShortReadvError):
 
418
        return ('ShortReadvError', err.path, str(err.offset), str(err.length),
 
419
                str(err.actual))
 
420
    elif isinstance(err, errors.RevisionNotPresent):
 
421
        return ('RevisionNotPresent', err.revision_id, err.file_id)
 
422
    elif isinstance(err, errors.UnstackableRepositoryFormat):
 
423
        return (('UnstackableRepositoryFormat', str(err.format), err.url))
 
424
    elif isinstance(err, errors.UnstackableBranchFormat):
 
425
        return ('UnstackableBranchFormat', str(err.format), err.url)
 
426
    elif isinstance(err, errors.NotStacked):
 
427
        return ('NotStacked',)
 
428
    elif isinstance(err, errors.BzrCheckError):
 
429
        return ('BzrCheckError', err.msg)
 
430
    elif isinstance(err, UnicodeError):
 
431
        # If it is a DecodeError, than most likely we are starting
 
432
        # with a plain string
 
433
        str_or_unicode = err.object
 
434
        if isinstance(str_or_unicode, unicode):
 
435
            # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
 
436
            # byte) in it, so this encoding could cause broken responses.
 
437
            # Newer clients use protocol v3, so will be fine.
 
438
            val = 'u:' + str_or_unicode.encode('utf-8')
 
439
        else:
 
440
            val = 's:' + str_or_unicode.encode('base64')
 
441
        # This handles UnicodeEncodeError or UnicodeDecodeError
 
442
        return (err.__class__.__name__, err.encoding, val, str(err.start),
 
443
                str(err.end), err.reason)
 
444
    elif isinstance(err, errors.TransportNotPossible):
 
445
        if err.msg == "readonly transport":
 
446
            return ('ReadOnlyError', )
 
447
    elif isinstance(err, errors.ReadError):
 
448
        # cannot read the file
 
449
        return ('ReadError', err.path)
 
450
    elif isinstance(err, errors.PermissionDenied):
 
451
        return ('PermissionDenied', err.path, err.extra)
 
452
    elif isinstance(err, errors.TokenMismatch):
 
453
        return ('TokenMismatch', err.given_token, err.lock_token)
 
454
    elif isinstance(err, errors.LockContention):
 
455
        return ('LockContention',)
 
456
    elif isinstance(err, MemoryError):
 
457
        # GZ 2011-02-24: Copy bzrlib.trace -Dmem_dump functionality here?
 
458
        return ('MemoryError',)
 
459
    # Unserialisable error.  Log it, and return a generic error
 
460
    trace.log_exception_quietly()
 
461
    return ('error', trace._qualified_exception_name(err.__class__, True),
 
462
        str(err))
335
463
 
336
464
 
337
465
class HelloRequest(SmartServerRequest):
353
481
        repo = control.open_repository()
354
482
        tmpf = tempfile.TemporaryFile()
355
483
        base_revision = revision.NULL_REVISION
356
 
        write_bundle(repo, revision_id, base_revision, tmpf)
 
484
        serializer.write_bundle(repo, revision_id, base_revision, tmpf)
357
485
        tmpf.seek(0)
358
486
        return SuccessfulSmartServerResponse((), tmpf.read())
359
487
 
369
497
        return SuccessfulSmartServerResponse((answer,))
370
498
 
371
499
 
 
500
# In the 'info' attribute, we store whether this request is 'safe' to retry if
 
501
# we get a disconnect while reading the response. It can have the values:
 
502
#   read    This is purely a read request, so retrying it is perfectly ok.
 
503
#   idem    An idempotent write request. Something like 'put' where if you put
 
504
#           the same bytes twice you end up with the same final bytes.
 
505
#   semi    This is a request that isn't strictly idempotent, but doesn't
 
506
#           result in corruption if it is retried. This is for things like
 
507
#           'lock' and 'unlock'. If you call lock, it updates the disk
 
508
#           structure. If you fail to read the response, you won't be able to
 
509
#           use the lock, because you don't have the lock token. Calling lock
 
510
#           again will fail, because the lock is already taken. However, we
 
511
#           can't tell if the server received our request or not. If it didn't,
 
512
#           then retrying the request is fine, as it will actually do what we
 
513
#           want. If it did, we will interrupt the current operation, but we
 
514
#           are no worse off than interrupting the current operation because of
 
515
#           a ConnectionReset.
 
516
#   semivfs Similar to semi, but specific to a Virtual FileSystem request.
 
517
#   stream  This is a request that takes a stream that cannot be restarted if
 
518
#           consumed. This request is 'safe' in that if we determine the
 
519
#           connection is closed before we consume the stream, we can try
 
520
#           again.
 
521
#   mutate  State is updated in a way that replaying that request results in a
 
522
#           different state. For example 'append' writes more bytes to a given
 
523
#           file. If append succeeds, it moves the file pointer.
372
524
request_handlers = registry.Registry()
373
525
request_handlers.register_lazy(
374
 
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
375
 
request_handlers.register_lazy(
376
 
    'Branch.get_config_file', 'bzrlib.smart.branch', 'SmartServerBranchGetConfigFile')
377
 
request_handlers.register_lazy(
378
 
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
379
 
request_handlers.register_lazy(
380
 
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
381
 
request_handlers.register_lazy(
382
 
    'Branch.revision_history', 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
383
 
request_handlers.register_lazy(
384
 
    'Branch.set_last_revision', 'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
 
526
    'append', 'bzrlib.smart.vfs', 'AppendRequest', info='mutate')
 
527
request_handlers.register_lazy(
 
528
    'Branch.break_lock', 'bzrlib.smart.branch',
 
529
    'SmartServerBranchBreakLock', info='idem')
 
530
request_handlers.register_lazy(
 
531
    'Branch.get_config_file', 'bzrlib.smart.branch',
 
532
    'SmartServerBranchGetConfigFile', info='read')
 
533
request_handlers.register_lazy(
 
534
    'Branch.get_parent', 'bzrlib.smart.branch', 'SmartServerBranchGetParent',
 
535
    info='read')
 
536
request_handlers.register_lazy(
 
537
    'Branch.put_config_file', 'bzrlib.smart.branch',
 
538
    'SmartServerBranchPutConfigFile', info='idem')
 
539
request_handlers.register_lazy(
 
540
    'Branch.get_tags_bytes', 'bzrlib.smart.branch',
 
541
    'SmartServerBranchGetTagsBytes', info='read')
 
542
request_handlers.register_lazy(
 
543
    'Branch.set_tags_bytes', 'bzrlib.smart.branch',
 
544
    'SmartServerBranchSetTagsBytes', info='idem')
 
545
request_handlers.register_lazy(
 
546
    'Branch.heads_to_fetch', 'bzrlib.smart.branch',
 
547
    'SmartServerBranchHeadsToFetch', info='read')
 
548
request_handlers.register_lazy(
 
549
    'Branch.get_stacked_on_url', 'bzrlib.smart.branch',
 
550
    'SmartServerBranchRequestGetStackedOnURL', info='read')
 
551
request_handlers.register_lazy(
 
552
    'Branch.get_physical_lock_status', 'bzrlib.smart.branch',
 
553
    'SmartServerBranchRequestGetPhysicalLockStatus', info='read')
 
554
request_handlers.register_lazy(
 
555
    'Branch.last_revision_info', 'bzrlib.smart.branch',
 
556
    'SmartServerBranchRequestLastRevisionInfo', info='read')
 
557
request_handlers.register_lazy(
 
558
    'Branch.lock_write', 'bzrlib.smart.branch',
 
559
    'SmartServerBranchRequestLockWrite', info='semi')
 
560
request_handlers.register_lazy(
 
561
    'Branch.revision_history', 'bzrlib.smart.branch',
 
562
    'SmartServerRequestRevisionHistory', info='read')
 
563
request_handlers.register_lazy(
 
564
    'Branch.set_config_option', 'bzrlib.smart.branch',
 
565
    'SmartServerBranchRequestSetConfigOption', info='idem')
 
566
request_handlers.register_lazy(
 
567
    'Branch.set_config_option_dict', 'bzrlib.smart.branch',
 
568
    'SmartServerBranchRequestSetConfigOptionDict', info='idem')
 
569
request_handlers.register_lazy(
 
570
    'Branch.set_last_revision', 'bzrlib.smart.branch',
 
571
    'SmartServerBranchRequestSetLastRevision', info='idem')
385
572
request_handlers.register_lazy(
386
573
    'Branch.set_last_revision_info', 'bzrlib.smart.branch',
387
 
    'SmartServerBranchRequestSetLastRevisionInfo')
 
574
    'SmartServerBranchRequestSetLastRevisionInfo', info='idem')
388
575
request_handlers.register_lazy(
389
576
    'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
390
 
    'SmartServerBranchRequestSetLastRevisionEx')
391
 
request_handlers.register_lazy(
392
 
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
393
 
request_handlers.register_lazy(
394
 
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV1')
395
 
request_handlers.register_lazy(
396
 
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV2')
397
 
request_handlers.register_lazy(
398
 
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir', 'SmartServerRequestInitializeBzrDir')
399
 
request_handlers.register_lazy(
400
 
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBranch')
401
 
request_handlers.register_lazy(
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(
412
 
    'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest')
413
 
request_handlers.register_lazy(
414
 
    'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest')
415
 
request_handlers.register_lazy(
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')
427
 
request_handlers.register_lazy('Repository.gather_stats',
428
 
                               'bzrlib.smart.repository',
429
 
                               'SmartServerRepositoryGatherStats')
430
 
request_handlers.register_lazy('Repository.get_parent_map',
431
 
                               'bzrlib.smart.repository',
432
 
                               'SmartServerRepositoryGetParentMap')
433
 
request_handlers.register_lazy(
434
 
    'Repository.get_revision_graph', 'bzrlib.smart.repository', 'SmartServerRepositoryGetRevisionGraph')
435
 
request_handlers.register_lazy(
436
 
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
437
 
request_handlers.register_lazy(
438
 
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
439
 
request_handlers.register_lazy(
440
 
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
441
 
request_handlers.register_lazy(
442
 
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
 
577
    'SmartServerBranchRequestSetLastRevisionEx', info='idem')
 
578
request_handlers.register_lazy(
 
579
    'Branch.set_parent_location', 'bzrlib.smart.branch',
 
580
    'SmartServerBranchRequestSetParentLocation', info='idem')
 
581
request_handlers.register_lazy(
 
582
    'Branch.unlock', 'bzrlib.smart.branch',
 
583
    'SmartServerBranchRequestUnlock', info='semi')
 
584
request_handlers.register_lazy(
 
585
    'Branch.revision_id_to_revno', 'bzrlib.smart.branch',
 
586
    'SmartServerBranchRequestRevisionIdToRevno', info='read')
 
587
request_handlers.register_lazy(
 
588
    'BzrDir.checkout_metadir', 'bzrlib.smart.bzrdir',
 
589
    'SmartServerBzrDirRequestCheckoutMetaDir', info='read')
 
590
request_handlers.register_lazy(
 
591
    'BzrDir.cloning_metadir', 'bzrlib.smart.bzrdir',
 
592
    'SmartServerBzrDirRequestCloningMetaDir', info='read')
 
593
request_handlers.register_lazy(
 
594
    'BzrDir.create_branch', 'bzrlib.smart.bzrdir',
 
595
    'SmartServerRequestCreateBranch', info='semi')
 
596
request_handlers.register_lazy(
 
597
    'BzrDir.create_repository', 'bzrlib.smart.bzrdir',
 
598
    'SmartServerRequestCreateRepository', info='semi')
 
599
request_handlers.register_lazy(
 
600
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir',
 
601
    'SmartServerRequestFindRepositoryV1', info='read')
 
602
request_handlers.register_lazy(
 
603
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir',
 
604
    'SmartServerRequestFindRepositoryV2', info='read')
 
605
request_handlers.register_lazy(
 
606
    'BzrDir.find_repositoryV3', 'bzrlib.smart.bzrdir',
 
607
    'SmartServerRequestFindRepositoryV3', info='read')
 
608
request_handlers.register_lazy(
 
609
    'BzrDir.get_branches', 'bzrlib.smart.bzrdir',
 
610
    'SmartServerBzrDirRequestGetBranches', info='read')
 
611
request_handlers.register_lazy(
 
612
    'BzrDir.get_config_file', 'bzrlib.smart.bzrdir',
 
613
    'SmartServerBzrDirRequestConfigFile', info='read')
 
614
request_handlers.register_lazy(
 
615
    'BzrDir.destroy_branch', 'bzrlib.smart.bzrdir',
 
616
    'SmartServerBzrDirRequestDestroyBranch', info='semi')
 
617
request_handlers.register_lazy(
 
618
    'BzrDir.destroy_repository', 'bzrlib.smart.bzrdir',
 
619
    'SmartServerBzrDirRequestDestroyRepository', info='semi')
 
620
request_handlers.register_lazy(
 
621
    'BzrDir.has_workingtree', 'bzrlib.smart.bzrdir',
 
622
    'SmartServerBzrDirRequestHasWorkingTree', info='read')
 
623
request_handlers.register_lazy(
 
624
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir',
 
625
    'SmartServerRequestInitializeBzrDir', info='semi')
 
626
request_handlers.register_lazy(
 
627
    'BzrDirFormat.initialize_ex_1.16', 'bzrlib.smart.bzrdir',
 
628
    'SmartServerRequestBzrDirInitializeEx', info='semi')
 
629
request_handlers.register_lazy(
 
630
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir',
 
631
    info='read')
 
632
request_handlers.register_lazy(
 
633
    'BzrDir.open_2.1', 'bzrlib.smart.bzrdir',
 
634
    'SmartServerRequestOpenBzrDir_2_1', info='read')
 
635
request_handlers.register_lazy(
 
636
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir',
 
637
    'SmartServerRequestOpenBranch', info='read')
 
638
request_handlers.register_lazy(
 
639
    'BzrDir.open_branchV2', 'bzrlib.smart.bzrdir',
 
640
    'SmartServerRequestOpenBranchV2', info='read')
 
641
request_handlers.register_lazy(
 
642
    'BzrDir.open_branchV3', 'bzrlib.smart.bzrdir',
 
643
    'SmartServerRequestOpenBranchV3', info='read')
 
644
request_handlers.register_lazy(
 
645
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest', info='semivfs')
 
646
request_handlers.register_lazy(
 
647
    'get', 'bzrlib.smart.vfs', 'GetRequest', info='read')
 
648
request_handlers.register_lazy(
 
649
    'get_bundle', 'bzrlib.smart.request', 'GetBundleRequest', info='read')
 
650
request_handlers.register_lazy(
 
651
    'has', 'bzrlib.smart.vfs', 'HasRequest', info='read')
 
652
request_handlers.register_lazy(
 
653
    'hello', 'bzrlib.smart.request', 'HelloRequest', info='read')
 
654
request_handlers.register_lazy(
 
655
    'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest',
 
656
    info='read')
 
657
request_handlers.register_lazy(
 
658
    'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest', info='read')
 
659
request_handlers.register_lazy(
 
660
    'mkdir', 'bzrlib.smart.vfs', 'MkdirRequest', info='semivfs')
 
661
request_handlers.register_lazy(
 
662
    'move', 'bzrlib.smart.vfs', 'MoveRequest', info='semivfs')
 
663
request_handlers.register_lazy(
 
664
    'put', 'bzrlib.smart.vfs', 'PutRequest', info='idem')
 
665
request_handlers.register_lazy(
 
666
    'put_non_atomic', 'bzrlib.smart.vfs', 'PutNonAtomicRequest', info='idem')
 
667
request_handlers.register_lazy(
 
668
    'readv', 'bzrlib.smart.vfs', 'ReadvRequest', info='read')
 
669
request_handlers.register_lazy(
 
670
    'rename', 'bzrlib.smart.vfs', 'RenameRequest', info='semivfs')
 
671
request_handlers.register_lazy(
 
672
    'Repository.add_signature_text', 'bzrlib.smart.repository',
 
673
    'SmartServerRepositoryAddSignatureText', info='idem')
 
674
request_handlers.register_lazy(
 
675
    'Repository.all_revision_ids', 'bzrlib.smart.repository',
 
676
    'SmartServerRepositoryAllRevisionIds', info='read')
 
677
request_handlers.register_lazy(
 
678
    'PackRepository.autopack', 'bzrlib.smart.packrepository',
 
679
    'SmartServerPackRepositoryAutopack', info='idem')
 
680
request_handlers.register_lazy(
 
681
    'Repository.break_lock', 'bzrlib.smart.repository',
 
682
    'SmartServerRepositoryBreakLock', info='idem')
 
683
request_handlers.register_lazy(
 
684
    'Repository.gather_stats', 'bzrlib.smart.repository',
 
685
    'SmartServerRepositoryGatherStats', info='read')
 
686
request_handlers.register_lazy(
 
687
    'Repository.get_parent_map', 'bzrlib.smart.repository',
 
688
    'SmartServerRepositoryGetParentMap', info='read')
 
689
request_handlers.register_lazy(
 
690
    'Repository.get_revision_graph', 'bzrlib.smart.repository',
 
691
    'SmartServerRepositoryGetRevisionGraph', info='read')
 
692
request_handlers.register_lazy(
 
693
    'Repository.get_revision_signature_text', 'bzrlib.smart.repository',
 
694
    'SmartServerRepositoryGetRevisionSignatureText', info='read')
 
695
request_handlers.register_lazy(
 
696
    'Repository.has_revision', 'bzrlib.smart.repository',
 
697
    'SmartServerRequestHasRevision', info='read')
 
698
request_handlers.register_lazy(
 
699
    'Repository.has_signature_for_revision_id', 'bzrlib.smart.repository',
 
700
    'SmartServerRequestHasSignatureForRevisionId', info='read')
 
701
request_handlers.register_lazy(
 
702
    'Repository.insert_stream', 'bzrlib.smart.repository',
 
703
    'SmartServerRepositoryInsertStream', info='stream')
 
704
request_handlers.register_lazy(
 
705
    'Repository.insert_stream_1.19', 'bzrlib.smart.repository',
 
706
    'SmartServerRepositoryInsertStream_1_19', info='stream')
 
707
request_handlers.register_lazy(
 
708
    'Repository.insert_stream_locked', 'bzrlib.smart.repository',
 
709
    'SmartServerRepositoryInsertStreamLocked', info='stream')
 
710
request_handlers.register_lazy(
 
711
    'Repository.is_shared', 'bzrlib.smart.repository',
 
712
    'SmartServerRepositoryIsShared', info='read')
 
713
request_handlers.register_lazy(
 
714
    'Repository.iter_files_bytes', 'bzrlib.smart.repository',
 
715
    'SmartServerRepositoryIterFilesBytes', info='read')
 
716
request_handlers.register_lazy(
 
717
    'Repository.lock_write', 'bzrlib.smart.repository',
 
718
    'SmartServerRepositoryLockWrite', info='semi')
 
719
request_handlers.register_lazy(
 
720
    'Repository.make_working_trees', 'bzrlib.smart.repository',
 
721
    'SmartServerRepositoryMakeWorkingTrees', info='read')
 
722
request_handlers.register_lazy(
 
723
    'Repository.set_make_working_trees', 'bzrlib.smart.repository',
 
724
    'SmartServerRepositorySetMakeWorkingTrees', info='idem')
 
725
request_handlers.register_lazy(
 
726
    'Repository.unlock', 'bzrlib.smart.repository',
 
727
    'SmartServerRepositoryUnlock', info='semi')
 
728
request_handlers.register_lazy(
 
729
    'Repository.get_physical_lock_status', 'bzrlib.smart.repository',
 
730
    'SmartServerRepositoryGetPhysicalLockStatus', info='read')
 
731
request_handlers.register_lazy(
 
732
    'Repository.get_rev_id_for_revno', 'bzrlib.smart.repository',
 
733
    'SmartServerRepositoryGetRevIdForRevno', info='read')
 
734
request_handlers.register_lazy(
 
735
    'Repository.get_stream', 'bzrlib.smart.repository',
 
736
    'SmartServerRepositoryGetStream', info='read')
 
737
request_handlers.register_lazy(
 
738
    'Repository.get_stream_1.19', 'bzrlib.smart.repository',
 
739
    'SmartServerRepositoryGetStream_1_19', info='read')
 
740
request_handlers.register_lazy(
 
741
    'Repository.iter_revisions', 'bzrlib.smart.repository',
 
742
    'SmartServerRepositoryIterRevisions', info='read')
 
743
request_handlers.register_lazy(
 
744
    'Repository.pack', 'bzrlib.smart.repository',
 
745
    'SmartServerRepositoryPack', info='idem')
 
746
request_handlers.register_lazy(
 
747
    'Repository.start_write_group', 'bzrlib.smart.repository',
 
748
    'SmartServerRepositoryStartWriteGroup', info='semi')
 
749
request_handlers.register_lazy(
 
750
    'Repository.commit_write_group', 'bzrlib.smart.repository',
 
751
    'SmartServerRepositoryCommitWriteGroup', info='semi')
 
752
request_handlers.register_lazy(
 
753
    'Repository.abort_write_group', 'bzrlib.smart.repository',
 
754
    'SmartServerRepositoryAbortWriteGroup', info='semi')
 
755
request_handlers.register_lazy(
 
756
    'Repository.check_write_group', 'bzrlib.smart.repository',
 
757
    'SmartServerRepositoryCheckWriteGroup', info='read')
 
758
request_handlers.register_lazy(
 
759
    'Repository.reconcile', 'bzrlib.smart.repository',
 
760
    'SmartServerRepositoryReconcile', info='idem')
443
761
request_handlers.register_lazy(
444
762
    'Repository.tarball', 'bzrlib.smart.repository',
445
 
    'SmartServerRepositoryTarball')
446
 
request_handlers.register_lazy(
447
 
    'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest')
448
 
request_handlers.register_lazy(
449
 
    'stat', 'bzrlib.smart.vfs', 'StatRequest')
450
 
request_handlers.register_lazy(
451
 
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
452
 
request_handlers.register_lazy(
453
 
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')
 
763
    'SmartServerRepositoryTarball', info='read')
 
764
request_handlers.register_lazy(
 
765
    'VersionedFileRepository.get_serializer_format', 'bzrlib.smart.repository',
 
766
    'SmartServerRepositoryGetSerializerFormat', info='read')
 
767
request_handlers.register_lazy(
 
768
    'VersionedFileRepository.get_inventories', 'bzrlib.smart.repository',
 
769
    'SmartServerRepositoryGetInventories', info='read')
 
770
request_handlers.register_lazy(
 
771
    'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest', info='semivfs')
 
772
request_handlers.register_lazy(
 
773
    'stat', 'bzrlib.smart.vfs', 'StatRequest', info='read')
 
774
request_handlers.register_lazy(
 
775
    'Transport.is_readonly', 'bzrlib.smart.request',
 
776
    'SmartServerIsReadonly', info='read')