Rev 6067: (jelmer) Add URL.clone, in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Fri Aug 12 18:48:44 UTC 2011
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 6067 [merge]
revision-id: pqm at pqm.ubuntu.com-20110812184836-5jv1u3ns0s74zsg0
parent: pqm at pqm.ubuntu.com-20110812161223-hfvwsgbtb9vype5r
parent: jelmer at samba.org-20110811162409-ouacri7g3pde8ygu
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Fri 2011-08-12 18:48:36 +0000
message:
(jelmer) Add URL.clone,
URL.__str__ and use them in various places. (Jelmer Vernooij)
modified:
bzrlib/tests/test_transport.py testtransport.py-20050718175618-e5cdb99f4555ddce
bzrlib/tests/test_urlutils.py test_urlutils.py-20060502192900-46b1f9579987cf9c
bzrlib/transport/__init__.py transport.py-20050711165921-4978aa7ce1285ad5
bzrlib/transport/gio_transport.py __init__.py-20100430125031-jb4f7q7mtyz55kz3-2
bzrlib/transport/http/__init__.py http_transport.py-20050711212304-506c5fd1059ace96
bzrlib/transport/memory.py memory.py-20051016101338-cd008dbdf69f04fc
bzrlib/transport/pathfilter.py pathfilter.py-20090911074646-d3befzxpj1zglo7s-1
bzrlib/transport/remote.py ssh.py-20060608202016-c25gvf1ob7ypbus6-1
bzrlib/transport/sftp.py sftp.py-20051019050329-ab48ce71b7e32dfe
bzrlib/urlutils.py urlutils.py-20060502195429-e8a161ecf8fac004
=== modified file 'bzrlib/tests/test_transport.py'
--- a/bzrlib/tests/test_transport.py 2011-08-12 01:42:55 +0000
+++ b/bzrlib/tests/test_transport.py 2011-08-12 18:48:36 +0000
@@ -138,17 +138,6 @@
self.assertRaises(errors.ReadError, a_file.read, 40)
a_file.close()
- def test__combine_paths(self):
- t = transport.Transport('/')
- self.assertEqual('/home/sarah/project/foo',
- t._combine_paths('/home/sarah', 'project/foo'))
- self.assertEqual('/etc',
- t._combine_paths('/home/sarah', '../../etc'))
- self.assertEqual('/etc',
- t._combine_paths('/home/sarah', '../../../etc'))
- self.assertEqual('/etc',
- t._combine_paths('/home/sarah', '/etc'))
-
def test_local_abspath_non_local_transport(self):
# the base implementation should throw
t = memory.MemoryTransport()
=== modified file 'bzrlib/tests/test_urlutils.py'
--- a/bzrlib/tests/test_urlutils.py 2011-08-10 23:27:14 +0000
+++ b/bzrlib/tests/test_urlutils.py 2011-08-11 14:46:42 +0000
@@ -864,3 +864,27 @@
"<URL('http', None, None, '1:2:3::40', 80, '/one')>",
repr(parsed))
+ def test_str(self):
+ parsed = urlutils.URL.from_string('http://[1:2:3::40]:80/one')
+ self.assertEquals('http://[1:2:3::40]:80/one', str(parsed))
+
+ def test__combine_paths(self):
+ combine = urlutils.URL._combine_paths
+ self.assertEqual('/home/sarah/project/foo',
+ combine('/home/sarah', 'project/foo'))
+ self.assertEqual('/etc',
+ combine('/home/sarah', '../../etc'))
+ self.assertEqual('/etc',
+ combine('/home/sarah', '../../../etc'))
+ self.assertEqual('/etc',
+ combine('/home/sarah', '/etc'))
+
+ def test_clone(self):
+ url = urlutils.URL.from_string('http://[1:2:3::40]:80/one')
+ url1 = url.clone("two")
+ self.assertEquals("/one/two", url1.path)
+ url2 = url.clone("/two")
+ self.assertEquals("/two", url2.path)
+ url3 = url.clone()
+ self.assertIsNot(url, url3)
+ self.assertEquals(url, url3)
=== modified file 'bzrlib/transport/__init__.py'
--- a/bzrlib/transport/__init__.py 2011-08-10 22:55:12 +0000
+++ b/bzrlib/transport/__init__.py 2011-08-11 15:13:57 +0000
@@ -479,50 +479,6 @@
# interface ?
raise NotImplementedError(self.abspath)
- def _combine_paths(self, base_path, relpath):
- """Transform a Transport-relative path to a remote absolute path.
-
- This does not handle substitution of ~ but does handle '..' and '.'
- components.
-
- Examples::
-
- t._combine_paths('/home/sarah', 'project/foo')
- => '/home/sarah/project/foo'
- t._combine_paths('/home/sarah', '../../etc')
- => '/etc'
- t._combine_paths('/home/sarah', '/etc')
- => '/etc'
-
- :param base_path: urlencoded path for the transport root; typically a
- URL but need not contain scheme/host/etc.
- :param relpath: relative url string for relative part of remote path.
- :return: urlencoded string for final path.
- """
- if not isinstance(relpath, str):
- raise errors.InvalidURL(relpath)
- if relpath.startswith('/'):
- base_parts = []
- else:
- base_parts = base_path.split('/')
- if len(base_parts) > 0 and base_parts[-1] == '':
- base_parts = base_parts[:-1]
- for p in relpath.split('/'):
- if p == '..':
- if len(base_parts) == 0:
- # In most filesystems, a request for the parent
- # of root, just returns root.
- continue
- base_parts.pop()
- elif p == '.':
- continue # No-op
- elif p != '':
- base_parts.append(p)
- path = '/'.join(base_parts)
- if not path.startswith('/'):
- path = '/' + path
- return path
-
def recommended_page_size(self):
"""Return the recommended page size for this transport.
@@ -1478,11 +1434,9 @@
:returns: the Unicode version of the absolute path for relpath.
"""
- relative = urlutils.unescape(relpath).encode('utf-8')
- path = self._combine_paths(self._parsed_url.path, relative)
- return self._unsplit_url(self._parsed_url.scheme,
- self._parsed_url.user, self._parsed_url.password,
- self._parsed_url.host, self._parsed_url.port, path)
+ other = self._parsed_url.clone(relpath)
+ return self._unsplit_url(other.scheme, other.user, other.password,
+ other.host, other.port, other.path)
def _remote_path(self, relpath):
"""Return the absolute path part of the url to the given relative path.
@@ -1495,9 +1449,7 @@
:return: the absolute Unicode path on the server,
"""
- relative = urlutils.unescape(relpath).encode('utf-8')
- remote_path = self._combine_paths(self._path, relative)
- return remote_path
+ return self._parsed_url.clone(relpath).path
def _get_shared_connection(self):
"""Get the object shared amongst cloned transports.
=== modified file 'bzrlib/transport/gio_transport.py'
--- a/bzrlib/transport/gio_transport.py 2011-08-10 22:34:25 +0000
+++ b/bzrlib/transport/gio_transport.py 2011-08-11 16:24:09 +0000
@@ -250,9 +250,7 @@
self._set_connection(connection, credentials)
def _remote_path(self, relpath):
- relative = urlutils.unescape(relpath).encode('utf-8')
- remote_path = self._combine_paths(self._path, relative)
- return remote_path
+ return self._parsed_url.clone(relpath).path
def has(self, relpath):
"""Does the target location exist?"""
=== modified file 'bzrlib/transport/http/__init__.py'
--- a/bzrlib/transport/http/__init__.py 2011-08-08 17:52:59 +0000
+++ b/bzrlib/transport/http/__init__.py 2011-08-11 16:24:09 +0000
@@ -148,8 +148,7 @@
user and passwords are not embedded in the path provided to the server.
"""
- relative = urlutils.unescape(relpath).encode('utf-8')
- path = self._combine_paths(self._parsed_url.path, relative)
+ path = self._parsed_url.clone(relpath).path
return self._unsplit_url(self._unqualified_scheme,
None, None, self._parsed_url.host,
self._parsed_url.port, path)
=== modified file 'bzrlib/transport/memory.py'
--- a/bzrlib/transport/memory.py 2011-06-28 21:47:24 +0000
+++ b/bzrlib/transport/memory.py 2011-08-11 14:08:05 +0000
@@ -81,7 +81,7 @@
def clone(self, offset=None):
"""See Transport.clone()."""
- path = self._combine_paths(self._cwd, offset)
+ path = urlutils.URL._combine_paths(self._cwd, offset)
if len(path) == 0 or path[-1] != '/':
path += '/'
url = self._scheme + path
=== modified file 'bzrlib/transport/pathfilter.py'
--- a/bzrlib/transport/pathfilter.py 2011-01-26 19:34:58 +0000
+++ b/bzrlib/transport/pathfilter.py 2011-08-11 14:08:05 +0000
@@ -16,6 +16,7 @@
"""A transport decorator that filters all paths that are passed to it."""
+from bzrlib import urlutils
from bzrlib.transport import (
register_transport,
@@ -81,7 +82,7 @@
self.scheme = self.server.scheme
def _relpath_from_server_root(self, relpath):
- unfiltered_path = self._combine_paths(self.base_path, relpath)
+ unfiltered_path = urlutils.URL._combine_paths(self.base_path, relpath)
if not unfiltered_path.startswith('/'):
raise ValueError(unfiltered_path)
return unfiltered_path[1:]
=== modified file 'bzrlib/transport/remote.py'
--- a/bzrlib/transport/remote.py 2011-08-08 17:52:59 +0000
+++ b/bzrlib/transport/remote.py 2011-08-11 14:08:05 +0000
@@ -170,7 +170,7 @@
def _remote_path(self, relpath):
"""Returns the Unicode version of the absolute path for relpath."""
- return self._combine_paths(self._parsed_url.path, relpath)
+ return urlutils.URL._combine_paths(self._parsed_url.path, relpath)
def _call(self, method, *args):
resp = self._call2(method, *args)
=== modified file 'bzrlib/transport/sftp.py'
--- a/bzrlib/transport/sftp.py 2011-08-08 17:52:59 +0000
+++ b/bzrlib/transport/sftp.py 2011-08-11 16:24:09 +0000
@@ -335,8 +335,7 @@
:param relpath: is a urlencoded string.
"""
- relative = urlutils.unescape(relpath).encode('utf-8')
- remote_path = self._combine_paths(self._parsed_url.path, relative)
+ remote_path = self._parsed_url.clone(relpath).path
# the initial slash should be removed from the path, and treated as a
# homedir relative path (the path begins with a double slash if it is
# absolute). see draft-ietf-secsh-scp-sftp-ssh-uri-03.txt
=== modified file 'bzrlib/urlutils.py'
--- a/bzrlib/urlutils.py 2011-08-10 23:27:14 +0000
+++ b/bzrlib/urlutils.py 2011-08-11 14:46:42 +0000
@@ -785,7 +785,8 @@
else:
host = netloc
- if ':' in host and not (host[0] == '[' and host[-1] == ']'): #there *is* port
+ if ':' in host and not (host[0] == '[' and host[-1] == ']'):
+ # there *is* port
host, port = host.rsplit(':',1)
try:
port = int(port)
@@ -797,6 +798,80 @@
return cls(scheme, user, password, host, port, path)
+ def __str__(self):
+ netloc = self.quoted_host
+ if ":" in netloc:
+ netloc = "[%s]" % netloc
+ if self.quoted_user is not None:
+ # Note that we don't put the password back even if we
+ # have one so that it doesn't get accidentally
+ # exposed.
+ netloc = '%s@%s' % (self.quoted_user, netloc)
+ if self.port is not None:
+ netloc = '%s:%d' % (netloc, self.port)
+ return urlparse.urlunparse(
+ (self.scheme, netloc, self.quoted_path, None, None, None))
+
+ @staticmethod
+ def _combine_paths(base_path, relpath):
+ """Transform a Transport-relative path to a remote absolute path.
+
+ This does not handle substitution of ~ but does handle '..' and '.'
+ components.
+
+ Examples::
+
+ t._combine_paths('/home/sarah', 'project/foo')
+ => '/home/sarah/project/foo'
+ t._combine_paths('/home/sarah', '../../etc')
+ => '/etc'
+ t._combine_paths('/home/sarah', '/etc')
+ => '/etc'
+
+ :param base_path: base path
+ :param relpath: relative url string for relative part of remote path.
+ :return: urlencoded string for final path.
+ """
+ if not isinstance(relpath, str):
+ raise errors.InvalidURL(relpath)
+ if relpath.startswith('/'):
+ base_parts = []
+ else:
+ base_parts = base_path.split('/')
+ if len(base_parts) > 0 and base_parts[-1] == '':
+ base_parts = base_parts[:-1]
+ for p in relpath.split('/'):
+ if p == '..':
+ if len(base_parts) == 0:
+ # In most filesystems, a request for the parent
+ # of root, just returns root.
+ continue
+ base_parts.pop()
+ elif p == '.':
+ continue # No-op
+ elif p != '':
+ base_parts.append(p)
+ path = '/'.join(base_parts)
+ if not path.startswith('/'):
+ path = '/' + path
+ return path
+
+ def clone(self, offset=None):
+ """Return a new URL for a path relative to this URL.
+
+ :param offset: A relative path, already urlencoded
+ :return: `URL` instance
+ """
+ if offset is not None:
+ relative = unescape(offset).encode('utf-8')
+ path = self._combine_paths(self.path, relative)
+ path = urllib.quote(path)
+ else:
+ path = self.quoted_path
+ return self.__class__(self.scheme, self.quoted_user,
+ self.quoted_password, self.quoted_host, self.port,
+ path)
+
def parse_url(url):
"""Extract the server address, the credentials and the path from the url.
More information about the bazaar-commits
mailing list