/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
  • Date: 2010-01-12 22:51:31 UTC
  • mto: This revision was merged to the branch mainline in revision 4955.
  • Revision ID: john@arbash-meinel.com-20100112225131-he8h411p6aeeb947
Delay grabbing an output stream until we actually go to show a diff.

This makes the test suite happy, but it also seems to be reasonable.
If we aren't going to write anything, we don't need to hold an
output stream open.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 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
"""
 
28
 
 
29
# XXX: The class names are a little confusing: the protocol will instantiate a
 
30
# SmartServerRequestHandler, whose dispatch_command method creates an instance
 
31
# of a SmartServerRequest subclass.
 
32
 
 
33
 
 
34
import tempfile
 
35
import thread
 
36
import threading
 
37
 
 
38
from bzrlib import (
 
39
    bzrdir,
 
40
    debug,
 
41
    errors,
 
42
    osutils,
 
43
    registry,
 
44
    revision,
 
45
    trace,
 
46
    urlutils,
 
47
    )
 
48
from bzrlib.lazy_import import lazy_import
 
49
lazy_import(globals(), """
 
50
from bzrlib.bundle import serializer
 
51
""")
 
52
 
 
53
 
 
54
jail_info = threading.local()
 
55
jail_info.transports = None
 
56
 
 
57
 
 
58
def _install_hook():
 
59
    bzrdir.BzrDir.hooks.install_named_hook(
 
60
        'pre_open', _pre_open_hook, 'checking server jail')
 
61
 
 
62
 
 
63
def _pre_open_hook(transport):
 
64
    allowed_transports = getattr(jail_info, 'transports', None)
 
65
    if allowed_transports is None:
 
66
        return
 
67
    abspath = transport.base
 
68
    for allowed_transport in allowed_transports:
 
69
        try:
 
70
            allowed_transport.relpath(abspath)
 
71
        except errors.PathNotChild:
 
72
            continue
 
73
        else:
 
74
            return
 
75
    raise errors.JailBreak(abspath)
 
76
 
 
77
 
 
78
_install_hook()
 
79
 
 
80
 
 
81
class SmartServerRequest(object):
 
82
    """Base class for request handlers.
 
83
 
 
84
    To define a new request, subclass this class and override the `do` method
 
85
    (and if appropriate, `do_body` as well).  Request implementors should take
 
86
    care to call `translate_client_path` and `transport_from_client_path` as
 
87
    appropriate when dealing with paths received from the client.
 
88
    """
 
89
    # XXX: rename this class to BaseSmartServerRequestHandler ?  A request
 
90
    # *handler* is a different concept to the request.
 
91
 
 
92
    def __init__(self, backing_transport, root_client_path='/', jail_root=None):
 
93
        """Constructor.
 
94
 
 
95
        :param backing_transport: the base transport to be used when performing
 
96
            this request.
 
97
        :param root_client_path: the client path that maps to the root of
 
98
            backing_transport.  This is used to interpret relpaths received
 
99
            from the client.  Clients will not be able to refer to paths above
 
100
            this root.  If root_client_path is None, then no translation will
 
101
            be performed on client paths.  Default is '/'.
 
102
        :param jail_root: if specified, the root of the BzrDir.open jail to use
 
103
            instead of backing_transport.
 
104
        """
 
105
        self._backing_transport = backing_transport
 
106
        if jail_root is None:
 
107
            jail_root = backing_transport
 
108
        self._jail_root = jail_root
 
109
        if root_client_path is not None:
 
110
            if not root_client_path.startswith('/'):
 
111
                root_client_path = '/' + root_client_path
 
112
            if not root_client_path.endswith('/'):
 
113
                root_client_path += '/'
 
114
        self._root_client_path = root_client_path
 
115
        self._body_chunks = []
 
116
 
 
117
    def _check_enabled(self):
 
118
        """Raises DisabledMethod if this method is disabled."""
 
119
        pass
 
120
 
 
121
    def do(self, *args):
 
122
        """Mandatory extension point for SmartServerRequest subclasses.
 
123
 
 
124
        Subclasses must implement this.
 
125
 
 
126
        This should return a SmartServerResponse if this command expects to
 
127
        receive no body.
 
128
        """
 
129
        raise NotImplementedError(self.do)
 
130
 
 
131
    def execute(self, *args):
 
132
        """Public entry point to execute this request.
 
133
 
 
134
        It will return a SmartServerResponse if the command does not expect a
 
135
        body.
 
136
 
 
137
        :param *args: the arguments of the request.
 
138
        """
 
139
        self._check_enabled()
 
140
        return self.do(*args)
 
141
 
 
142
    def do_body(self, body_bytes):
 
143
        """Called if the client sends a body with the request.
 
144
 
 
145
        The do() method is still called, and must have returned None.
 
146
 
 
147
        Must return a SmartServerResponse.
 
148
        """
 
149
        if body_bytes != '':
 
150
            raise errors.SmartProtocolError('Request does not expect a body')
 
151
 
 
152
    def do_chunk(self, chunk_bytes):
 
153
        """Called with each body chunk if the request has a streamed body.
 
154
 
 
155
        The do() method is still called, and must have returned None.
 
156
        """
 
157
        self._body_chunks.append(chunk_bytes)
 
158
 
 
159
    def do_end(self):
 
160
        """Called when the end of the request has been received."""
 
161
        body_bytes = ''.join(self._body_chunks)
 
162
        self._body_chunks = None
 
163
        return self.do_body(body_bytes)
 
164
 
 
165
    def setup_jail(self):
 
166
        jail_info.transports = [self._jail_root]
 
167
 
 
168
    def teardown_jail(self):
 
169
        jail_info.transports = None
 
170
 
 
171
    def translate_client_path(self, client_path):
 
172
        """Translate a path received from a network client into a local
 
173
        relpath.
 
174
 
 
175
        All paths received from the client *must* be translated.
 
176
 
 
177
        :param client_path: the path from the client.
 
178
        :returns: a relpath that may be used with self._backing_transport
 
179
            (unlike the untranslated client_path, which must not be used with
 
180
            the backing transport).
 
181
        """
 
182
        if self._root_client_path is None:
 
183
            # no translation necessary!
 
184
            return client_path
 
185
        if not client_path.startswith('/'):
 
186
            client_path = '/' + client_path
 
187
        if client_path + '/' == self._root_client_path:
 
188
            return '.'
 
189
        if client_path.startswith(self._root_client_path):
 
190
            path = client_path[len(self._root_client_path):]
 
191
            relpath = urlutils.joinpath('/', path)
 
192
            if not relpath.startswith('/'):
 
193
                raise ValueError(relpath)
 
194
            return urlutils.escape('.' + relpath)
 
195
        else:
 
196
            raise errors.PathNotChild(client_path, self._root_client_path)
 
197
 
 
198
    def transport_from_client_path(self, client_path):
 
199
        """Get a backing transport corresponding to the location referred to by
 
200
        a network client.
 
201
 
 
202
        :seealso: translate_client_path
 
203
        :returns: a transport cloned from self._backing_transport
 
204
        """
 
205
        relpath = self.translate_client_path(client_path)
 
206
        return self._backing_transport.clone(relpath)
 
207
 
 
208
 
 
209
class SmartServerResponse(object):
 
210
    """A response to a client request.
 
211
 
 
212
    This base class should not be used. Instead use
 
213
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
 
214
    """
 
215
 
 
216
    def __init__(self, args, body=None, body_stream=None):
 
217
        """Constructor.
 
218
 
 
219
        :param args: tuple of response arguments.
 
220
        :param body: string of a response body.
 
221
        :param body_stream: iterable of bytestrings to be streamed to the
 
222
            client.
 
223
        """
 
224
        self.args = args
 
225
        if body is not None and body_stream is not None:
 
226
            raise errors.BzrError(
 
227
                "'body' and 'body_stream' are mutually exclusive.")
 
228
        self.body = body
 
229
        self.body_stream = body_stream
 
230
 
 
231
    def __eq__(self, other):
 
232
        if other is None:
 
233
            return False
 
234
        return (other.args == self.args and
 
235
                other.body == self.body and
 
236
                other.body_stream is self.body_stream)
 
237
 
 
238
    def __repr__(self):
 
239
        return "<%s args=%r body=%r>" % (self.__class__.__name__,
 
240
            self.args, self.body)
 
241
 
 
242
 
 
243
class FailedSmartServerResponse(SmartServerResponse):
 
244
    """A SmartServerResponse for a request which failed."""
 
245
 
 
246
    def is_successful(self):
 
247
        """FailedSmartServerResponse are not successful."""
 
248
        return False
 
249
 
 
250
 
 
251
class SuccessfulSmartServerResponse(SmartServerResponse):
 
252
    """A SmartServerResponse for a successfully completed request."""
 
253
 
 
254
    def is_successful(self):
 
255
        """SuccessfulSmartServerResponse are successful."""
 
256
        return True
 
257
 
 
258
 
 
259
class SmartServerRequestHandler(object):
 
260
    """Protocol logic for smart server.
 
261
 
 
262
    This doesn't handle serialization at all, it just processes requests and
 
263
    creates responses.
 
264
    """
 
265
 
 
266
    # IMPORTANT FOR IMPLEMENTORS: It is important that SmartServerRequestHandler
 
267
    # not contain encoding or decoding logic to allow the wire protocol to vary
 
268
    # from the object protocol: we will want to tweak the wire protocol separate
 
269
    # from the object model, and ideally we will be able to do that without
 
270
    # having a SmartServerRequestHandler subclass for each wire protocol, rather
 
271
    # just a Protocol subclass.
 
272
 
 
273
    # TODO: Better way of representing the body for commands that take it,
 
274
    # and allow it to be streamed into the server.
 
275
 
 
276
    def __init__(self, backing_transport, commands, root_client_path,
 
277
        jail_root=None):
 
278
        """Constructor.
 
279
 
 
280
        :param backing_transport: a Transport to handle requests for.
 
281
        :param commands: a registry mapping command names to SmartServerRequest
 
282
            subclasses. e.g. bzrlib.transport.smart.vfs.vfs_commands.
 
283
        """
 
284
        self._backing_transport = backing_transport
 
285
        self._root_client_path = root_client_path
 
286
        self._commands = commands
 
287
        if jail_root is None:
 
288
            jail_root = backing_transport
 
289
        self._jail_root = jail_root
 
290
        self.response = None
 
291
        self.finished_reading = False
 
292
        self._command = None
 
293
        if 'hpss' in debug.debug_flags:
 
294
            self._request_start_time = osutils.timer_func()
 
295
            self._thread_id = thread.get_ident()
 
296
 
 
297
    def _trace(self, action, message, extra_bytes=None, include_time=False):
 
298
        # It is a bit of a shame that this functionality overlaps with that of 
 
299
        # ProtocolThreeRequester._trace. However, there is enough difference
 
300
        # that just putting it in a helper doesn't help a lot. And some state
 
301
        # is taken from the instance.
 
302
        if include_time:
 
303
            t = '%5.3fs ' % (osutils.timer_func() - self._request_start_time)
 
304
        else:
 
305
            t = ''
 
306
        if extra_bytes is None:
 
307
            extra = ''
 
308
        else:
 
309
            extra = ' ' + repr(extra_bytes[:40])
 
310
            if len(extra) > 33:
 
311
                extra = extra[:29] + extra[-1] + '...'
 
312
        trace.mutter('%12s: [%s] %s%s%s'
 
313
                     % (action, self._thread_id, t, message, extra))
 
314
 
 
315
    def accept_body(self, bytes):
 
316
        """Accept body data."""
 
317
        if self._command is None:
 
318
            # no active command object, so ignore the event.
 
319
            return
 
320
        self._run_handler_code(self._command.do_chunk, (bytes,), {})
 
321
        if 'hpss' in debug.debug_flags:
 
322
            self._trace('accept body',
 
323
                        '%d bytes' % (len(bytes),), bytes)
 
324
 
 
325
    def end_of_body(self):
 
326
        """No more body data will be received."""
 
327
        self._run_handler_code(self._command.do_end, (), {})
 
328
        # cannot read after this.
 
329
        self.finished_reading = True
 
330
        if 'hpss' in debug.debug_flags:
 
331
            self._trace('end of body', '', include_time=True)
 
332
 
 
333
    def _run_handler_code(self, callable, args, kwargs):
 
334
        """Run some handler specific code 'callable'.
 
335
 
 
336
        If a result is returned, it is considered to be the commands response,
 
337
        and finished_reading is set true, and its assigned to self.response.
 
338
 
 
339
        Any exceptions caught are translated and a response object created
 
340
        from them.
 
341
        """
 
342
        result = self._call_converting_errors(callable, args, kwargs)
 
343
 
 
344
        if result is not None:
 
345
            self.response = result
 
346
            self.finished_reading = True
 
347
 
 
348
    def _call_converting_errors(self, callable, args, kwargs):
 
349
        """Call callable converting errors to Response objects."""
 
350
        # XXX: most of this error conversion is VFS-related, and thus ought to
 
351
        # be in SmartServerVFSRequestHandler somewhere.
 
352
        try:
 
353
            self._command.setup_jail()
 
354
            try:
 
355
                return callable(*args, **kwargs)
 
356
            finally:
 
357
                self._command.teardown_jail()
 
358
        except (KeyboardInterrupt, SystemExit):
 
359
            raise
 
360
        except Exception, err:
 
361
            err_struct = _translate_error(err)
 
362
            return FailedSmartServerResponse(err_struct)
 
363
 
 
364
    def headers_received(self, headers):
 
365
        # Just a no-op at the moment.
 
366
        if 'hpss' in debug.debug_flags:
 
367
            self._trace('headers', repr(headers))
 
368
 
 
369
    def args_received(self, args):
 
370
        cmd = args[0]
 
371
        args = args[1:]
 
372
        try:
 
373
            command = self._commands.get(cmd)
 
374
        except LookupError:
 
375
            if 'hpss' in debug.debug_flags:
 
376
                self._trace('hpss unknown request', 
 
377
                            cmd, repr(args)[1:-1])
 
378
            raise errors.UnknownSmartMethod(cmd)
 
379
        if 'hpss' in debug.debug_flags:
 
380
            from bzrlib.smart import vfs
 
381
            if issubclass(command, vfs.VfsRequest):
 
382
                action = 'hpss vfs req'
 
383
            else:
 
384
                action = 'hpss request'
 
385
            self._trace(action, 
 
386
                        '%s %s' % (cmd, repr(args)[1:-1]))
 
387
        self._command = command(
 
388
            self._backing_transport, self._root_client_path, self._jail_root)
 
389
        self._run_handler_code(self._command.execute, args, {})
 
390
 
 
391
    def end_received(self):
 
392
        if self._command is None:
 
393
            # no active command object, so ignore the event.
 
394
            return
 
395
        self._run_handler_code(self._command.do_end, (), {})
 
396
        if 'hpss' in debug.debug_flags:
 
397
            self._trace('end', '', include_time=True)
 
398
 
 
399
    def post_body_error_received(self, error_args):
 
400
        # Just a no-op at the moment.
 
401
        pass
 
402
 
 
403
 
 
404
def _translate_error(err):
 
405
    if isinstance(err, errors.NoSuchFile):
 
406
        return ('NoSuchFile', err.path)
 
407
    elif isinstance(err, errors.FileExists):
 
408
        return ('FileExists', err.path)
 
409
    elif isinstance(err, errors.DirectoryNotEmpty):
 
410
        return ('DirectoryNotEmpty', err.path)
 
411
    elif isinstance(err, errors.IncompatibleRepositories):
 
412
        return ('IncompatibleRepositories', str(err.source), str(err.target),
 
413
            str(err.details))
 
414
    elif isinstance(err, errors.ShortReadvError):
 
415
        return ('ShortReadvError', err.path, str(err.offset), str(err.length),
 
416
                str(err.actual))
 
417
    elif isinstance(err, errors.UnstackableRepositoryFormat):
 
418
        return (('UnstackableRepositoryFormat', str(err.format), err.url))
 
419
    elif isinstance(err, errors.UnstackableBranchFormat):
 
420
        return ('UnstackableBranchFormat', str(err.format), err.url)
 
421
    elif isinstance(err, errors.NotStacked):
 
422
        return ('NotStacked',)
 
423
    elif isinstance(err, UnicodeError):
 
424
        # If it is a DecodeError, than most likely we are starting
 
425
        # with a plain string
 
426
        str_or_unicode = err.object
 
427
        if isinstance(str_or_unicode, unicode):
 
428
            # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
 
429
            # byte) in it, so this encoding could cause broken responses.
 
430
            # Newer clients use protocol v3, so will be fine.
 
431
            val = 'u:' + str_or_unicode.encode('utf-8')
 
432
        else:
 
433
            val = 's:' + str_or_unicode.encode('base64')
 
434
        # This handles UnicodeEncodeError or UnicodeDecodeError
 
435
        return (err.__class__.__name__, err.encoding, val, str(err.start),
 
436
                str(err.end), err.reason)
 
437
    elif isinstance(err, errors.TransportNotPossible):
 
438
        if err.msg == "readonly transport":
 
439
            return ('ReadOnlyError', )
 
440
    elif isinstance(err, errors.ReadError):
 
441
        # cannot read the file
 
442
        return ('ReadError', err.path)
 
443
    elif isinstance(err, errors.PermissionDenied):
 
444
        return ('PermissionDenied', err.path, err.extra)
 
445
    elif isinstance(err, errors.TokenMismatch):
 
446
        return ('TokenMismatch', err.given_token, err.lock_token)
 
447
    elif isinstance(err, errors.LockContention):
 
448
        return ('LockContention',)
 
449
    # Unserialisable error.  Log it, and return a generic error
 
450
    trace.log_exception_quietly()
 
451
    return ('error', str(err))
 
452
 
 
453
 
 
454
class HelloRequest(SmartServerRequest):
 
455
    """Answer a version request with the highest protocol version this server
 
456
    supports.
 
457
    """
 
458
 
 
459
    def do(self):
 
460
        return SuccessfulSmartServerResponse(('ok', '2'))
 
461
 
 
462
 
 
463
class GetBundleRequest(SmartServerRequest):
 
464
    """Get a bundle of from the null revision to the specified revision."""
 
465
 
 
466
    def do(self, path, revision_id):
 
467
        # open transport relative to our base
 
468
        t = self.transport_from_client_path(path)
 
469
        control, extra_path = bzrdir.BzrDir.open_containing_from_transport(t)
 
470
        repo = control.open_repository()
 
471
        tmpf = tempfile.TemporaryFile()
 
472
        base_revision = revision.NULL_REVISION
 
473
        serializer.write_bundle(repo, revision_id, base_revision, tmpf)
 
474
        tmpf.seek(0)
 
475
        return SuccessfulSmartServerResponse((), tmpf.read())
 
476
 
 
477
 
 
478
class SmartServerIsReadonly(SmartServerRequest):
 
479
    # XXX: this request method belongs somewhere else.
 
480
 
 
481
    def do(self):
 
482
        if self._backing_transport.is_readonly():
 
483
            answer = 'yes'
 
484
        else:
 
485
            answer = 'no'
 
486
        return SuccessfulSmartServerResponse((answer,))
 
487
 
 
488
 
 
489
request_handlers = registry.Registry()
 
490
request_handlers.register_lazy(
 
491
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
 
492
request_handlers.register_lazy(
 
493
    'Branch.get_config_file', 'bzrlib.smart.branch',
 
494
    'SmartServerBranchGetConfigFile')
 
495
request_handlers.register_lazy(
 
496
    'Branch.get_parent', 'bzrlib.smart.branch', 'SmartServerBranchGetParent')
 
497
request_handlers.register_lazy(
 
498
    'Branch.get_tags_bytes', 'bzrlib.smart.branch',
 
499
    'SmartServerBranchGetTagsBytes')
 
500
request_handlers.register_lazy(
 
501
    'Branch.set_tags_bytes', 'bzrlib.smart.branch',
 
502
    'SmartServerBranchSetTagsBytes')
 
503
request_handlers.register_lazy(
 
504
    'Branch.get_stacked_on_url', 'bzrlib.smart.branch', 'SmartServerBranchRequestGetStackedOnURL')
 
505
request_handlers.register_lazy(
 
506
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
 
507
request_handlers.register_lazy(
 
508
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
 
509
request_handlers.register_lazy( 'Branch.revision_history',
 
510
    'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
 
511
request_handlers.register_lazy( 'Branch.set_config_option',
 
512
    'bzrlib.smart.branch', 'SmartServerBranchRequestSetConfigOption')
 
513
request_handlers.register_lazy( 'Branch.set_last_revision',
 
514
    'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
 
515
request_handlers.register_lazy(
 
516
    'Branch.set_last_revision_info', 'bzrlib.smart.branch',
 
517
    'SmartServerBranchRequestSetLastRevisionInfo')
 
518
request_handlers.register_lazy(
 
519
    'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
 
520
    'SmartServerBranchRequestSetLastRevisionEx')
 
521
request_handlers.register_lazy(
 
522
    'Branch.set_parent_location', 'bzrlib.smart.branch',
 
523
    'SmartServerBranchRequestSetParentLocation')
 
524
request_handlers.register_lazy(
 
525
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
 
526
request_handlers.register_lazy(
 
527
    'BzrDir.cloning_metadir', 'bzrlib.smart.bzrdir',
 
528
    'SmartServerBzrDirRequestCloningMetaDir')
 
529
request_handlers.register_lazy(
 
530
    'BzrDir.create_branch', 'bzrlib.smart.bzrdir',
 
531
    'SmartServerRequestCreateBranch')
 
532
request_handlers.register_lazy(
 
533
    'BzrDir.create_repository', 'bzrlib.smart.bzrdir',
 
534
    'SmartServerRequestCreateRepository')
 
535
request_handlers.register_lazy(
 
536
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir',
 
537
    'SmartServerRequestFindRepositoryV1')
 
538
request_handlers.register_lazy(
 
539
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir',
 
540
    'SmartServerRequestFindRepositoryV2')
 
541
request_handlers.register_lazy(
 
542
    'BzrDir.find_repositoryV3', 'bzrlib.smart.bzrdir',
 
543
    'SmartServerRequestFindRepositoryV3')
 
544
request_handlers.register_lazy(
 
545
    'BzrDir.get_config_file', 'bzrlib.smart.bzrdir',
 
546
    'SmartServerBzrDirRequestConfigFile')
 
547
request_handlers.register_lazy(
 
548
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir',
 
549
    'SmartServerRequestInitializeBzrDir')
 
550
request_handlers.register_lazy(
 
551
    'BzrDirFormat.initialize_ex_1.16', 'bzrlib.smart.bzrdir',
 
552
    'SmartServerRequestBzrDirInitializeEx')
 
553
request_handlers.register_lazy(
 
554
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')
 
555
request_handlers.register_lazy(
 
556
    'BzrDir.open_2.1', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir_2_1')
 
557
request_handlers.register_lazy(
 
558
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir',
 
559
    'SmartServerRequestOpenBranch')
 
560
request_handlers.register_lazy(
 
561
    'BzrDir.open_branchV2', 'bzrlib.smart.bzrdir',
 
562
    'SmartServerRequestOpenBranchV2')
 
563
request_handlers.register_lazy(
 
564
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
 
565
request_handlers.register_lazy(
 
566
    'get', 'bzrlib.smart.vfs', 'GetRequest')
 
567
request_handlers.register_lazy(
 
568
    'get_bundle', 'bzrlib.smart.request', 'GetBundleRequest')
 
569
request_handlers.register_lazy(
 
570
    'has', 'bzrlib.smart.vfs', 'HasRequest')
 
571
request_handlers.register_lazy(
 
572
    'hello', 'bzrlib.smart.request', 'HelloRequest')
 
573
request_handlers.register_lazy(
 
574
    'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest')
 
575
request_handlers.register_lazy(
 
576
    'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest')
 
577
request_handlers.register_lazy(
 
578
    'mkdir', 'bzrlib.smart.vfs', 'MkdirRequest')
 
579
request_handlers.register_lazy(
 
580
    'move', 'bzrlib.smart.vfs', 'MoveRequest')
 
581
request_handlers.register_lazy(
 
582
    'put', 'bzrlib.smart.vfs', 'PutRequest')
 
583
request_handlers.register_lazy(
 
584
    'put_non_atomic', 'bzrlib.smart.vfs', 'PutNonAtomicRequest')
 
585
request_handlers.register_lazy(
 
586
    'readv', 'bzrlib.smart.vfs', 'ReadvRequest')
 
587
request_handlers.register_lazy(
 
588
    'rename', 'bzrlib.smart.vfs', 'RenameRequest')
 
589
request_handlers.register_lazy(
 
590
    'PackRepository.autopack', 'bzrlib.smart.packrepository',
 
591
    'SmartServerPackRepositoryAutopack')
 
592
request_handlers.register_lazy('Repository.gather_stats',
 
593
                               'bzrlib.smart.repository',
 
594
                               'SmartServerRepositoryGatherStats')
 
595
request_handlers.register_lazy('Repository.get_parent_map',
 
596
                               'bzrlib.smart.repository',
 
597
                               'SmartServerRepositoryGetParentMap')
 
598
request_handlers.register_lazy(
 
599
    'Repository.get_revision_graph', 'bzrlib.smart.repository', 'SmartServerRepositoryGetRevisionGraph')
 
600
request_handlers.register_lazy(
 
601
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
 
602
request_handlers.register_lazy(
 
603
    'Repository.insert_stream', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream')
 
604
request_handlers.register_lazy(
 
605
    'Repository.insert_stream_1.19', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream_1_19')
 
606
request_handlers.register_lazy(
 
607
    'Repository.insert_stream_locked', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStreamLocked')
 
608
request_handlers.register_lazy(
 
609
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
 
610
request_handlers.register_lazy(
 
611
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
 
612
request_handlers.register_lazy(
 
613
    'Repository.set_make_working_trees', 'bzrlib.smart.repository',
 
614
    'SmartServerRepositorySetMakeWorkingTrees')
 
615
request_handlers.register_lazy(
 
616
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
 
617
request_handlers.register_lazy(
 
618
    'Repository.get_rev_id_for_revno', 'bzrlib.smart.repository',
 
619
    'SmartServerRepositoryGetRevIdForRevno')
 
620
request_handlers.register_lazy(
 
621
    'Repository.get_stream', 'bzrlib.smart.repository',
 
622
    'SmartServerRepositoryGetStream')
 
623
request_handlers.register_lazy(
 
624
    'Repository.get_stream_1.19', 'bzrlib.smart.repository',
 
625
    'SmartServerRepositoryGetStream_1_19')
 
626
request_handlers.register_lazy(
 
627
    'Repository.tarball', 'bzrlib.smart.repository',
 
628
    'SmartServerRepositoryTarball')
 
629
request_handlers.register_lazy(
 
630
    'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest')
 
631
request_handlers.register_lazy(
 
632
    'stat', 'bzrlib.smart.vfs', 'StatRequest')
 
633
request_handlers.register_lazy(
 
634
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')