~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/request.py

  • Committer: Jelmer Vernooij
  • Date: 2010-12-20 11:57:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5577.
  • Revision ID: jelmer@samba.org-20101220115714-2ru3hfappjweeg7q
Don't use no-plugins.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2006-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
 
17
 
"""Basic server-side logic for dealing with requests."""
 
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.
18
32
 
19
33
 
20
34
import tempfile
 
35
import thread
 
36
import threading
21
37
 
22
38
from bzrlib import (
23
39
    bzrdir,
 
40
    debug,
24
41
    errors,
 
42
    osutils,
25
43
    registry,
26
44
    revision,
 
45
    trace,
 
46
    urlutils,
27
47
    )
28
 
from bzrlib.bundle.serializer import write_bundle
 
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()
29
79
 
30
80
 
31
81
class SmartServerRequest(object):
32
 
    """Base class for request handlers."""
33
 
 
34
 
    def __init__(self, backing_transport):
 
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):
35
93
        """Constructor.
36
94
 
37
95
        :param backing_transport: the base transport to be used when performing
38
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.
39
104
        """
40
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 = []
41
116
 
42
117
    def _check_enabled(self):
43
118
        """Raises DisabledMethod if this method is disabled."""
45
120
 
46
121
    def do(self, *args):
47
122
        """Mandatory extension point for SmartServerRequest subclasses.
48
 
        
 
123
 
49
124
        Subclasses must implement this.
50
 
        
 
125
 
51
126
        This should return a SmartServerResponse if this command expects to
52
127
        receive no body.
53
128
        """
66
141
 
67
142
    def do_body(self, body_bytes):
68
143
        """Called if the client sends a body with the request.
69
 
        
 
144
 
 
145
        The do() method is still called, and must have returned None.
 
146
 
70
147
        Must return a SmartServerResponse.
71
148
        """
72
 
        # TODO: if a client erroneously sends a request that shouldn't have a
73
 
        # body, what to do?  Probably SmartServerRequestHandler should catch
74
 
        # this NotImplementedError and translate it into a 'bad request' error
75
 
        # to send to the client.
76
 
        raise NotImplementedError(self.do_body)
 
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)
77
207
 
78
208
 
79
209
class SmartServerResponse(object):
80
210
    """A response to a client request.
81
 
    
 
211
 
82
212
    This base class should not be used. Instead use
83
213
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
84
214
    """
106
236
                other.body_stream is self.body_stream)
107
237
 
108
238
    def __repr__(self):
109
 
        return "<SmartServerResponse %r args=%r body=%r>" % (
110
 
            self.is_successful(), self.args, self.body)
 
239
        return "<%s args=%r body=%r>" % (self.__class__.__name__,
 
240
            self.args, self.body)
111
241
 
112
242
 
113
243
class FailedSmartServerResponse(SmartServerResponse):
128
258
 
129
259
class SmartServerRequestHandler(object):
130
260
    """Protocol logic for smart server.
131
 
    
 
261
 
132
262
    This doesn't handle serialization at all, it just processes requests and
133
263
    creates responses.
134
264
    """
143
273
    # TODO: Better way of representing the body for commands that take it,
144
274
    # and allow it to be streamed into the server.
145
275
 
146
 
    def __init__(self, backing_transport, commands):
 
276
    def __init__(self, backing_transport, commands, root_client_path,
 
277
        jail_root=None):
147
278
        """Constructor.
148
279
 
149
280
        :param backing_transport: a Transport to handle requests for.
151
282
            subclasses. e.g. bzrlib.transport.smart.vfs.vfs_commands.
152
283
        """
153
284
        self._backing_transport = backing_transport
 
285
        self._root_client_path = root_client_path
154
286
        self._commands = commands
155
 
        self._body_bytes = ''
 
287
        if jail_root is None:
 
288
            jail_root = backing_transport
 
289
        self._jail_root = jail_root
156
290
        self.response = None
157
291
        self.finished_reading = False
158
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))
159
314
 
160
315
    def accept_body(self, bytes):
161
316
        """Accept body data."""
162
 
 
163
 
        # TODO: This should be overriden for each command that desired body data
164
 
        # to handle the right format of that data, i.e. plain bytes, a bundle,
165
 
        # etc.  The deserialisation into that format should be done in the
166
 
        # Protocol object.
167
 
 
168
 
        # default fallback is to accumulate bytes.
169
 
        self._body_bytes += bytes
170
 
        
 
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
 
171
325
    def end_of_body(self):
172
326
        """No more body data will be received."""
173
 
        self._run_handler_code(self._command.do_body, (self._body_bytes,), {})
 
327
        self._run_handler_code(self._command.do_end, (), {})
174
328
        # cannot read after this.
175
329
        self.finished_reading = True
176
 
 
177
 
    def dispatch_command(self, cmd, args):
178
 
        """Deprecated compatibility method.""" # XXX XXX
179
 
        try:
180
 
            command = self._commands.get(cmd)
181
 
        except LookupError:
182
 
            raise errors.SmartProtocolError("bad request %r" % (cmd,))
183
 
        self._command = command(self._backing_transport)
184
 
        self._run_handler_code(self._command.execute, args, {})
 
330
        if 'hpss' in debug.debug_flags:
 
331
            self._trace('end of body', '', include_time=True)
185
332
 
186
333
    def _run_handler_code(self, callable, args, kwargs):
187
334
        """Run some handler specific code 'callable'.
203
350
        # XXX: most of this error conversion is VFS-related, and thus ought to
204
351
        # be in SmartServerVFSRequestHandler somewhere.
205
352
        try:
206
 
            return callable(*args, **kwargs)
207
 
        except errors.NoSuchFile, e:
208
 
            return FailedSmartServerResponse(('NoSuchFile', e.path))
209
 
        except errors.FileExists, e:
210
 
            return FailedSmartServerResponse(('FileExists', e.path))
211
 
        except errors.DirectoryNotEmpty, e:
212
 
            return FailedSmartServerResponse(('DirectoryNotEmpty', e.path))
213
 
        except errors.ShortReadvError, e:
214
 
            return FailedSmartServerResponse(('ShortReadvError',
215
 
                e.path, str(e.offset), str(e.length), str(e.actual)))
216
 
        except UnicodeError, e:
217
 
            # If it is a DecodeError, than most likely we are starting
218
 
            # with a plain string
219
 
            str_or_unicode = e.object
220
 
            if isinstance(str_or_unicode, unicode):
221
 
                # XXX: UTF-8 might have \x01 (our seperator byte) in it.  We
222
 
                # should escape it somehow.
223
 
                val = 'u:' + str_or_unicode.encode('utf-8')
224
 
            else:
225
 
                val = 's:' + str_or_unicode.encode('base64')
226
 
            # This handles UnicodeEncodeError or UnicodeDecodeError
227
 
            return FailedSmartServerResponse((e.__class__.__name__,
228
 
                    e.encoding, val, str(e.start), str(e.end), e.reason))
229
 
        except errors.TransportNotPossible, e:
230
 
            if e.msg == "readonly transport":
231
 
                return FailedSmartServerResponse(('ReadOnlyError', ))
232
 
            else:
233
 
                raise
 
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))
234
452
 
235
453
 
236
454
class HelloRequest(SmartServerRequest):
247
465
 
248
466
    def do(self, path, revision_id):
249
467
        # open transport relative to our base
250
 
        t = self._backing_transport.clone(path)
 
468
        t = self.transport_from_client_path(path)
251
469
        control, extra_path = bzrdir.BzrDir.open_containing_from_transport(t)
252
470
        repo = control.open_repository()
253
471
        tmpf = tempfile.TemporaryFile()
254
472
        base_revision = revision.NULL_REVISION
255
 
        write_bundle(repo, revision_id, base_revision, tmpf)
 
473
        serializer.write_bundle(repo, revision_id, base_revision, tmpf)
256
474
        tmpf.seek(0)
257
475
        return SuccessfulSmartServerResponse((), tmpf.read())
258
476
 
272
490
request_handlers.register_lazy(
273
491
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
274
492
request_handlers.register_lazy(
275
 
    'Branch.get_config_file', 'bzrlib.smart.branch', 'SmartServerBranchGetConfigFile')
 
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')
276
505
request_handlers.register_lazy(
277
506
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
278
507
request_handlers.register_lazy(
279
508
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
280
 
request_handlers.register_lazy(
281
 
    'Branch.revision_history', 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
282
 
request_handlers.register_lazy(
283
 
    'Branch.set_last_revision', 'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
 
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_config_option_dict',
 
514
    'bzrlib.smart.branch', 'SmartServerBranchRequestSetConfigOptionDict')
 
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')
284
526
request_handlers.register_lazy(
285
527
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
286
528
request_handlers.register_lazy(
287
 
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepository')
288
 
request_handlers.register_lazy(
289
 
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir', 'SmartServerRequestInitializeBzrDir')
290
 
request_handlers.register_lazy(
291
 
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBranch')
 
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
    'BzrDir.open_branchV3', 'bzrlib.smart.bzrdir',
 
567
    'SmartServerRequestOpenBranchV3')
292
568
request_handlers.register_lazy(
293
569
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
294
570
request_handlers.register_lazy(
315
591
    'readv', 'bzrlib.smart.vfs', 'ReadvRequest')
316
592
request_handlers.register_lazy(
317
593
    'rename', 'bzrlib.smart.vfs', 'RenameRequest')
 
594
request_handlers.register_lazy(
 
595
    'PackRepository.autopack', 'bzrlib.smart.packrepository',
 
596
    'SmartServerPackRepositoryAutopack')
318
597
request_handlers.register_lazy('Repository.gather_stats',
319
598
                               'bzrlib.smart.repository',
320
599
                               'SmartServerRepositoryGatherStats')
321
 
request_handlers.register_lazy(
322
 
    'Repository.stream_knit_data_for_revisions', 'bzrlib.smart.repository',
323
 
    'SmartServerRepositoryStreamKnitDataForRevisions')
 
600
request_handlers.register_lazy('Repository.get_parent_map',
 
601
                               'bzrlib.smart.repository',
 
602
                               'SmartServerRepositoryGetParentMap')
324
603
request_handlers.register_lazy(
325
604
    'Repository.get_revision_graph', 'bzrlib.smart.repository', 'SmartServerRepositoryGetRevisionGraph')
326
605
request_handlers.register_lazy(
327
606
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
328
607
request_handlers.register_lazy(
 
608
    'Repository.insert_stream', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream')
 
609
request_handlers.register_lazy(
 
610
    'Repository.insert_stream_1.19', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream_1_19')
 
611
request_handlers.register_lazy(
 
612
    'Repository.insert_stream_locked', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStreamLocked')
 
613
request_handlers.register_lazy(
329
614
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
330
615
request_handlers.register_lazy(
331
616
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
332
617
request_handlers.register_lazy(
 
618
    'Repository.set_make_working_trees', 'bzrlib.smart.repository',
 
619
    'SmartServerRepositorySetMakeWorkingTrees')
 
620
request_handlers.register_lazy(
333
621
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
334
622
request_handlers.register_lazy(
 
623
    'Repository.get_rev_id_for_revno', 'bzrlib.smart.repository',
 
624
    'SmartServerRepositoryGetRevIdForRevno')
 
625
request_handlers.register_lazy(
 
626
    'Repository.get_stream', 'bzrlib.smart.repository',
 
627
    'SmartServerRepositoryGetStream')
 
628
request_handlers.register_lazy(
 
629
    'Repository.get_stream_1.19', 'bzrlib.smart.repository',
 
630
    'SmartServerRepositoryGetStream_1_19')
 
631
request_handlers.register_lazy(
335
632
    'Repository.tarball', 'bzrlib.smart.repository',
336
633
    'SmartServerRepositoryTarball')
337
634
request_handlers.register_lazy(
340
637
    'stat', 'bzrlib.smart.vfs', 'StatRequest')
341
638
request_handlers.register_lazy(
342
639
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
343
 
request_handlers.register_lazy(
344
 
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')