~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/__init__.py

  • Committer: Patch Queue Manager
  • Date: 2015-12-17 18:39:00 UTC
  • mfrom: (6606.1.2 fix-float)
  • Revision ID: pqm@pqm.ubuntu.com-20151217183900-0719du2uv1kwu3lc
(vila) Inline testtools private method to fix an issue in xenial (the
 private implementation has changed in an backward incompatible way).
 (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
it.
27
27
"""
28
28
 
 
29
from __future__ import absolute_import
 
30
 
29
31
from cStringIO import StringIO
30
32
import sys
31
33
 
33
35
lazy_import(globals(), """
34
36
import errno
35
37
from stat import S_ISDIR
36
 
import urllib
37
38
import urlparse
38
39
 
39
40
from bzrlib import (
51
52
from bzrlib.trace import (
52
53
    mutter,
53
54
    )
54
 
from bzrlib import registry
 
55
from bzrlib import (
 
56
    hooks,
 
57
    registry,
 
58
    )
55
59
 
56
60
 
57
61
# a dictionary of open file streams. Keys are absolute paths, values are
134
138
def register_lazy_transport(prefix, module, classname):
135
139
    if not prefix in transport_list_registry:
136
140
        register_transport_proto(prefix)
137
 
    transport_list_registry.register_lazy_transport_provider(prefix, module, classname)
138
 
 
139
 
 
140
 
def register_transport(prefix, klass, override=DEPRECATED_PARAMETER):
 
141
    transport_list_registry.register_lazy_transport_provider(
 
142
        prefix, module, classname)
 
143
 
 
144
 
 
145
def register_transport(prefix, klass):
141
146
    if not prefix in transport_list_registry:
142
147
        register_transport_proto(prefix)
143
148
    transport_list_registry.register_transport_provider(prefix, klass)
282
287
        self.transport.append_bytes(self.relpath, bytes)
283
288
 
284
289
 
 
290
class TransportHooks(hooks.Hooks):
 
291
    """Mapping of hook names to registered callbacks for transport hooks"""
 
292
    def __init__(self):
 
293
        super(TransportHooks, self).__init__()
 
294
        self.add_hook("post_connect",
 
295
            "Called after a new connection is established or a reconnect "
 
296
            "occurs. The sole argument passed is either the connected "
 
297
            "transport or smart medium instance.", (2, 5))
 
298
 
 
299
 
285
300
class Transport(object):
286
301
    """This class encapsulates methods for retrieving or putting a file
287
302
    from/to a storage location.
306
321
    #       where the biggest benefit between combining reads and
307
322
    #       and seeking is. Consider a runtime auto-tune.
308
323
    _bytes_to_read_before_seek = 0
 
324
    
 
325
    hooks = TransportHooks()
309
326
 
310
327
    def __init__(self, base):
311
328
        super(Transport, self).__init__()
312
329
        self.base = base
313
 
        self._segment_parameters = urlutils.split_segment_parameters(base)[1]
 
330
        (self._raw_base, self._segment_parameters) = (
 
331
            urlutils.split_segment_parameters(base))
314
332
 
315
333
    def _translate_error(self, e, path, raise_generic=True):
316
334
        """Translate an IOError or OSError into an appropriate bzr error.
347
365
        """
348
366
        raise NotImplementedError(self.clone)
349
367
 
350
 
    def create_prefix(self):
 
368
    def create_prefix(self, mode=None):
351
369
        """Create all the directories leading down to self.base."""
352
370
        cur_transport = self
353
371
        needed = [cur_transport]
359
377
                    "Failed to create path prefix for %s."
360
378
                    % cur_transport.base)
361
379
            try:
362
 
                new_transport.mkdir('.')
 
380
                new_transport.mkdir('.', mode=mode)
363
381
            except errors.NoSuchFile:
364
382
                needed.append(new_transport)
365
383
                cur_transport = new_transport
370
388
        # Now we only need to create child directories
371
389
        while needed:
372
390
            cur_transport = needed.pop()
373
 
            cur_transport.ensure_base()
 
391
            cur_transport.ensure_base(mode=mode)
374
392
 
375
 
    def ensure_base(self):
 
393
    def ensure_base(self, mode=None):
376
394
        """Ensure that the directory this transport references exists.
377
395
 
378
396
        This will create a directory if it doesn't exist.
382
400
        # than permission". We attempt to create the directory, and just
383
401
        # suppress FileExists and PermissionDenied (for Windows) exceptions.
384
402
        try:
385
 
            self.mkdir('.')
 
403
            self.mkdir('.', mode=mode)
386
404
        except (errors.FileExists, errors.PermissionDenied):
387
405
            return False
388
406
        else:
415
433
        """
416
434
        return self._segment_parameters
417
435
 
 
436
    def set_segment_parameter(self, name, value):
 
437
        """Set a segment parameter.
 
438
 
 
439
        :param name: Segment parameter name (urlencoded string)
 
440
        :param value: Segment parameter value (urlencoded string)
 
441
        """
 
442
        if value is None:
 
443
            try:
 
444
                del self._segment_parameters[name]
 
445
            except KeyError:
 
446
                pass
 
447
        else:
 
448
            self._segment_parameters[name] = value
 
449
        self.base = urlutils.join_segment_parameters(
 
450
            self._raw_base, self._segment_parameters)
 
451
 
418
452
    def _pump(self, from_file, to_file):
419
453
        """Most children will need to copy from one file-like
420
454
        object or string to another one.
1398
1432
 
1399
1433
        :return: The corresponding URL.
1400
1434
        """
1401
 
        netloc = urllib.quote(host)
 
1435
        netloc = urlutils.quote(host)
1402
1436
        if user is not None:
1403
1437
            # Note that we don't put the password back even if we
1404
1438
            # have one so that it doesn't get accidentally
1405
1439
            # exposed.
1406
 
            netloc = '%s@%s' % (urllib.quote(user), netloc)
 
1440
            netloc = '%s@%s' % (urlutils.quote(user), netloc)
1407
1441
        if port is not None:
1408
1442
            netloc = '%s:%d' % (netloc, port)
1409
1443
        path = urlutils.escape(path)
1478
1512
        """
1479
1513
        self._shared_connection.connection = connection
1480
1514
        self._shared_connection.credentials = credentials
 
1515
        for hook in self.hooks["post_connect"]:
 
1516
            hook(self)
1481
1517
 
1482
1518
    def _get_connection(self):
1483
1519
        """Returns the transport specific connection object."""
1747
1783
                 help="Read-only access of branches exported on the web.")
1748
1784
register_transport_proto('https://',
1749
1785
            help="Read-only access of branches exported on the web using SSL.")
1750
 
# The default http implementation is urllib, but https is pycurl if available
 
1786
# The default http implementation is urllib
1751
1787
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl',
1752
1788
                        'PyCurlTransport')
1753
1789
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',
1754
1790
                        'HttpTransport_urllib')
 
1791
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl',
 
1792
                        'PyCurlTransport')
1755
1793
register_lazy_transport('https://', 'bzrlib.transport.http._urllib',
1756
1794
                        'HttpTransport_urllib')
1757
 
register_lazy_transport('https://', 'bzrlib.transport.http._pycurl',
1758
 
                        'PyCurlTransport')
1759
1795
 
1760
1796
register_transport_proto('ftp://', help="Access using passive FTP.")
1761
1797
register_lazy_transport('ftp://', 'bzrlib.transport.ftp', 'FtpTransport')