~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/request.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-09-01 08:02:42 UTC
  • mfrom: (5390.3.3 faster-revert-593560)
  • Revision ID: pqm@pqm.ubuntu.com-20100901080242-esg62ody4frwmy66
(spiv) Avoid repeatedly calling self.target.all_file_ids() in
 InterTree.iter_changes. (Andrew Bennetts)

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.
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).
 
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
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
 
29
34
import tempfile
 
35
import thread
 
36
import threading
30
37
 
31
38
from bzrlib import (
32
39
    bzrdir,
 
40
    debug,
33
41
    errors,
 
42
    osutils,
34
43
    registry,
35
44
    revision,
 
45
    trace,
36
46
    urlutils,
37
47
    )
38
48
from bzrlib.lazy_import import lazy_import
41
51
""")
42
52
 
43
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
 
44
81
class SmartServerRequest(object):
45
82
    """Base class for request handlers.
46
 
    
 
83
 
47
84
    To define a new request, subclass this class and override the `do` method
48
85
    (and if appropriate, `do_body` as well).  Request implementors should take
49
86
    care to call `translate_client_path` and `transport_from_client_path` as
52
89
    # XXX: rename this class to BaseSmartServerRequestHandler ?  A request
53
90
    # *handler* is a different concept to the request.
54
91
 
55
 
    def __init__(self, backing_transport, root_client_path='/'):
 
92
    def __init__(self, backing_transport, root_client_path='/', jail_root=None):
56
93
        """Constructor.
57
94
 
58
95
        :param backing_transport: the base transport to be used when performing
62
99
            from the client.  Clients will not be able to refer to paths above
63
100
            this root.  If root_client_path is None, then no translation will
64
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.
65
104
        """
66
105
        self._backing_transport = backing_transport
 
106
        if jail_root is None:
 
107
            jail_root = backing_transport
 
108
        self._jail_root = jail_root
67
109
        if root_client_path is not None:
68
110
            if not root_client_path.startswith('/'):
69
111
                root_client_path = '/' + root_client_path
78
120
 
79
121
    def do(self, *args):
80
122
        """Mandatory extension point for SmartServerRequest subclasses.
81
 
        
 
123
 
82
124
        Subclasses must implement this.
83
 
        
 
125
 
84
126
        This should return a SmartServerResponse if this command expects to
85
127
        receive no body.
86
128
        """
101
143
        """Called if the client sends a body with the request.
102
144
 
103
145
        The do() method is still called, and must have returned None.
104
 
        
 
146
 
105
147
        Must return a SmartServerResponse.
106
148
        """
107
149
        if body_bytes != '':
119
161
        body_bytes = ''.join(self._body_chunks)
120
162
        self._body_chunks = None
121
163
        return self.do_body(body_bytes)
122
 
    
 
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
 
123
171
    def translate_client_path(self, client_path):
124
172
        """Translate a path received from a network client into a local
125
173
        relpath.
136
184
            return client_path
137
185
        if not client_path.startswith('/'):
138
186
            client_path = '/' + client_path
 
187
        if client_path + '/' == self._root_client_path:
 
188
            return '.'
139
189
        if client_path.startswith(self._root_client_path):
140
190
            path = client_path[len(self._root_client_path):]
141
191
            relpath = urlutils.joinpath('/', path)
142
192
            if not relpath.startswith('/'):
143
193
                raise ValueError(relpath)
144
 
            return '.' + relpath
 
194
            return urlutils.escape('.' + relpath)
145
195
        else:
146
196
            raise errors.PathNotChild(client_path, self._root_client_path)
147
197
 
158
208
 
159
209
class SmartServerResponse(object):
160
210
    """A response to a client request.
161
 
    
 
211
 
162
212
    This base class should not be used. Instead use
163
213
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
164
214
    """
208
258
 
209
259
class SmartServerRequestHandler(object):
210
260
    """Protocol logic for smart server.
211
 
    
 
261
 
212
262
    This doesn't handle serialization at all, it just processes requests and
213
263
    creates responses.
214
264
    """
223
273
    # TODO: Better way of representing the body for commands that take it,
224
274
    # and allow it to be streamed into the server.
225
275
 
226
 
    def __init__(self, backing_transport, commands, root_client_path):
 
276
    def __init__(self, backing_transport, commands, root_client_path,
 
277
        jail_root=None):
227
278
        """Constructor.
228
279
 
229
280
        :param backing_transport: a Transport to handle requests for.
233
284
        self._backing_transport = backing_transport
234
285
        self._root_client_path = root_client_path
235
286
        self._commands = commands
 
287
        if jail_root is None:
 
288
            jail_root = backing_transport
 
289
        self._jail_root = jail_root
236
290
        self.response = None
237
291
        self.finished_reading = False
238
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))
239
314
 
240
315
    def accept_body(self, bytes):
241
316
        """Accept body data."""
 
317
        if self._command is None:
 
318
            # no active command object, so ignore the event.
 
319
            return
242
320
        self._run_handler_code(self._command.do_chunk, (bytes,), {})
243
 
        
 
321
        if 'hpss' in debug.debug_flags:
 
322
            self._trace('accept body',
 
323
                        '%d bytes' % (len(bytes),), bytes)
 
324
 
244
325
    def end_of_body(self):
245
326
        """No more body data will be received."""
246
327
        self._run_handler_code(self._command.do_end, (), {})
247
328
        # cannot read after this.
248
329
        self.finished_reading = True
249
 
 
250
 
    def dispatch_command(self, cmd, args):
251
 
        """Deprecated compatibility method.""" # XXX XXX
252
 
        try:
253
 
            command = self._commands.get(cmd)
254
 
        except LookupError:
255
 
            raise errors.UnknownSmartMethod(cmd)
256
 
        self._command = command(self._backing_transport, self._root_client_path)
257
 
        self._run_handler_code(self._command.execute, args, {})
 
330
        if 'hpss' in debug.debug_flags:
 
331
            self._trace('end of body', '', include_time=True)
258
332
 
259
333
    def _run_handler_code(self, callable, args, kwargs):
260
334
        """Run some handler specific code 'callable'.
276
350
        # XXX: most of this error conversion is VFS-related, and thus ought to
277
351
        # be in SmartServerVFSRequestHandler somewhere.
278
352
        try:
279
 
            return callable(*args, **kwargs)
280
 
        except errors.NoSuchFile, e:
281
 
            return FailedSmartServerResponse(('NoSuchFile', e.path))
282
 
        except errors.FileExists, e:
283
 
            return FailedSmartServerResponse(('FileExists', e.path))
284
 
        except errors.DirectoryNotEmpty, e:
285
 
            return FailedSmartServerResponse(('DirectoryNotEmpty', e.path))
286
 
        except errors.ShortReadvError, e:
287
 
            return FailedSmartServerResponse(('ShortReadvError',
288
 
                e.path, str(e.offset), str(e.length), str(e.actual)))
289
 
        except errors.UnstackableRepositoryFormat, e:
290
 
            return FailedSmartServerResponse(('UnstackableRepositoryFormat',
291
 
                str(e.format), e.url))
292
 
        except errors.UnstackableBranchFormat, e:
293
 
            return FailedSmartServerResponse(('UnstackableBranchFormat',
294
 
                str(e.format), e.url))
295
 
        except errors.NotStacked, e:
296
 
            return FailedSmartServerResponse(('NotStacked',))
297
 
        except UnicodeError, e:
298
 
            # If it is a DecodeError, than most likely we are starting
299
 
            # with a plain string
300
 
            str_or_unicode = e.object
301
 
            if isinstance(str_or_unicode, unicode):
302
 
                # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
303
 
                # byte) in it, so this encoding could cause broken responses.
304
 
                # Newer clients use protocol v3, so will be fine.
305
 
                val = 'u:' + str_or_unicode.encode('utf-8')
306
 
            else:
307
 
                val = 's:' + str_or_unicode.encode('base64')
308
 
            # This handles UnicodeEncodeError or UnicodeDecodeError
309
 
            return FailedSmartServerResponse((e.__class__.__name__,
310
 
                    e.encoding, val, str(e.start), str(e.end), e.reason))
311
 
        except errors.TransportNotPossible, e:
312
 
            if e.msg == "readonly transport":
313
 
                return FailedSmartServerResponse(('ReadOnlyError', ))
314
 
            else:
315
 
                raise
316
 
        except errors.ReadError, e:
317
 
            # cannot read the file
318
 
            return FailedSmartServerResponse(('ReadError', e.path))
319
 
        except errors.PermissionDenied, e:
320
 
            return FailedSmartServerResponse(
321
 
                ('PermissionDenied', e.path, e.extra))
 
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)
322
363
 
323
364
    def headers_received(self, headers):
324
365
        # Just a no-op at the moment.
325
 
        pass
 
366
        if 'hpss' in debug.debug_flags:
 
367
            self._trace('headers', repr(headers))
326
368
 
327
369
    def args_received(self, args):
328
370
        cmd = args[0]
330
372
        try:
331
373
            command = self._commands.get(cmd)
332
374
        except LookupError:
 
375
            if 'hpss' in debug.debug_flags:
 
376
                self._trace('hpss unknown request', 
 
377
                            cmd, repr(args)[1:-1])
333
378
            raise errors.UnknownSmartMethod(cmd)
334
 
        self._command = command(self._backing_transport)
 
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)
335
389
        self._run_handler_code(self._command.execute, args, {})
336
390
 
337
391
    def end_received(self):
 
392
        if self._command is None:
 
393
            # no active command object, so ignore the event.
 
394
            return
338
395
        self._run_handler_code(self._command.do_end, (), {})
 
396
        if 'hpss' in debug.debug_flags:
 
397
            self._trace('end', '', include_time=True)
339
398
 
340
399
    def post_body_error_received(self, error_args):
341
400
        # Just a no-op at the moment.
342
401
        pass
343
402
 
344
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
 
345
454
class HelloRequest(SmartServerRequest):
346
455
    """Answer a version request with the highest protocol version this server
347
456
    supports.
381
490
request_handlers.register_lazy(
382
491
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
383
492
request_handlers.register_lazy(
384
 
    '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')
385
503
request_handlers.register_lazy(
386
504
    'Branch.get_stacked_on_url', 'bzrlib.smart.branch', 'SmartServerBranchRequestGetStackedOnURL')
387
505
request_handlers.register_lazy(
388
506
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
389
507
request_handlers.register_lazy(
390
508
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
391
 
request_handlers.register_lazy(
392
 
    'Branch.revision_history', 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
393
 
request_handlers.register_lazy(
394
 
    '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')
395
517
request_handlers.register_lazy(
396
518
    'Branch.set_last_revision_info', 'bzrlib.smart.branch',
397
519
    'SmartServerBranchRequestSetLastRevisionInfo')
399
521
    'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
400
522
    'SmartServerBranchRequestSetLastRevisionEx')
401
523
request_handlers.register_lazy(
 
524
    'Branch.set_parent_location', 'bzrlib.smart.branch',
 
525
    'SmartServerBranchRequestSetParentLocation')
 
526
request_handlers.register_lazy(
402
527
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
403
528
request_handlers.register_lazy(
404
 
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV1')
405
 
request_handlers.register_lazy(
406
 
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV2')
407
 
request_handlers.register_lazy(
408
 
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir', 'SmartServerRequestInitializeBzrDir')
409
 
request_handlers.register_lazy(
410
 
    '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')
411
568
request_handlers.register_lazy(
412
569
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
413
570
request_handlers.register_lazy(
448
605
request_handlers.register_lazy(
449
606
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
450
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(
451
614
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
452
615
request_handlers.register_lazy(
453
616
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
454
617
request_handlers.register_lazy(
 
618
    'Repository.set_make_working_trees', 'bzrlib.smart.repository',
 
619
    'SmartServerRepositorySetMakeWorkingTrees')
 
620
request_handlers.register_lazy(
455
621
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
456
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(
457
632
    'Repository.tarball', 'bzrlib.smart.repository',
458
633
    'SmartServerRepositoryTarball')
459
634
request_handlers.register_lazy(
462
637
    'stat', 'bzrlib.smart.vfs', 'StatRequest')
463
638
request_handlers.register_lazy(
464
639
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
465
 
request_handlers.register_lazy(
466
 
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')