~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/__init__.py

Merge Goffredo's urlspec help patch and tweak the NEWS entries.

Show diffs side-by-side

added added

removed removed

Lines of Context:
63
63
    mutter,
64
64
    warning,
65
65
    )
66
 
 
67
 
# {prefix: [transport_classes]}
68
 
# Transports are inserted onto the list LIFO and tried in order; as a result
69
 
# transports provided by plugins are tried first, which is usually what we
70
 
# want.
71
 
_protocol_handlers = {
72
 
}
73
 
 
74
 
def register_transport(prefix, klass, override=DEPRECATED_PARAMETER):
75
 
    """Register a transport that can be used to open URLs
76
 
 
77
 
    Normally you should use register_lazy_transport, which defers loading the
78
 
    implementation until it's actually used, and so avoids pulling in possibly
79
 
    large implementation libraries.
80
 
    """
81
 
    # Note that this code runs very early in library setup -- trace may not be
82
 
    # working, etc.
83
 
    global _protocol_handlers
84
 
    if deprecated_passed(override):
85
 
        warnings.warn("register_transport(override) is deprecated")
86
 
    _protocol_handlers.setdefault(prefix, []).insert(0, klass)
87
 
 
88
 
 
89
 
def register_lazy_transport(scheme, module, classname):
90
 
    """Register lazy-loaded transport class.
91
 
 
92
 
    When opening a URL with the given scheme, load the module and then
93
 
    instantiate the particular class.  
94
 
 
95
 
    If the module raises DependencyNotPresent when it's imported, it is
96
 
    skipped and another implementation of the protocol is tried.  This is
97
 
    intended to be used when the implementation depends on an external
98
 
    implementation that may not be present.  If any other error is raised, it
99
 
    propagates up and the attempt to open the url fails.
100
 
 
101
 
    :param scheme: The url scheme part, eg "ftp://"
102
 
    """
103
 
    # TODO: If no implementation of a protocol is available because of missing
104
 
    # dependencies, we should perhaps show the message about what dependency
105
 
    # was missing.
106
 
    def _loader(base):
107
 
        mod = __import__(module, globals(), locals(), [classname])
108
 
        klass = getattr(mod, classname)
109
 
        return klass(base)
110
 
    _loader.module = module
111
 
    register_transport(scheme, _loader)
112
 
 
113
 
 
114
 
def unregister_transport(scheme, factory):
115
 
    """Unregister a transport."""
116
 
    _protocol_handlers[scheme].remove(factory)
117
 
    if _protocol_handlers[scheme] == []:
118
 
        del _protocol_handlers[scheme]
 
66
from bzrlib import registry
119
67
 
120
68
 
121
69
def _get_protocol_handlers():
122
70
    """Return a dictionary of {urlprefix: [factory]}"""
123
 
    return _protocol_handlers
 
71
    return transport_list_registry
124
72
 
125
73
 
126
74
def _set_protocol_handlers(new_handlers):
128
76
 
129
77
    WARNING this will remove all build in protocols. Use with care.
130
78
    """
131
 
    global _protocol_handlers
132
 
    _protocol_handlers = new_handlers
 
79
    global transport_list_registry
 
80
    transport_list_registry = new_handlers
133
81
 
134
82
 
135
83
def _clear_protocol_handlers():
136
 
    global _protocol_handlers
137
 
    _protocol_handlers = {}
 
84
    global transport_list_registry
 
85
    transport_list_registry = TransportListRegistry()
138
86
 
139
87
 
140
88
def _get_transport_modules():
141
89
    """Return a list of the modules providing transports."""
142
90
    modules = set()
143
 
    for prefix, factory_list in _protocol_handlers.items():
 
91
    for prefix, factory_list in transport_list_registry.iteritems():
144
92
        for factory in factory_list:
145
 
            if factory.__module__ == "bzrlib.transport":
146
 
                # this is a lazy load transport, because no real ones
147
 
                # are directly in bzrlib.transport
148
 
                modules.add(factory.module)
 
93
            if hasattr(factory, "_module_name"):
 
94
                modules.add(factory._module_name)
149
95
            else:
150
 
                modules.add(factory.__module__)
 
96
                modules.add(factory._obj.__module__)
151
97
    # Add chroot directly, because there is not handler registered for it.
152
98
    modules.add('bzrlib.transport.chroot')
153
99
    result = list(modules)
155
101
    return result
156
102
 
157
103
 
 
104
class TransportListRegistry(registry.Registry):
 
105
    """A registry which simplifies tracking available Transports.
 
106
 
 
107
    A registration of a new protocol requires two step:
 
108
    1) register the prefix with the function register_transport( )
 
109
    2) register the protocol provider with the function
 
110
    register_transport_provider( ) ( and the "lazy" variant )
 
111
 
 
112
    This in needed because:
 
113
    a) a single provider can support multple protcol ( like the ftp
 
114
    privider which supports both the ftp:// and the aftp:// protocols )
 
115
    b) a single protocol can have multiple providers ( like the http://
 
116
    protocol which is supported by both the urllib and pycurl privider )
 
117
    """
 
118
 
 
119
    def register_transport_provider(self, key, obj):
 
120
        self.get(key).insert(0, registry._ObjectGetter(obj))
 
121
 
 
122
    def register_lazy_transport_provider(self, key, module_name, member_name):
 
123
        self.get(key).insert(0, 
 
124
                registry._LazyObjectGetter(module_name, member_name))
 
125
 
 
126
    def register_transport(self, key, help=None, info=None):
 
127
        self.register(key, [], help, info)
 
128
 
 
129
    def set_default_transport(self, key=None):
 
130
        """Return either 'key' or the default key if key is None"""
 
131
        self._default_key = key
 
132
 
 
133
 
 
134
transport_list_registry = TransportListRegistry( )
 
135
 
 
136
 
 
137
def register_transport_proto(prefix, help=None, info=None):
 
138
    transport_list_registry.register_transport(prefix, help, info)
 
139
 
 
140
 
 
141
def register_lazy_transport(prefix, module, classname):
 
142
    if not prefix in transport_list_registry:
 
143
        register_transport_proto(prefix)
 
144
    transport_list_registry.register_lazy_transport_provider(prefix, module, classname)
 
145
 
 
146
 
 
147
def register_transport(prefix, klass, override=DEPRECATED_PARAMETER):
 
148
    if not prefix in transport_list_registry:
 
149
        register_transport_proto(prefix)
 
150
    transport_list_registry.register_transport_provider(prefix, klass)
 
151
 
 
152
 
158
153
def register_urlparse_netloc_protocol(protocol):
159
154
    """Ensure that protocol is setup to be used with urlparse netloc parsing."""
160
155
    if protocol not in urlparse.uses_netloc:
161
156
        urlparse.uses_netloc.append(protocol)
162
157
 
163
158
 
 
159
def unregister_transport(scheme, factory):
 
160
    """Unregister a transport."""
 
161
    l = transport_list_registry.get(scheme)
 
162
    for i in l:
 
163
        o = i.get_obj( )
 
164
        if o == factory:
 
165
            transport_list_registry.get(scheme).remove(i)
 
166
            break
 
167
    if len(l) == 0:
 
168
        transport_list_registry.remove(scheme)
 
169
 
 
170
 
 
171
 
164
172
def split_url(url):
165
173
    # TODO: jam 20060606 urls should only be ascii, or they should raise InvalidURL
166
174
    if isinstance(url, unicode):
405
413
        """
406
414
        raise errors.NotLocalUrl(self.abspath(relpath))
407
415
 
 
416
 
408
417
    def has(self, relpath):
409
418
        """Does the file relpath exist?
410
419
        
1019
1028
 
1020
1029
    base is either a URL or a directory name.  
1021
1030
    """
1022
 
    global _protocol_handlers
 
1031
 
1023
1032
    if base is None:
1024
1033
        base = '.'
1025
1034
    last_err = None
1043
1052
        base = convert_path_to_url(base,
1044
1053
            'URLs must be properly escaped (protocol: %s)')
1045
1054
    
1046
 
    for proto, factory_list in _protocol_handlers.iteritems():
 
1055
    for proto, factory_list in transport_list_registry.iteritems():
1047
1056
        if proto is not None and base.startswith(proto):
1048
1057
            t, last_err = _try_transport_factories(base, factory_list)
1049
1058
            if t:
1054
1063
    base = convert_path_to_url(base, 'Unsupported protocol: %s')
1055
1064
 
1056
1065
    # The default handler is the filesystem handler, stored as protocol None
1057
 
    return _try_transport_factories(base, _protocol_handlers[None])[0]
1058
 
 
1059
 
 
 
1066
    return _try_transport_factories(base,
 
1067
                    transport_list_registry.get(None))[0]
 
1068
                                                   
1060
1069
def do_catching_redirections(action, transport, redirected):
1061
1070
    """Execute an action with given transport catching redirections.
1062
1071
 
1103
1112
    last_err = None
1104
1113
    for factory in factory_list:
1105
1114
        try:
1106
 
            return factory(base), None
 
1115
            return factory.get_obj()(base), None
1107
1116
        except errors.DependencyNotPresent, e:
1108
1117
            mutter("failed to instantiate transport %r for %r: %r" %
1109
1118
                    (factory, base, e))
1218
1227
    def readv(self, name, offsets):
1219
1228
        self._calls.append((name, offsets))
1220
1229
        return self._adapted.readv(name, offsets)
1221
 
        
 
1230
 
1222
1231
 
1223
1232
# None is the default transport, for things with no url scheme
1224
 
register_lazy_transport(None, 'bzrlib.transport.local', 'LocalTransport')
 
1233
register_transport_proto('file://',
 
1234
            help="Access using the standard filesystem (default)")
1225
1235
register_lazy_transport('file://', 'bzrlib.transport.local', 'LocalTransport')
 
1236
transport_list_registry.set_default_transport("file://")
 
1237
 
 
1238
register_transport_proto('sftp://',
 
1239
            help="Access using SFTP (most SSH servers provide SFTP).")
1226
1240
register_lazy_transport('sftp://', 'bzrlib.transport.sftp', 'SFTPTransport')
1227
1241
# Decorated http transport
 
1242
register_transport_proto('http+urllib://',
 
1243
#                help="Read-only access of branches exported on the web."
 
1244
            )
1228
1245
register_lazy_transport('http+urllib://', 'bzrlib.transport.http._urllib',
1229
1246
                        'HttpTransport_urllib')
 
1247
register_transport_proto('https+urllib://',
 
1248
#                help="Read-only access of branches exported on the web using SSL."
 
1249
            )
1230
1250
register_lazy_transport('https+urllib://', 'bzrlib.transport.http._urllib',
1231
1251
                        'HttpTransport_urllib')
 
1252
register_transport_proto('http+pycurl://',
 
1253
#                help="Read-only access of branches exported on the web."
 
1254
            )
1232
1255
register_lazy_transport('http+pycurl://', 'bzrlib.transport.http._pycurl',
1233
1256
                        'PyCurlTransport')
 
1257
register_transport_proto('https+pycurl://',
 
1258
#                help="Read-only access of branches exported on the web using SSL."
 
1259
            )
1234
1260
register_lazy_transport('https+pycurl://', 'bzrlib.transport.http._pycurl',
1235
1261
                        'PyCurlTransport')
1236
1262
# Default http transports (last declared wins (if it can be imported))
 
1263
register_transport_proto('http://',
 
1264
            help="Read-only access of branches exported on the web.")
 
1265
register_transport_proto('https://',
 
1266
            help="Read-only access of branches exported on the web using SSL.")
1237
1267
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',
1238
1268
                        'HttpTransport_urllib')
1239
1269
register_lazy_transport('https://', 'bzrlib.transport.http._urllib',
1240
1270
                        'HttpTransport_urllib')
1241
1271
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
1242
1272
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
 
1273
 
 
1274
register_transport_proto('ftp://',
 
1275
            help="Access using passive FTP.")
1243
1276
register_lazy_transport('ftp://', 'bzrlib.transport.ftp', 'FtpTransport')
 
1277
register_transport_proto('aftp://',
 
1278
            help="Access using active FTP.")
1244
1279
register_lazy_transport('aftp://', 'bzrlib.transport.ftp', 'FtpTransport')
 
1280
 
 
1281
register_transport_proto('memory://')
1245
1282
register_lazy_transport('memory://', 'bzrlib.transport.memory', 'MemoryTransport')
 
1283
register_transport_proto('chroot+')
 
1284
 
 
1285
register_transport_proto('readonly+',
 
1286
#              help="This modifier converts any transport to be readonly."
 
1287
            )
1246
1288
register_lazy_transport('readonly+', 'bzrlib.transport.readonly', 'ReadonlyTransportDecorator')
 
1289
register_transport_proto('fakenfs+')
1247
1290
register_lazy_transport('fakenfs+', 'bzrlib.transport.fakenfs', 'FakeNFSTransportDecorator')
 
1291
register_transport_proto('vfat+')
1248
1292
register_lazy_transport('vfat+',
1249
1293
                        'bzrlib.transport.fakevfat',
1250
1294
                        'FakeVFATTransportDecorator')
 
1295
register_transport_proto('bzr://',
 
1296
            help="Fast access using the Bazaar smart server.")
 
1297
 
1251
1298
register_lazy_transport('bzr://',
1252
1299
                        'bzrlib.transport.remote',
1253
1300
                        'RemoteTCPTransport')
 
1301
register_transport_proto('bzr+http://',
 
1302
#                help="Fast access using the Bazaar smart server over HTTP."
 
1303
             )
1254
1304
register_lazy_transport('bzr+http://',
1255
1305
                        'bzrlib.transport.remote',
1256
1306
                        'RemoteHTTPTransport')
 
1307
register_transport_proto('bzr+ssh://',
 
1308
            help="Fast access using the Bazaar smart server over SSH.")
1257
1309
register_lazy_transport('bzr+ssh://',
1258
1310
                        'bzrlib.transport.remote',
1259
1311
                        'RemoteSSHTransport')