~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/__init__.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2011-08-12 01:42:55 UTC
  • mfrom: (6055.2.12 unparsedurl)
  • Revision ID: pqm@pqm.ubuntu.com-20110812014255-y3thbw6gdn7cw6uz
(jelmer) Add a URL object for manipulating parsed URLs. (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
"""
28
28
 
29
29
from cStringIO import StringIO
30
 
import os
31
30
import sys
32
31
 
33
32
from bzrlib.lazy_import import lazy_import
1364
1363
        """
1365
1364
        if not base.endswith('/'):
1366
1365
            base += '/'
1367
 
        (self._scheme,
1368
 
         self._user, self._password,
1369
 
         self._host, self._port,
1370
 
         self._path) = self._split_url(base)
 
1366
        self._parsed_url = self._split_url(base)
1371
1367
        if _from_transport is not None:
1372
1368
            # Copy the password as it does not appear in base and will be lost
1373
1369
            # otherwise. It can appear in the _split_url above if the user
1374
1370
            # provided it on the command line. Otherwise, daughter classes will
1375
1371
            # prompt the user for one when appropriate.
1376
 
            self._password = _from_transport._password
 
1372
            self._parsed_url.password = _from_transport._parsed_url.password
 
1373
            self._parsed_url.quoted_password = (
 
1374
                _from_transport._parsed_url.quoted_password)
1377
1375
 
1378
 
        base = self._unsplit_url(self._scheme,
1379
 
                                 self._user, self._password,
1380
 
                                 self._host, self._port,
1381
 
                                 self._path)
 
1376
        base = self._unsplit_url(self._parsed_url.scheme,
 
1377
            self._parsed_url.user, self._parsed_url.password,
 
1378
            self._parsed_url.host, self._parsed_url.port,
 
1379
            self._parsed_url.path)
1382
1380
 
1383
1381
        super(ConnectedTransport, self).__init__(base)
1384
1382
        if _from_transport is None:
1386
1384
        else:
1387
1385
            self._shared_connection = _from_transport._shared_connection
1388
1386
 
 
1387
    @property
 
1388
    def _user(self):
 
1389
        return self._parsed_url.user
 
1390
 
 
1391
    @property
 
1392
    def _password(self):
 
1393
        return self._parsed_url.password
 
1394
 
 
1395
    @property
 
1396
    def _host(self):
 
1397
        return self._parsed_url.host
 
1398
 
 
1399
    @property
 
1400
    def _port(self):
 
1401
        return self._parsed_url.port
 
1402
 
 
1403
    @property
 
1404
    def _path(self):
 
1405
        return self._parsed_url.path
 
1406
 
 
1407
    @property
 
1408
    def _scheme(self):
 
1409
        return self._parsed_url.scheme
 
1410
 
1389
1411
    def clone(self, offset=None):
1390
1412
        """Return a new transport with root at self.base + offset
1391
1413
 
1399
1421
 
1400
1422
    @staticmethod
1401
1423
    def _split_url(url):
1402
 
        return urlutils.parse_url(url)
 
1424
        return urlutils.URL.from_string(url)
1403
1425
 
1404
1426
    @staticmethod
1405
1427
    def _unsplit_url(scheme, user, password, host, port, path):
1406
 
        """
1407
 
        Build the full URL for the given already URL encoded path.
 
1428
        """Build the full URL for the given already URL encoded path.
1408
1429
 
1409
1430
        user, password, host and path will be quoted if they contain reserved
1410
1431
        chars.
1411
1432
 
1412
1433
        :param scheme: protocol
1413
 
 
1414
1434
        :param user: login
1415
 
 
1416
1435
        :param password: associated password
1417
 
 
1418
1436
        :param host: the server address
1419
 
 
1420
1437
        :param port: the associated port
1421
 
 
1422
1438
        :param path: the absolute path on the server
1423
1439
 
1424
1440
        :return: The corresponding URL.
1436
1452
 
1437
1453
    def relpath(self, abspath):
1438
1454
        """Return the local path portion from a given absolute path"""
1439
 
        scheme, user, password, host, port, path = self._split_url(abspath)
 
1455
        parsed_url = self._split_url(abspath)
1440
1456
        error = []
1441
 
        if (scheme != self._scheme):
 
1457
        if parsed_url.scheme != self._parsed_url.scheme:
1442
1458
            error.append('scheme mismatch')
1443
 
        if (user != self._user):
 
1459
        if parsed_url.user != self._parsed_url.user:
1444
1460
            error.append('user name mismatch')
1445
 
        if (host != self._host):
 
1461
        if parsed_url.host != self._parsed_url.host:
1446
1462
            error.append('host mismatch')
1447
 
        if (port != self._port):
 
1463
        if parsed_url.port != self._parsed_url.port:
1448
1464
            error.append('port mismatch')
1449
 
        if not (path == self._path[:-1] or path.startswith(self._path)):
 
1465
        if (not (parsed_url.path == self._parsed_url.path[:-1] or
 
1466
            parsed_url.path.startswith(self._parsed_url.path))):
1450
1467
            error.append('path mismatch')
1451
1468
        if error:
1452
1469
            extra = ', '.join(error)
1453
1470
            raise errors.PathNotChild(abspath, self.base, extra=extra)
1454
 
        pl = len(self._path)
1455
 
        return path[pl:].strip('/')
 
1471
        pl = len(self._parsed_url.path)
 
1472
        return parsed_url.path[pl:].strip('/')
1456
1473
 
1457
1474
    def abspath(self, relpath):
1458
1475
        """Return the full url to the given relative path.
1462
1479
        :returns: the Unicode version of the absolute path for relpath.
1463
1480
        """
1464
1481
        relative = urlutils.unescape(relpath).encode('utf-8')
1465
 
        path = self._combine_paths(self._path, relative)
1466
 
        return self._unsplit_url(self._scheme, self._user, self._password,
1467
 
                                 self._host, self._port,
1468
 
                                 path)
 
1482
        path = self._combine_paths(self._parsed_url.path, relative)
 
1483
        return self._unsplit_url(self._parsed_url.scheme,
 
1484
            self._parsed_url.user, self._parsed_url.password,
 
1485
            self._parsed_url.host, self._parsed_url.port, path)
1469
1486
 
1470
1487
    def _remote_path(self, relpath):
1471
1488
        """Return the absolute path part of the url to the given relative path.
1545
1562
        :return: A new transport or None if the connection cannot be shared.
1546
1563
        """
1547
1564
        try:
1548
 
            (scheme, user, password,
1549
 
             host, port, path) = self._split_url(other_base)
 
1565
            parsed_url = self._split_url(other_base)
1550
1566
        except errors.InvalidURL:
1551
1567
            # No hope in trying to reuse an existing transport for an invalid
1552
1568
            # URL
1555
1571
        transport = None
1556
1572
        # Don't compare passwords, they may be absent from other_base or from
1557
1573
        # self and they don't carry more information than user anyway.
1558
 
        if (scheme == self._scheme
1559
 
            and user == self._user
1560
 
            and host == self._host
1561
 
            and port == self._port):
 
1574
        if (parsed_url.scheme == self._parsed_url.scheme
 
1575
            and parsed_url.user == self._parsed_url.user
 
1576
            and parsed_url.host == self._parsed_url.host
 
1577
            and parsed_url.port == self._parsed_url.port):
 
1578
            path = parsed_url.path
1562
1579
            if not path.endswith('/'):
1563
1580
                # This normally occurs at __init__ time, but it's easier to do
1564
1581
                # it now to avoid creating two transports for the same base.
1565
1582
                path += '/'
1566
 
            if self._path  == path:
 
1583
            if self._parsed_url.path  == path:
1567
1584
                # shortcut, it's really the same transport
1568
1585
                return self
1569
1586
            # We don't call clone here because the intent is different: we