125
125
self.get(key).insert(0, registry._ObjectGetter(obj))
127
127
def register_lazy_transport_provider(self, key, module_name, member_name):
128
self.get(key).insert(0,
128
self.get(key).insert(0,
129
129
registry._LazyObjectGetter(module_name, member_name))
131
def register_transport(self, key, help=None, info=None):
132
self.register(key, [], help, info)
131
def register_transport(self, key, help=None, default_port=None):
132
self.register(key, [], help, default_port)
134
134
def set_default_transport(self, key=None):
135
135
"""Return either 'key' or the default key if key is None"""
136
136
self._default_key = key
139
transport_list_registry = TransportListRegistry( )
142
def register_transport_proto(prefix, help=None, info=None):
143
transport_list_registry.register_transport(prefix, help, info)
138
def get_default_port(self, scheme):
139
"""Return the registered default port for this protocol scheme."""
141
return self.get_info(scheme + '://')
146
transport_list_registry = TransportListRegistry()
149
def register_transport_proto(prefix, help=None, info=None, default_port=None):
150
transport_list_registry.register_transport(prefix, help, default_port)
146
153
def register_lazy_transport(prefix, module, classname):
407
414
assert not isinstance(from_file, basestring), \
408
415
'_pump should only be called on files not %s' % (type(from_file,))
409
osutils.pumpfile(from_file, to_file)
416
return osutils.pumpfile(from_file, to_file)
411
418
def _get_total(self, multi):
412
419
"""Try to figure out how many entries are in multi,
636
643
raise errors.NoSmartMedium(self)
638
def readv(self, relpath, offsets):
639
"""Get parts of the file at the given relative path.
641
:offsets: A list of (offset, size) tuples.
645
def readv(self, relpath, offsets, adjust_for_latency=False,
647
"""Get parts of the file at the given relative path.
649
:param relpath: The path to read data from.
650
:param offsets: A list of (offset, size) tuples.
651
:param adjust_for_latency: Adjust the requested offsets to accomdate
652
transport latency. This may re-order the offsets, expand them to
653
grab adjacent data when there is likely a high cost to requesting
654
data relative to delivering it.
655
:param upper_limit: When adjust_for_latency is True setting upper_limit
656
allows the caller to tell the transport about the length of the
657
file, so that requests are not issued for ranges beyond the end of
658
the file. This matters because some servers and/or transports error
659
in such a case rather than just satisfying the available ranges.
660
upper_limit should always be provided when adjust_for_latency is
661
True, and should be the size of the file in bytes.
662
:return: A list or generator of (offset, data) tuples
664
if adjust_for_latency:
665
offsets = sorted(offsets)
666
# short circuit empty requests
667
if len(offsets) == 0:
669
# Quick thunk to stop this function becoming a generator
670
# itself, rather we return a generator that has nothing to
674
return empty_yielder()
675
# expand by page size at either end
676
expansion = self.recommended_page_size()
677
reduction = expansion / 2
679
for offset, length in offsets:
680
new_offset = offset - reduction
681
new_length = length + expansion
683
# don't ask for anything < 0
684
new_length -= new_offset
686
if (upper_limit is not None and
687
new_offset + new_length > upper_limit):
688
new_length = upper_limit - new_offset
689
new_offsets.append((new_offset, new_length))
690
# combine the expanded offsets
692
current_offset, current_length = new_offsets[0]
693
current_finish = current_length + current_offset
694
for offset, length in new_offsets[1:]:
695
if offset > current_finish:
696
offsets.append((current_offset, current_length))
697
current_offset = offset
698
current_length = length
700
finish = offset + length
701
if finish > current_finish:
702
current_finish = finish
703
offsets.append((current_offset, current_length))
704
return self._readv(relpath, offsets)
706
def _readv(self, relpath, offsets):
707
"""Get parts of the file at the given relative path.
709
:param relpath: The path to read.
710
:param offsets: A list of (offset, size) tuples.
642
711
:return: A list or generator of (offset, data) tuples
1285
1359
# have one so that it doesn't get accidentally
1287
1361
netloc = '%s@%s' % (urllib.quote(user), netloc)
1288
if port is not None:
1362
if (port is not None and
1363
port != transport_list_registry.get_default_port(scheme)):
1364
# Include the port in the netloc (unless it's the same as the
1365
# default, in which case we omit it as it is redundant).
1289
1366
netloc = '%s:%d' % (netloc, port)
1290
1367
path = urllib.quote(path)
1291
1368
return urlparse.urlunparse((scheme, netloc, path, None, None, None))
1594
1671
raise NotImplementedError
1597
class TransportLogger(object):
1598
"""Adapt a transport to get clear logging data on api calls.
1600
Feel free to extend to log whatever calls are of interest.
1603
def __init__(self, adapted):
1604
self._adapted = adapted
1607
def get(self, name):
1608
self._calls.append((name,))
1609
return self._adapted.get(name)
1611
def __getattr__(self, name):
1612
"""Thunk all undefined access through to self._adapted."""
1613
# raise AttributeError, name
1614
return getattr(self._adapted, name)
1616
def readv(self, name, offsets):
1617
self._calls.append((name, offsets))
1618
return self._adapted.readv(name, offsets)
1621
1674
# None is the default transport, for things with no url scheme
1622
1675
register_transport_proto('file://',
1623
1676
help="Access using the standard filesystem (default)")
1625
1678
transport_list_registry.set_default_transport("file://")
1627
1680
register_transport_proto('sftp://',
1628
help="Access using SFTP (most SSH servers provide SFTP).")
1681
help="Access using SFTP (most SSH servers provide SFTP).",
1629
1683
register_lazy_transport('sftp://', 'bzrlib.transport.sftp', 'SFTPTransport')
1630
1684
# Decorated http transport
1631
1685
register_transport_proto('http+urllib://',
1632
1686
# help="Read-only access of branches exported on the web."
1634
1688
register_lazy_transport('http+urllib://', 'bzrlib.transport.http._urllib',
1635
1689
'HttpTransport_urllib')
1636
1690
register_transport_proto('https+urllib://',
1637
1691
# help="Read-only access of branches exported on the web using SSL."
1639
1693
register_lazy_transport('https+urllib://', 'bzrlib.transport.http._urllib',
1640
1694
'HttpTransport_urllib')
1641
1695
register_transport_proto('http+pycurl://',
1642
1696
# help="Read-only access of branches exported on the web."
1644
1698
register_lazy_transport('http+pycurl://', 'bzrlib.transport.http._pycurl',
1645
1699
'PyCurlTransport')
1646
1700
register_transport_proto('https+pycurl://',
1647
1701
# help="Read-only access of branches exported on the web using SSL."
1649
1703
register_lazy_transport('https+pycurl://', 'bzrlib.transport.http._pycurl',
1650
1704
'PyCurlTransport')
1651
1705
# Default http transports (last declared wins (if it can be imported))
1652
1706
register_transport_proto('http://',
1653
help="Read-only access of branches exported on the web.")
1707
help="Read-only access of branches exported on the web.",
1654
1709
register_transport_proto('https://',
1655
help="Read-only access of branches exported on the web using SSL.")
1710
help="Read-only access of branches exported on the web using SSL.",
1656
1712
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',
1657
1713
'HttpTransport_urllib')
1658
1714
register_lazy_transport('https://', 'bzrlib.transport.http._urllib',
1661
1717
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl', 'PyCurlTransport')
1663
1719
register_transport_proto('ftp://',
1664
help="Access using passive FTP.")
1720
help="Access using passive FTP.",
1665
1722
register_lazy_transport('ftp://', 'bzrlib.transport.ftp', 'FtpTransport')
1666
1723
register_transport_proto('aftp://',
1667
help="Access using active FTP.")
1724
help="Access using active FTP.",
1668
1726
register_lazy_transport('aftp://', 'bzrlib.transport.ftp', 'FtpTransport')
1670
1728
register_transport_proto('memory://')
1671
1729
register_lazy_transport('memory://', 'bzrlib.transport.memory', 'MemoryTransport')
1731
# chroots cannot be implicitly accessed, they must be explicitly created:
1672
1732
register_transport_proto('chroot+')
1674
1734
register_transport_proto('readonly+',
1679
1739
register_transport_proto('fakenfs+')
1680
1740
register_lazy_transport('fakenfs+', 'bzrlib.transport.fakenfs', 'FakeNFSTransportDecorator')
1742
register_transport_proto('trace+')
1743
register_lazy_transport('trace+', 'bzrlib.transport.trace', 'TransportTraceDecorator')
1682
1745
register_transport_proto('unlistable+')
1683
1746
register_lazy_transport('unlistable+', 'bzrlib.transport.unlistable', 'UnlistableTransportDecorator')
1691
1754
'bzrlib.transport.fakevfat',
1692
1755
'FakeVFATTransportDecorator')
1693
1756
register_transport_proto('bzr://',
1694
help="Fast access using the Bazaar smart server.")
1757
help="Fast access using the Bazaar smart server.",
1696
1760
register_lazy_transport('bzr://',
1697
1761
'bzrlib.transport.remote',
1698
1762
'RemoteTCPTransport')
1699
1763
register_transport_proto('bzr+http://',
1700
1764
# help="Fast access using the Bazaar smart server over HTTP."
1766
register_lazy_transport('bzr+http://',
1767
'bzrlib.transport.remote',
1768
'RemoteHTTPTransport')
1769
register_transport_proto('bzr+https://',
1770
# help="Fast access using the Bazaar smart server over HTTPS."
1702
register_lazy_transport('bzr+http://',
1772
register_lazy_transport('bzr+https://',
1703
1773
'bzrlib.transport.remote',
1704
1774
'RemoteHTTPTransport')
1705
1775
register_transport_proto('bzr+ssh://',
1706
help="Fast access using the Bazaar smart server over SSH.")
1776
help="Fast access using the Bazaar smart server over SSH.",
1707
1778
register_lazy_transport('bzr+ssh://',
1708
1779
'bzrlib.transport.remote',
1709
1780
'RemoteSSHTransport')