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
29
from bzrlib.trace import mutter
36
from bzrlib.trace import mutter, warning
30
37
import bzrlib.errors as errors
38
from bzrlib.errors import DependencyNotPresent
39
from bzrlib.symbol_versioning import *
41
# {prefix: [transport_classes]}
42
# Transports are inserted onto the list LIFO and tried in order; as a result
43
# transports provided by plugins are tried first, which is usually what we
32
45
_protocol_handlers = {
35
def register_transport(prefix, klass, override=True):
48
def register_transport(prefix, klass, override=DEPRECATED_PARAMETER):
49
"""Register a transport that can be used to open URLs
51
Normally you should use register_lazy_transport, which defers loading the
52
implementation until it's actually used, and so avoids pulling in possibly
53
large implementation libraries.
55
# Note that this code runs very early in library setup -- trace may not be
36
57
global _protocol_handlers
37
# trace messages commented out because they're typically
38
# run during import before trace is set up
39
if _protocol_handlers.has_key(prefix):
41
## mutter('overriding transport: %s => %s' % (prefix, klass.__name__))
42
_protocol_handlers[prefix] = klass
44
## mutter('registering transport: %s => %s' % (prefix, klass.__name__))
45
_protocol_handlers[prefix] = klass
58
if deprecated_passed(override):
59
warn("register_transport(override) is deprecated")
60
_protocol_handlers.setdefault(prefix, []).insert(0, klass)
63
def register_lazy_transport(scheme, module, classname):
64
"""Register lazy-loaded transport class.
66
When opening a URL with the given scheme, load the module and then
67
instantiate the particular class.
69
If the module raises DependencyNotPresent when it's imported, it is
70
skipped and another implementation of the protocol is tried. This is
71
intended to be used when the implementation depends on an external
72
implementation that may not be present. If any other error is raised, it
73
propagates up and the attempt to open the url fails.
75
# TODO: If no implementation of a protocol is available because of missing
76
# dependencies, we should perhaps show the message about what dependency
79
mod = __import__(module, globals(), locals(), [classname])
80
klass = getattr(mod, classname)
82
_loader.module = module
83
register_transport(scheme, _loader)
48
86
def _get_protocol_handlers():
49
"""Return a dictionary of prefix:transport-factories."""
87
"""Return a dictionary of {urlprefix: [factory]}"""
50
88
return _protocol_handlers
59
97
_protocol_handlers = new_handlers
100
def _clear_protocol_handlers():
101
global _protocol_handlers
102
_protocol_handlers = {}
62
105
def _get_transport_modules():
63
106
"""Return a list of the modules providing transports."""
65
for prefix, factory in _protocol_handlers.items():
66
if factory.__module__ == "bzrlib.transport":
67
# this is a lazy load transport, because no real ones
68
# are directlry in bzrlib.transport
69
modules.add(factory.module)
71
modules.add(factory.__module__)
108
for prefix, factory_list in _protocol_handlers.items():
109
for factory in factory_list:
110
if factory.__module__ == "bzrlib.transport":
111
# this is a lazy load transport, because no real ones
112
# are directlry in bzrlib.transport
113
modules.add(factory.module)
115
modules.add(factory.__module__)
72
116
result = list(modules)
332
376
def mkdir(self, relpath, mode=None):
333
377
"""Create a directory at the given path."""
334
raise NotImplementedError
378
raise NotImplementedError(self.mkdir)
336
380
def mkdir_multi(self, relpaths, mode=None, pb=None):
337
381
"""Create a group of directories"""
464
508
# This is not implemented, because you need to do special tricks to
465
509
# extract the basename, and add it to rel_to
466
raise NotImplementedError
510
raise NotImplementedError(self.move_multi_to)
468
512
def delete(self, relpath):
469
513
"""Delete the item at relpath"""
470
raise NotImplementedError
514
raise NotImplementedError(self.delete)
472
516
def delete_multi(self, relpaths, pb=None):
473
517
"""Queue up a bunch of deletes to be done.
569
613
base is either a URL or a directory name.
615
# TODO: give a better error if base looks like a url but there's no
616
# handler for the scheme?
571
617
global _protocol_handlers
575
621
base = unicode(base)
576
for proto, klass in _protocol_handlers.iteritems():
622
for proto, factory_list in _protocol_handlers.iteritems():
577
623
if proto is not None and base.startswith(proto):
579
# The default handler is the filesystem handler
580
# which has a lookup of None
581
return _protocol_handlers[None](base)
584
def register_lazy_transport(scheme, module, classname):
585
"""Register lazy-loaded transport class.
587
When opening a URL with the given scheme, load the module and then
588
instantiate the particular class.
591
mod = __import__(module, globals(), locals(), [classname])
592
klass = getattr(mod, classname)
594
_loader.module = module
595
register_transport(scheme, _loader)
624
t = _try_transport_factories(base, factory_list)
627
# The default handler is the filesystem handler, stored as protocol None
628
return _try_transport_factories(base, _protocol_handlers[None])
631
def _try_transport_factories(base, factory_list):
632
for factory in factory_list:
635
except DependencyNotPresent, e:
636
mutter("failed to instantiate transport %r for %r: %r" %
598
642
def urlescape(relpath):
713
761
register_lazy_transport(None, 'bzrlib.transport.local', 'LocalTransport')
714
762
register_lazy_transport('file://', 'bzrlib.transport.local', 'LocalTransport')
715
763
register_lazy_transport('sftp://', 'bzrlib.transport.sftp', 'SFTPTransport')
716
register_lazy_transport('http://', 'bzrlib.transport.http', 'HttpTransport')
717
register_lazy_transport('https://', 'bzrlib.transport.http', 'HttpTransport')
764
register_lazy_transport('http+urllib://', 'bzrlib.transport.http._urllib',
765
'HttpTransport_urllib')
766
register_lazy_transport('https+urllib://', 'bzrlib.transport.http._urllib',
767
'HttpTransport_urllib')
768
register_lazy_transport('http+pycurl://', 'bzrlib.transport.http._pycurl',
770
register_lazy_transport('https+pycurl://', 'bzrlib.transport.http._pycurl',
772
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',
773
'HttpTransport_urllib')
774
register_lazy_transport('https://', 'bzrlib.transport.http._urllib',
775
'HttpTransport_urllib')
776
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
777
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
718
778
register_lazy_transport('ftp://', 'bzrlib.transport.ftp', 'FtpTransport')
719
779
register_lazy_transport('aftp://', 'bzrlib.transport.ftp', 'FtpTransport')
720
780
register_lazy_transport('memory:/', 'bzrlib.transport.memory', 'MemoryTransport')