/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: 2009-12-22 16:28:47 UTC
  • mto: This revision was merged to the branch mainline in revision 4922.
  • Revision ID: john@arbash-meinel.com-20091222162847-tvnsc69to4l4uf5r
Implement a permute_for_extension helper.

Use it for all of the 'simple' extension permutations.
It basically permutes all tests in the current module, by setting TestCase.module.
Which works well for most of our extension tests. Some had more advanced
handling of permutations (extra permutations, custom vars, etc.)

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