/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/smart/request.py

  • Committer: John Arbash Meinel
  • Author(s): Mark Hammond
  • Date: 2008-09-09 17:02:21 UTC
  • mto: This revision was merged to the branch mainline in revision 3697.
  • Revision ID: john@arbash-meinel.com-20080909170221-svim3jw2mrz0amp3
An updated transparent icon for bzr.

Show diffs side-by-side

added added

removed removed

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