~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/request.py

Merge and cleanup pre-external-reference-repository tests

Show diffs side-by-side

added added

removed removed

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