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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
17
"""Transport is an abstraction layer to handle file access.
18
19
The abstraction is to allow access from the local filesystem, as well
19
20
as remote (such as http or sftp).
22
Transports are constructed from a string, being a URL or (as a degenerate
23
case) a local filesystem path. This is typically the top directory of
24
a bzrdir, repository, or similar object we are interested in working with.
25
The Transport returned has methods to read, write and manipulate files within
27
34
from unittest import TestSuite
30
from bzrlib.trace import mutter
37
from bzrlib.trace import mutter, warning
31
38
import bzrlib.errors as errors
39
from bzrlib.errors import DependencyNotPresent
40
from bzrlib.symbol_versioning import *
42
# {prefix: [transport_classes]}
43
# Transports are inserted onto the list LIFO and tried in order; as a result
44
# transports provided by plugins are tried first, which is usually what we
33
46
_protocol_handlers = {
36
def register_transport(prefix, klass, override=True):
49
def register_transport(prefix, klass, override=DEPRECATED_PARAMETER):
50
"""Register a transport that can be used to open URLs
52
Normally you should use register_lazy_transport, which defers loading the
53
implementation until it's actually used, and so avoids pulling in possibly
54
large implementation libraries.
56
# Note that this code runs very early in library setup -- trace may not be
37
58
global _protocol_handlers
38
# trace messages commented out because they're typically
39
# run during import before trace is set up
40
if _protocol_handlers.has_key(prefix):
42
## mutter('overriding transport: %s => %s' % (prefix, klass.__name__))
43
_protocol_handlers[prefix] = klass
45
## mutter('registering transport: %s => %s' % (prefix, klass.__name__))
46
_protocol_handlers[prefix] = klass
59
if deprecated_passed(override):
60
warn("register_transport(override) is deprecated")
61
_protocol_handlers.setdefault(prefix, []).insert(0, klass)
64
def register_lazy_transport(scheme, module, classname):
65
"""Register lazy-loaded transport class.
67
When opening a URL with the given scheme, load the module and then
68
instantiate the particular class.
70
If the module raises DependencyNotPresent when it's imported, it is
71
skipped and another implementation of the protocol is tried. This is
72
intended to be used when the implementation depends on an external
73
implementation that may not be present. If any other error is raised, it
74
propagates up and the attempt to open the url fails.
76
# TODO: If no implementation of a protocol is available because of missing
77
# dependencies, we should perhaps show the message about what dependency
80
mod = __import__(module, globals(), locals(), [classname])
81
klass = getattr(mod, classname)
83
_loader.module = module
84
register_transport(scheme, _loader)
49
87
def _get_protocol_handlers():
50
"""Return a dictionary of prefix:transport-factories."""
88
"""Return a dictionary of {urlprefix: [factory]}"""
51
89
return _protocol_handlers
60
98
_protocol_handlers = new_handlers
101
def _clear_protocol_handlers():
102
global _protocol_handlers
103
_protocol_handlers = {}
63
106
def _get_transport_modules():
64
107
"""Return a list of the modules providing transports."""
66
for prefix, factory in _protocol_handlers.items():
67
if factory.__module__ == "bzrlib.transport":
68
# this is a lazy load transport, because no real ones
69
# are directlry in bzrlib.transport
70
modules.add(factory.module)
72
modules.add(factory.__module__)
109
for prefix, factory_list in _protocol_handlers.items():
110
for factory in factory_list:
111
if factory.__module__ == "bzrlib.transport":
112
# this is a lazy load transport, because no real ones
113
# are directlry in bzrlib.transport
114
modules.add(factory.module)
116
modules.add(factory.__module__)
73
117
result = list(modules)
333
377
def mkdir(self, relpath, mode=None):
334
378
"""Create a directory at the given path."""
335
raise NotImplementedError
379
raise NotImplementedError(self.mkdir)
337
381
def mkdir_multi(self, relpaths, mode=None, pb=None):
338
382
"""Create a group of directories"""
465
509
# This is not implemented, because you need to do special tricks to
466
510
# extract the basename, and add it to rel_to
467
raise NotImplementedError
511
raise NotImplementedError(self.move_multi_to)
469
513
def delete(self, relpath):
470
514
"""Delete the item at relpath"""
471
raise NotImplementedError
515
raise NotImplementedError(self.delete)
473
517
def delete_multi(self, relpaths, pb=None):
474
518
"""Queue up a bunch of deletes to be done.
570
614
base is either a URL or a directory name.
616
# TODO: give a better error if base looks like a url but there's no
617
# handler for the scheme?
572
618
global _protocol_handlers
576
622
base = unicode(base)
577
for proto, klass in _protocol_handlers.iteritems():
623
for proto, factory_list in _protocol_handlers.iteritems():
578
624
if proto is not None and base.startswith(proto):
580
# The default handler is the filesystem handler
581
# which has a lookup of None
582
return _protocol_handlers[None](base)
585
def register_lazy_transport(scheme, module, classname):
586
"""Register lazy-loaded transport class.
588
When opening a URL with the given scheme, load the module and then
589
instantiate the particular class.
592
mod = __import__(module, globals(), locals(), [classname])
593
klass = getattr(mod, classname)
595
_loader.module = module
596
register_transport(scheme, _loader)
625
t = _try_transport_factories(base, factory_list)
628
# The default handler is the filesystem handler, stored as protocol None
629
return _try_transport_factories(base, _protocol_handlers[None])
632
def _try_transport_factories(base, factory_list):
633
for factory in factory_list:
636
except DependencyNotPresent, e:
637
mutter("failed to instantiate transport %r for %r: %r" %
599
643
def urlescape(relpath):
712
760
register_lazy_transport(None, 'bzrlib.transport.local', 'LocalTransport')
713
761
register_lazy_transport('file://', 'bzrlib.transport.local', 'LocalTransport')
714
762
register_lazy_transport('sftp://', 'bzrlib.transport.sftp', 'SFTPTransport')
715
register_lazy_transport('http://', 'bzrlib.transport.http', 'HttpTransport')
716
register_lazy_transport('https://', 'bzrlib.transport.http', 'HttpTransport')
763
register_lazy_transport('http+urllib://', 'bzrlib.transport.http._urllib',
764
'HttpTransport_urllib')
765
register_lazy_transport('https+urllib://', 'bzrlib.transport.http._urllib',
766
'HttpTransport_urllib')
767
register_lazy_transport('http+pycurl://', 'bzrlib.transport.http._pycurl',
769
register_lazy_transport('https+pycurl://', 'bzrlib.transport.http._pycurl',
771
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',
772
'HttpTransport_urllib')
773
register_lazy_transport('https://', 'bzrlib.transport.http._urllib',
774
'HttpTransport_urllib')
775
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
776
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
717
777
register_lazy_transport('ftp://', 'bzrlib.transport.ftp', 'FtpTransport')
718
778
register_lazy_transport('aftp://', 'bzrlib.transport.ftp', 'FtpTransport')
719
779
register_lazy_transport('memory:/', 'bzrlib.transport.memory', 'MemoryTransport')