~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/__init__.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-20 12:19:29 UTC
  • mfrom: (6437.23.11 2.5)
  • mto: (6581.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6582.
  • Revision ID: jelmer@samba.org-20120220121929-7ni2psvjoatm1yp4
Merge bzr/2.5.

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
282
286
        self.transport.append_bytes(self.relpath, bytes)
283
287
 
284
288
 
 
289
class TransportHooks(hooks.Hooks):
 
290
    """Mapping of hook names to registered callbacks for transport hooks"""
 
291
    def __init__(self):
 
292
        super(TransportHooks, self).__init__()
 
293
        self.add_hook("post_connect",
 
294
            "Called after a new connection is established or a reconnect "
 
295
            "occurs. The sole argument passed is either the connected "
 
296
            "transport or smart medium instance.", (2, 5))
 
297
 
 
298
 
285
299
class Transport(object):
286
300
    """This class encapsulates methods for retrieving or putting a file
287
301
    from/to a storage location.
306
320
    #       where the biggest benefit between combining reads and
307
321
    #       and seeking is. Consider a runtime auto-tune.
308
322
    _bytes_to_read_before_seek = 0
 
323
    
 
324
    hooks = TransportHooks()
309
325
 
310
326
    def __init__(self, base):
311
327
        super(Transport, self).__init__()
312
328
        self.base = base
313
 
        self._segment_parameters = urlutils.split_segment_parameters(
314
 
            base.rstrip("/"))[1]
 
329
        (self._raw_base, self._segment_parameters) = (
 
330
            urlutils.split_segment_parameters(base))
315
331
 
316
332
    def _translate_error(self, e, path, raise_generic=True):
317
333
        """Translate an IOError or OSError into an appropriate bzr error.
322
338
            if e.errno in (errno.ENOENT, errno.ENOTDIR):
323
339
                raise errors.NoSuchFile(path, extra=e)
324
340
            elif e.errno == errno.EINVAL:
325
 
                mutter("EINVAL returned on path %s: %s" % (path, e))
 
341
                mutter("EINVAL returned on path %s: %r" % (path, e))
326
342
                raise errors.NoSuchFile(path, extra=e)
327
343
            # I would rather use errno.EFOO, but there doesn't seem to be
328
344
            # any matching for 267
348
364
        """
349
365
        raise NotImplementedError(self.clone)
350
366
 
351
 
    def create_prefix(self):
 
367
    def create_prefix(self, mode=None):
352
368
        """Create all the directories leading down to self.base."""
353
369
        cur_transport = self
354
370
        needed = [cur_transport]
360
376
                    "Failed to create path prefix for %s."
361
377
                    % cur_transport.base)
362
378
            try:
363
 
                new_transport.mkdir('.')
 
379
                new_transport.mkdir('.', mode=mode)
364
380
            except errors.NoSuchFile:
365
381
                needed.append(new_transport)
366
382
                cur_transport = new_transport
371
387
        # Now we only need to create child directories
372
388
        while needed:
373
389
            cur_transport = needed.pop()
374
 
            cur_transport.ensure_base()
 
390
            cur_transport.ensure_base(mode=mode)
375
391
 
376
 
    def ensure_base(self):
 
392
    def ensure_base(self, mode=None):
377
393
        """Ensure that the directory this transport references exists.
378
394
 
379
395
        This will create a directory if it doesn't exist.
383
399
        # than permission". We attempt to create the directory, and just
384
400
        # suppress FileExists and PermissionDenied (for Windows) exceptions.
385
401
        try:
386
 
            self.mkdir('.')
 
402
            self.mkdir('.', mode=mode)
387
403
        except (errors.FileExists, errors.PermissionDenied):
388
404
            return False
389
405
        else:
416
432
        """
417
433
        return self._segment_parameters
418
434
 
 
435
    def set_segment_parameter(self, name, value):
 
436
        """Set a segment parameter.
 
437
 
 
438
        :param name: Segment parameter name (urlencoded string)
 
439
        :param value: Segment parameter value (urlencoded string)
 
440
        """
 
441
        if value is None:
 
442
            try:
 
443
                del self._segment_parameters[name]
 
444
            except KeyError:
 
445
                pass
 
446
        else:
 
447
            self._segment_parameters[name] = value
 
448
        self.base = urlutils.join_segment_parameters(
 
449
            self._raw_base, self._segment_parameters)
 
450
 
419
451
    def _pump(self, from_file, to_file):
420
452
        """Most children will need to copy from one file-like
421
453
        object or string to another one.
1399
1431
 
1400
1432
        :return: The corresponding URL.
1401
1433
        """
1402
 
        netloc = urllib.quote(host)
 
1434
        netloc = urlutils.quote(host)
1403
1435
        if user is not None:
1404
1436
            # Note that we don't put the password back even if we
1405
1437
            # have one so that it doesn't get accidentally
1406
1438
            # exposed.
1407
 
            netloc = '%s@%s' % (urllib.quote(user), netloc)
 
1439
            netloc = '%s@%s' % (urlutils.quote(user), netloc)
1408
1440
        if port is not None:
1409
1441
            netloc = '%s:%d' % (netloc, port)
1410
1442
        path = urlutils.escape(path)
1479
1511
        """
1480
1512
        self._shared_connection.connection = connection
1481
1513
        self._shared_connection.credentials = credentials
 
1514
        for hook in self.hooks["post_connect"]:
 
1515
            hook(self)
1482
1516
 
1483
1517
    def _get_connection(self):
1484
1518
        """Returns the transport specific connection object."""
1748
1782
                 help="Read-only access of branches exported on the web.")
1749
1783
register_transport_proto('https://',
1750
1784
            help="Read-only access of branches exported on the web using SSL.")
1751
 
# The default http implementation is urllib, but https is pycurl if available
 
1785
# The default http implementation is urllib, but https uses pycurl if available
1752
1786
register_lazy_transport('http://', 'bzrlib.transport.http._pycurl',
1753
1787
                        'PyCurlTransport')
1754
1788
register_lazy_transport('http://', 'bzrlib.transport.http._urllib',