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