/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/transport/__init__.py

Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005, 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
58
58
        zero_eight,
59
59
        zero_eleven,
60
60
        )
61
 
from bzrlib.trace import mutter, warning
62
 
 
63
 
# {prefix: [transport_classes]}
64
 
# Transports are inserted onto the list LIFO and tried in order; as a result
65
 
# transports provided by plugins are tried first, which is usually what we
66
 
# want.
67
 
_protocol_handlers = {
68
 
}
69
 
 
70
 
def register_transport(prefix, klass, override=DEPRECATED_PARAMETER):
71
 
    """Register a transport that can be used to open URLs
72
 
 
73
 
    Normally you should use register_lazy_transport, which defers loading the
74
 
    implementation until it's actually used, and so avoids pulling in possibly
75
 
    large implementation libraries.
76
 
    """
77
 
    # Note that this code runs very early in library setup -- trace may not be
78
 
    # working, etc.
79
 
    global _protocol_handlers
80
 
    if deprecated_passed(override):
81
 
        warnings.warn("register_transport(override) is deprecated")
82
 
    _protocol_handlers.setdefault(prefix, []).insert(0, klass)
83
 
 
84
 
 
85
 
def register_lazy_transport(scheme, module, classname):
86
 
    """Register lazy-loaded transport class.
87
 
 
88
 
    When opening a URL with the given scheme, load the module and then
89
 
    instantiate the particular class.  
90
 
 
91
 
    If the module raises DependencyNotPresent when it's imported, it is
92
 
    skipped and another implementation of the protocol is tried.  This is
93
 
    intended to be used when the implementation depends on an external
94
 
    implementation that may not be present.  If any other error is raised, it
95
 
    propagates up and the attempt to open the url fails.
96
 
    """
97
 
    # TODO: If no implementation of a protocol is available because of missing
98
 
    # dependencies, we should perhaps show the message about what dependency
99
 
    # was missing.
100
 
    def _loader(base):
101
 
        mod = __import__(module, globals(), locals(), [classname])
102
 
        klass = getattr(mod, classname)
103
 
        return klass(base)
104
 
    _loader.module = module
105
 
    register_transport(scheme, _loader)
 
61
from bzrlib.trace import (
 
62
    note,
 
63
    mutter,
 
64
    warning,
 
65
    )
 
66
from bzrlib import registry
106
67
 
107
68
 
108
69
def _get_protocol_handlers():
109
70
    """Return a dictionary of {urlprefix: [factory]}"""
110
 
    return _protocol_handlers
 
71
    return transport_list_registry
111
72
 
112
73
 
113
74
def _set_protocol_handlers(new_handlers):
115
76
 
116
77
    WARNING this will remove all build in protocols. Use with care.
117
78
    """
118
 
    global _protocol_handlers
119
 
    _protocol_handlers = new_handlers
 
79
    global transport_list_registry
 
80
    transport_list_registry = new_handlers
120
81
 
121
82
 
122
83
def _clear_protocol_handlers():
123
 
    global _protocol_handlers
124
 
    _protocol_handlers = {}
 
84
    global transport_list_registry
 
85
    transport_list_registry = TransportListRegistry()
125
86
 
126
87
 
127
88
def _get_transport_modules():
128
89
    """Return a list of the modules providing transports."""
129
90
    modules = set()
130
 
    for prefix, factory_list in _protocol_handlers.items():
 
91
    for prefix, factory_list in transport_list_registry.iteritems():
131
92
        for factory in factory_list:
132
 
            if factory.__module__ == "bzrlib.transport":
133
 
                # this is a lazy load transport, because no real ones
134
 
                # are directlry in bzrlib.transport
135
 
                modules.add(factory.module)
 
93
            if hasattr(factory, "_module_name"):
 
94
                modules.add(factory._module_name)
136
95
            else:
137
 
                modules.add(factory.__module__)
 
96
                modules.add(factory._obj.__module__)
 
97
    # Add chroot directly, because there is not handler registered for it.
 
98
    modules.add('bzrlib.transport.chroot')
138
99
    result = list(modules)
139
100
    result.sort()
140
101
    return result
141
102
 
142
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
 
143
153
def register_urlparse_netloc_protocol(protocol):
144
154
    """Ensure that protocol is setup to be used with urlparse netloc parsing."""
145
155
    if protocol not in urlparse.uses_netloc:
146
156
        urlparse.uses_netloc.append(protocol)
147
157
 
148
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
 
149
172
def split_url(url):
150
173
    # TODO: jam 20060606 urls should only be ascii, or they should raise InvalidURL
151
174
    if isinstance(url, unicode):
388
411
        This function will only be defined for Transports which have a
389
412
        physical local filesystem representation.
390
413
        """
391
 
        # TODO: jam 20060426 Should this raise NotLocalUrl instead?
392
 
        raise errors.TransportNotPossible('This is not a LocalTransport,'
393
 
            ' so there is no local representation for a path')
 
414
        raise errors.NotLocalUrl(self.abspath(relpath))
 
415
 
394
416
 
395
417
    def has(self, relpath):
396
418
        """Does the file relpath exist?
603
625
        :param mode: Create the file with the given mode.
604
626
        :return: None
605
627
        """
606
 
        assert isinstance(bytes, str), \
607
 
            'bytes must be a plain string, not %s' % type(bytes)
 
628
        if not isinstance(bytes, str):
 
629
            raise AssertionError(
 
630
                'bytes must be a plain string, not %s' % type(bytes))
608
631
        return self.put_file(relpath, StringIO(bytes), mode=mode)
609
632
 
610
633
    def put_bytes_non_atomic(self, relpath, bytes, mode=None,
625
648
                        create it, and then try again.
626
649
        :param dir_mode: Possible access permissions for new directories.
627
650
        """
628
 
        assert isinstance(bytes, str), \
629
 
            'bytes must be a plain string, not %s' % type(bytes)
 
651
        if not isinstance(bytes, str):
 
652
            raise AssertionError(
 
653
                'bytes must be a plain string, not %s' % type(bytes))
630
654
        self.put_file_non_atomic(relpath, StringIO(bytes), mode=mode,
631
655
                                 create_parent_dir=create_parent_dir,
632
656
                                 dir_mode=dir_mode)
1004
1028
 
1005
1029
    base is either a URL or a directory name.  
1006
1030
    """
1007
 
    # TODO: give a better error if base looks like a url but there's no
1008
 
    # handler for the scheme?
1009
 
    global _protocol_handlers
 
1031
 
1010
1032
    if base is None:
1011
1033
        base = '.'
1012
 
 
1013
1034
    last_err = None
1014
1035
 
1015
1036
    def convert_path_to_url(base, error_str):
1031
1052
        base = convert_path_to_url(base,
1032
1053
            'URLs must be properly escaped (protocol: %s)')
1033
1054
    
1034
 
    for proto, factory_list in _protocol_handlers.iteritems():
 
1055
    for proto, factory_list in transport_list_registry.iteritems():
1035
1056
        if proto is not None and base.startswith(proto):
1036
1057
            t, last_err = _try_transport_factories(base, factory_list)
1037
1058
            if t:
1042
1063
    base = convert_path_to_url(base, 'Unsupported protocol: %s')
1043
1064
 
1044
1065
    # The default handler is the filesystem handler, stored as protocol None
1045
 
    return _try_transport_factories(base, _protocol_handlers[None])[0]
 
1066
    return _try_transport_factories(base,
 
1067
                    transport_list_registry.get(None))[0]
 
1068
                                                   
 
1069
def do_catching_redirections(action, transport, redirected):
 
1070
    """Execute an action with given transport catching redirections.
 
1071
 
 
1072
    This is a facility provided for callers needing to follow redirections
 
1073
    silently. The silence is relative: it is the caller responsability to
 
1074
    inform the user about each redirection or only inform the user of a user
 
1075
    via the exception parameter.
 
1076
 
 
1077
    :param action: A callable, what the caller want to do while catching
 
1078
                  redirections.
 
1079
    :param transport: The initial transport used.
 
1080
    :param redirected: A callable receiving the redirected transport and the 
 
1081
                  RedirectRequested exception.
 
1082
 
 
1083
    :return: Whatever 'action' returns
 
1084
    """
 
1085
    MAX_REDIRECTIONS = 8
 
1086
 
 
1087
    # If a loop occurs, there is little we can do. So we don't try to detect
 
1088
    # them, just getting out if too much redirections occurs. The solution
 
1089
    # is outside: where the loop is defined.
 
1090
    for redirections in range(MAX_REDIRECTIONS):
 
1091
        try:
 
1092
            return action(transport)
 
1093
        except errors.RedirectRequested, e:
 
1094
            redirection_notice = '%s is%s redirected to %s' % (
 
1095
                e.source, e.permanently, e.target)
 
1096
            transport = redirected(transport, e, redirection_notice)
 
1097
    else:
 
1098
        # Loop exited without resolving redirect ? Either the
 
1099
        # user has kept a very very very old reference or a loop
 
1100
        # occurred in the redirections.  Nothing we can cure here:
 
1101
        # tell the user. Note that as the user has been informed
 
1102
        # about each redirection (it is the caller responsibility
 
1103
        # to do that in redirected via the provided
 
1104
        # redirection_notice). The caller may provide more
 
1105
        # information if needed (like what file or directory we
 
1106
        # were trying to act upon when the redirection loop
 
1107
        # occurred).
 
1108
        raise errors.TooManyRedirections
1046
1109
 
1047
1110
 
1048
1111
def _try_transport_factories(base, factory_list):
1049
1112
    last_err = None
1050
1113
    for factory in factory_list:
1051
1114
        try:
1052
 
            return factory(base), None
 
1115
            return factory.get_obj()(base), None
1053
1116
        except errors.DependencyNotPresent, e:
1054
1117
            mutter("failed to instantiate transport %r for %r: %r" %
1055
1118
                    (factory, base, e))
1090
1153
        raise NotImplementedError
1091
1154
 
1092
1155
    def get_bogus_url(self):
1093
 
        """Return a url for this protocol, that will fail to connect."""
 
1156
        """Return a url for this protocol, that will fail to connect.
 
1157
        
 
1158
        This may raise NotImplementedError to indicate that this server cannot
 
1159
        provide bogus urls.
 
1160
        """
1094
1161
        raise NotImplementedError
1095
1162
 
1096
1163
 
1160
1227
    def readv(self, name, offsets):
1161
1228
        self._calls.append((name, offsets))
1162
1229
        return self._adapted.readv(name, offsets)
1163
 
        
 
1230
 
1164
1231
 
1165
1232
# None is the default transport, for things with no url scheme
1166
 
register_lazy_transport(None, 'bzrlib.transport.local', 'LocalTransport')
 
1233
register_transport_proto('file://',
 
1234
            help="Access using the standard filesystem (default)")
1167
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).")
1168
1240
register_lazy_transport('sftp://', 'bzrlib.transport.sftp', 'SFTPTransport')
 
1241
# Decorated http transport
 
1242
register_transport_proto('http+urllib://',
 
1243
#                help="Read-only access of branches exported on the web."
 
1244
            )
1169
1245
register_lazy_transport('http+urllib://', 'bzrlib.transport.http._urllib',
1170
1246
                        'HttpTransport_urllib')
 
1247
register_transport_proto('https+urllib://',
 
1248
#                help="Read-only access of branches exported on the web using SSL."
 
1249
            )
1171
1250
register_lazy_transport('https+urllib://', 'bzrlib.transport.http._urllib',
1172
1251
                        'HttpTransport_urllib')
 
1252
register_transport_proto('http+pycurl://',
 
1253
#                help="Read-only access of branches exported on the web."
 
1254
            )
1173
1255
register_lazy_transport('http+pycurl://', 'bzrlib.transport.http._pycurl',
1174
1256
                        'PyCurlTransport')
 
1257
register_transport_proto('https+pycurl://',
 
1258
#                help="Read-only access of branches exported on the web using SSL."
 
1259
            )
1175
1260
register_lazy_transport('https+pycurl://', 'bzrlib.transport.http._pycurl',
1176
1261
                        'PyCurlTransport')
 
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.")
1177
1267
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',
1178
1268
                        'HttpTransport_urllib')
1179
1269
register_lazy_transport('https://', 'bzrlib.transport.http._urllib',
1180
1270
                        'HttpTransport_urllib')
1181
1271
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
1182
1272
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
 
1273
 
 
1274
register_transport_proto('ftp://',
 
1275
            help="Access using passive FTP.")
1183
1276
register_lazy_transport('ftp://', 'bzrlib.transport.ftp', 'FtpTransport')
 
1277
register_transport_proto('aftp://',
 
1278
            help="Access using active FTP.")
1184
1279
register_lazy_transport('aftp://', 'bzrlib.transport.ftp', 'FtpTransport')
 
1280
 
 
1281
register_transport_proto('memory://')
1185
1282
register_lazy_transport('memory://', 'bzrlib.transport.memory', 'MemoryTransport')
1186
 
register_lazy_transport('chroot+', 'bzrlib.transport.chroot',
1187
 
                        'ChrootTransportDecorator')
 
1283
register_transport_proto('chroot+')
 
1284
 
 
1285
register_transport_proto('readonly+',
 
1286
#              help="This modifier converts any transport to be readonly."
 
1287
            )
1188
1288
register_lazy_transport('readonly+', 'bzrlib.transport.readonly', 'ReadonlyTransportDecorator')
 
1289
register_transport_proto('fakenfs+')
1189
1290
register_lazy_transport('fakenfs+', 'bzrlib.transport.fakenfs', 'FakeNFSTransportDecorator')
 
1291
register_transport_proto('vfat+')
1190
1292
register_lazy_transport('vfat+',
1191
1293
                        'bzrlib.transport.fakevfat',
1192
1294
                        'FakeVFATTransportDecorator')
 
1295
register_transport_proto('bzr://',
 
1296
            help="Fast access using the Bazaar smart server.")
 
1297
 
1193
1298
register_lazy_transport('bzr://',
1194
 
                        'bzrlib.transport.smart',
1195
 
                        'SmartTCPTransport')
 
1299
                        'bzrlib.transport.remote',
 
1300
                        'RemoteTCPTransport')
 
1301
register_transport_proto('bzr+http://',
 
1302
#                help="Fast access using the Bazaar smart server over HTTP."
 
1303
             )
1196
1304
register_lazy_transport('bzr+http://',
1197
 
                        'bzrlib.transport.smart',
1198
 
                        'SmartHTTPTransport')
 
1305
                        'bzrlib.transport.remote',
 
1306
                        'RemoteHTTPTransport')
 
1307
register_transport_proto('bzr+ssh://',
 
1308
            help="Fast access using the Bazaar smart server over SSH.")
1199
1309
register_lazy_transport('bzr+ssh://',
1200
 
                        'bzrlib.transport.smart',
1201
 
                        'SmartSSHTransport')
 
1310
                        'bzrlib.transport.remote',
 
1311
                        'RemoteSSHTransport')