Rev 6079: (jelmer) Allow specifying the colocated branch to use in the branch URL, in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Wed Aug 17 18:14:09 UTC 2011


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 6079 [merge]
revision-id: pqm at pqm.ubuntu.com-20110817181357-y5q5eth1hk8bl3om
parent: pqm at pqm.ubuntu.com-20110817153820-fadqb9cj9kadzqpy
parent: jelmer at samba.org-20110817011917-nde9fanxwp2ie838
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2011-08-17 18:13:57 +0000
message:
  (jelmer) Allow specifying the colocated branch to use in the branch URL,
   and retrieving the branch name using ControlDir._get_selected_branch.
   (Jelmer Vernooij)
modified:
  bzrlib/controldir.py           controldir.py-20100802102926-hvtvh0uae5epuibp-1
  bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
  bzrlib/tests/blackbox/test_upgrade.py test_upgrade.py-20060120060132-b41e5ed2f886ad28
  bzrlib/tests/per_controldir/test_controldir.py test_bzrdir.py-20060131065642-0ebeca5e30e30866
  bzrlib/tests/per_transport.py  test_transport_implementations.py-20051227111451-f97c5c7d5c49fce7
  bzrlib/tests/stub_sftp.py      stub_sftp.py-20051027032739-0e7ef4f7bab0e174
  bzrlib/tests/test_ftp_transport.py test_aftp_transport.-20060823221619-98mwjzxtwtkt527k-1
  bzrlib/tests/test_smart_transport.py test_ssh_transport.py-20060608202016-c25gvf1ob7ypbus6-2
  bzrlib/tests/test_transport.py testtransport.py-20050718175618-e5cdb99f4555ddce
  bzrlib/tests/test_urlutils.py  test_urlutils.py-20060502192900-46b1f9579987cf9c
  bzrlib/tests/transport_util.py transportutil.py-20070525113600-5v2igk89s8fensom-1
  bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
  bzrlib/transport/decorator.py  decorator.py-20060402223305-e913a0f25319ab42
  bzrlib/transport/http/__init__.py http_transport.py-20050711212304-506c5fd1059ace96
  bzrlib/transport/local.py      local_transport.py-20050711165921-9b1f142bfe480c24
  bzrlib/urlutils.py             urlutils.py-20060502195429-e8a161ecf8fac004
  doc/en/release-notes/bzr-2.5.txt bzr2.5.txt-20110708125756-587p0hpw7oke4h05-1
=== modified file 'bzrlib/controldir.py'
--- a/bzrlib/controldir.py	2011-08-15 16:06:58 +0000
+++ b/bzrlib/controldir.py	2011-08-17 18:13:57 +0000
@@ -31,6 +31,7 @@
     revision as _mod_revision,
     transport as _mod_transport,
     ui,
+    urlutils,
     )
 from bzrlib.push import (
     PushResult,
@@ -273,6 +274,16 @@
         except errors.NotBranchError:
             return False
 
+    def _get_selected_branch(self):
+        """Return the name of the branch selected by the user.
+
+        :return: Name of the branch selected by the user, or None.
+        """
+        branch = self.root_transport.get_segment_parameters().get("branch")
+        if branch is not None:
+            branch = urlutils.unescape(branch)
+        return branch
+
     def has_workingtree(self):
         """Tell if this controldir contains a working tree.
 

=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py	2011-06-18 13:57:17 +0000
+++ b/bzrlib/remote.py	2011-08-17 01:19:17 +0000
@@ -669,7 +669,8 @@
 
     def _path_for_remote_call(self, client):
         """Return the path to be used for this bzrdir in a remote call."""
-        return client.remote_path_from_transport(self.root_transport)
+        return urlutils.split_segment_parameters_raw(
+            client.remote_path_from_transport(self.root_transport))[0]
 
     def get_branch_transport(self, branch_format, name=None):
         self._ensure_real()

=== modified file 'bzrlib/tests/blackbox/test_upgrade.py'
--- a/bzrlib/tests/blackbox/test_upgrade.py	2011-04-05 14:47:30 +0000
+++ b/bzrlib/tests/blackbox/test_upgrade.py	2011-08-12 13:04:56 +0000
@@ -254,7 +254,7 @@
         t = self.get_transport()
         url = t.base
         out, err = self.run_bzr(['upgrade', '--format=2a', url])
-        backup_dir = 'backup.bzr.~1~'
+        backup_dir = 'backup.bzr.%7E1%7E'
         self.assertEqualDiff("""Upgrading branch %s ...
 starting upgrade of %s
 making backup of %s.bzr
@@ -262,7 +262,7 @@
 starting repository conversion
 repository converted
 finished
-""" % (url, url, url, url,backup_dir), out)
+""" % (url, url, url, url, backup_dir), out)
         self.assertEqual('', err)
 
 

=== modified file 'bzrlib/tests/per_controldir/test_controldir.py'
--- a/bzrlib/tests/per_controldir/test_controldir.py	2011-08-10 14:02:04 +0000
+++ b/bzrlib/tests/per_controldir/test_controldir.py	2011-08-15 13:26:00 +0000
@@ -998,7 +998,8 @@
         repo_name = old_fmt.repository_format.network_name()
         # Should end up with a 1.9 format (stackable)
         repo, control = self.assertInitializeEx(t, need_meta=True,
-            repo_format_name=repo_name, stacked_on='../trunk', stack_on_pwd=t.base)
+            repo_format_name=repo_name, stacked_on='../trunk',
+            stack_on_pwd=t.base)
         if control is None:
             # uninitialisable format
             return
@@ -1282,6 +1283,41 @@
         self.assertIsInstance(opened_tree, made_tree.__class__)
         self.assertIsInstance(opened_tree._format, made_tree._format.__class__)
 
+    def test_get_selected_branch(self):
+        # The segment parameters are accessible from the root transport
+        # if a URL with segment parameters is opened.
+        if not self.bzrdir_format.is_supported():
+            # unsupported formats are not loopback testable
+            # because the default open will not open them and
+            # they may not be initializable.
+            return
+        t = self.get_transport()
+        try:
+            made_control = self.bzrdir_format.initialize(t.base)
+        except (errors.NotLocalUrl, errors.UnsupportedOperation):
+            raise TestSkipped("Can't initialize %r on transport %r"
+                              % (self.bzrdir_format, t))
+        dir = bzrdir.BzrDir.open(t.base+",branch=foo")
+        self.assertEquals({"branch": "foo"},
+            dir.user_transport.get_segment_parameters())
+        self.assertEquals("foo", dir._get_selected_branch())
+
+    def test_get_selected_branch_none_selected(self):
+        # _get_selected_branch defaults to None
+        if not self.bzrdir_format.is_supported():
+            # unsupported formats are not loopback testable
+            # because the default open will not open them and
+            # they may not be initializable.
+            return
+        t = self.get_transport()
+        try:
+            made_control = self.bzrdir_format.initialize(t.base)
+        except (errors.NotLocalUrl, errors.UnsupportedOperation):
+            raise TestSkipped("Can't initialize %r on transport %r"
+                              % (self.bzrdir_format, t))
+        dir = bzrdir.BzrDir.open(t.base)
+        self.assertIs(None, dir._get_selected_branch())
+
     def test_root_transport(self):
         dir = self.make_bzrdir('.')
         self.assertEqual(dir.root_transport.base,

=== modified file 'bzrlib/tests/per_transport.py'
--- a/bzrlib/tests/per_transport.py	2011-08-08 17:52:59 +0000
+++ b/bzrlib/tests/per_transport.py	2011-08-15 11:19:03 +0000
@@ -1230,7 +1230,7 @@
             if host     is None: host     = t._parsed_url.host
             if port     is None: port     = t._parsed_url.port
             if path     is None: path     = t._parsed_url.path
-            return t._unsplit_url(scheme, user, password, host, port, path)
+            return str(urlutils.URL(scheme, user, password, host, port, path))
 
         if t._parsed_url.scheme == 'ftp':
             scheme = 'sftp'
@@ -1776,6 +1776,21 @@
         self.assertListRaises((errors.ShortReadvError, errors.InvalidRange),
                               transport.readv, 'a', [(12,2)])
 
+    def test_no_segment_parameters(self):
+        """Segment parameters should be stripped and stored in
+        transport.segment_parameters."""
+        transport = self.get_transport("foo")
+        self.assertEquals({}, transport.get_segment_parameters())
+
+    def test_segment_parameters(self):
+        """Segment parameters should be stripped and stored in
+        transport.get_segment_parameters()."""
+        base_url = self._server.get_url()
+        parameters = {"key1": "val1", "key2": "val2"}
+        url = urlutils.join_segment_parameters(base_url, parameters)
+        transport = _mod_transport.get_transport(url)
+        self.assertEquals(parameters, transport.get_segment_parameters())
+
     def test_stat_symlink(self):
         # if a transport points directly to a symlink (and supports symlinks
         # at all) you can tell this.  helps with bug 32669.

=== modified file 'bzrlib/tests/stub_sftp.py'
--- a/bzrlib/tests/stub_sftp.py	2011-01-12 01:01:53 +0000
+++ b/bzrlib/tests/stub_sftp.py	2011-08-15 12:37:25 +0000
@@ -553,7 +553,7 @@
 
     def get_url(self):
         """See bzrlib.transport.Server.get_url."""
-        return self._get_sftp_url("~/")
+        return self._get_sftp_url("%7E/")
 
 
 class SFTPSiblingAbsoluteServer(SFTPAbsoluteServer):

=== modified file 'bzrlib/tests/test_ftp_transport.py'
--- a/bzrlib/tests/test_ftp_transport.py	2011-08-08 17:52:59 +0000
+++ b/bzrlib/tests/test_ftp_transport.py	2011-08-15 12:26:33 +0000
@@ -16,6 +16,7 @@
 
 import ftplib
 import getpass
+import urllib
 
 from bzrlib import (
     config,
@@ -82,10 +83,12 @@
         """Overrides get_url to inject our user."""
         base = super(TestFTPTestServerUI, self).get_url(relpath)
         parsed_url = transport.ConnectedTransport._split_url(base)
-        url = transport.ConnectedTransport._unsplit_url(
-            parsed_url.scheme, self.user, self.password, parsed_url.host,
-            parsed_url.port, parsed_url.path)
-        return url
+        new_url = parsed_url.clone()
+        new_url.user = self.user
+        new_url.quoted_user = urllib.quote(self.user)
+        new_url.password = self.password
+        new_url.quoted_password = urllib.quote(self.password)
+        return str(new_url)
 
     def test_no_prompt_for_username(self):
         """ensure getpass.getuser() is used if there's no username in the 

=== modified file 'bzrlib/tests/test_smart_transport.py'
--- a/bzrlib/tests/test_smart_transport.py	2011-08-08 17:52:59 +0000
+++ b/bzrlib/tests/test_smart_transport.py	2011-08-12 15:34:53 +0000
@@ -3558,7 +3558,7 @@
         # still work correctly.
         base_transport = remote.RemoteHTTPTransport('bzr+http://host/%7Ea/b')
         new_transport = base_transport.clone('c')
-        self.assertEqual('bzr+http://host/~a/b/c/', new_transport.base)
+        self.assertEqual('bzr+http://host/%7Ea/b/c/', new_transport.base)
         self.assertEqual(
             'c/',
             new_transport._client.remote_path_from_transport(new_transport))

=== modified file 'bzrlib/tests/test_transport.py'
--- a/bzrlib/tests/test_transport.py	2011-08-12 18:48:36 +0000
+++ b/bzrlib/tests/test_transport.py	2011-08-15 14:31:55 +0000
@@ -701,6 +701,15 @@
         self.assertIsInstance(t, local.LocalTransport)
         self.assertEquals(t.base.rstrip("/"), url)
 
+    def test_with_url_and_segment_parameters(self):
+        url = urlutils.local_path_to_url(self.test_dir)+",branch=foo"
+        t = transport.get_transport_from_url(url)
+        self.assertIsInstance(t, local.LocalTransport)
+        self.assertEquals(t.base.rstrip("/"), url)
+        with open(os.path.join(self.test_dir, "afile"), 'w') as f:
+            f.write("data")
+        self.assertTrue(t.has("afile"))
+
 
 class TestLocalTransports(tests.TestCase):
 
@@ -796,7 +805,7 @@
         self.assertEquals(t._parsed_url.path, '/path/')
 
         # Base should not keep track of the password
-        self.assertEquals(t.base, 'http://robey@exAmple.com:2222/path/')
+        self.assertEquals(t.base, 'http://ro%62ey@ex%41mple.com:2222/path/')
 
     def test_parse_invalid_url(self):
         self.assertRaises(errors.InvalidURL,

=== modified file 'bzrlib/tests/test_urlutils.py'
--- a/bzrlib/tests/test_urlutils.py	2011-08-11 14:46:42 +0000
+++ b/bzrlib/tests/test_urlutils.py	2011-08-15 13:12:36 +0000
@@ -336,17 +336,24 @@
 
     def test_function_type(self):
         if sys.platform == 'win32':
-            self.assertEqual(urlutils._win32_local_path_to_url, urlutils.local_path_to_url)
-            self.assertEqual(urlutils._win32_local_path_from_url, urlutils.local_path_from_url)
+            self.assertEqual(urlutils._win32_local_path_to_url,
+                urlutils.local_path_to_url)
+            self.assertEqual(urlutils._win32_local_path_from_url,
+                urlutils.local_path_from_url)
         else:
-            self.assertEqual(urlutils._posix_local_path_to_url, urlutils.local_path_to_url)
-            self.assertEqual(urlutils._posix_local_path_from_url, urlutils.local_path_from_url)
+            self.assertEqual(urlutils._posix_local_path_to_url,
+                urlutils.local_path_to_url)
+            self.assertEqual(urlutils._posix_local_path_from_url,
+                urlutils.local_path_from_url)
 
     def test_posix_local_path_to_url(self):
         to_url = urlutils._posix_local_path_to_url
         self.assertEqual('file:///path/to/foo',
             to_url('/path/to/foo'))
 
+        self.assertEqual('file:///path/to/foo%2Cbar',
+            to_url('/path/to/foo,bar'))
+
         try:
             result = to_url(u'/path/to/r\xe4ksm\xf6rg\xe5s')
         except UnicodeError:
@@ -359,6 +366,8 @@
         from_url = urlutils._posix_local_path_from_url
         self.assertEqual('/path/to/foo',
             from_url('file:///path/to/foo'))
+        self.assertEqual('/path/to/foo',
+            from_url('file:///path/to/foo,branch=foo'))
         self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
             from_url('file:///path/to/r%C3%A4ksm%C3%B6rg%C3%A5s'))
         self.assertEqual(u'/path/to/r\xe4ksm\xf6rg\xe5s',
@@ -386,6 +395,8 @@
 
         self.assertEqual('file:///', to_url('/'))
 
+        self.assertEqual('file:///C:/path/to/foo%2Cbar',
+            to_url('C:/path/to/foo,bar'))
         try:
             result = to_url(u'd:/path/to/r\xe4ksm\xf6rg\xe5s')
         except UnicodeError:
@@ -418,6 +429,8 @@
         self.assertEqual(u'D:/path/to/r\xe4ksm\xf6rg\xe5s',
             from_url('file:///d:/path/to/r%c3%a4ksm%c3%b6rg%c3%a5s'))
         self.assertEqual('/', from_url('file:///'))
+        self.assertEqual('C:/path/to/foo',
+            from_url('file:///C|/path/to/foo,branch=foo'))
 
         self.assertRaises(InvalidURL, from_url, 'file:///C:')
         self.assertRaises(InvalidURL, from_url, 'file:///c')
@@ -428,6 +441,8 @@
     def test_win32_unc_path_from_url(self):
         from_url = urlutils._win32_local_path_from_url
         self.assertEqual('//HOST/path', from_url('file://HOST/path'))
+        self.assertEqual('//HOST/path',
+            from_url('file://HOST/path,branch=foo'))
         # despite IE allows 2, 4, 5 and 6 slashes in URL to another machine
         # we want to use only 2 slashes
         # Firefox understand only 5 slashes in URL, but it's ugly
@@ -494,6 +509,8 @@
             split_segment_parameters_raw(",key1=val1"))
         self.assertEquals(("foo/", ["key1=val1"]),
             split_segment_parameters_raw("foo/,key1=val1"))
+        self.assertEquals(("/foo", ["key1=val1"]),
+            split_segment_parameters_raw("foo,key1=val1"))
         self.assertEquals(("foo/base,la=bla/other/elements", []),
             split_segment_parameters_raw("foo/base,la=bla/other/elements"))
         self.assertEquals(("foo/base,la=bla/other/elements", ["a=b"]),

=== modified file 'bzrlib/tests/transport_util.py'
--- a/bzrlib/tests/transport_util.py	2011-08-08 17:52:59 +0000
+++ b/bzrlib/tests/transport_util.py	2011-08-15 12:27:36 +0000
@@ -78,12 +78,7 @@
         # The following is needed to minimize the effects of our trick above
         # while retaining the best compatibility.
         self._parsed_url.scheme = _hooked_scheme
-        base = self._unsplit_url(self._parsed_url.scheme,
-                                 self._parsed_url.user,
-                                 self._parsed_url.password,
-                                 self._parsed_url.host, self._parsed_url.port,
-                                 self._parsed_url.path)
-        super(ConnectedTransport, self).__init__(base)
+        super(ConnectedTransport, self).__init__(str(self._parsed_url))
 
 
 class ConnectionHookedTransport(InstrumentedTransport):

=== modified file 'bzrlib/transport/__init__.py'
--- a/bzrlib/transport/__init__.py	2011-08-11 15:13:57 +0000
+++ b/bzrlib/transport/__init__.py	2011-08-12 15:34:53 +0000
@@ -310,6 +310,8 @@
     def __init__(self, base):
         super(Transport, self).__init__()
         self.base = base
+        self._segment_parameters = urlutils.split_segment_parameters(
+            base.rstrip("/"))[1]
 
     def _translate_error(self, e, path, raise_generic=True):
         """Translate an IOError or OSError into an appropriate bzr error.
@@ -409,6 +411,11 @@
         """
         raise NotImplementedError(self.external_url)
 
+    def get_segment_parameters(self):
+        """Return the segment parameters for the top segment of the URL.
+        """
+        return self._segment_parameters
+
     def _pump(self, from_file, to_file):
         """Most children will need to copy from one file-like
         object or string to another one.
@@ -1329,10 +1336,7 @@
             self._parsed_url.quoted_password = (
                 _from_transport._parsed_url.quoted_password)
 
-        base = self._unsplit_url(self._parsed_url.scheme,
-            self._parsed_url.user, self._parsed_url.password,
-            self._parsed_url.host, self._parsed_url.port,
-            self._parsed_url.path)
+        base = str(self._parsed_url)
 
         super(ConnectedTransport, self).__init__(base)
         if _from_transport is None:
@@ -1434,9 +1438,7 @@
 
         :returns: the Unicode version of the absolute path for relpath.
         """
-        other = self._parsed_url.clone(relpath)
-        return self._unsplit_url(other.scheme, other.user, other.password,
-            other.host, other.port, other.path)
+        return str(self._parsed_url.clone(relpath))
 
     def _remote_path(self, relpath):
         """Return the absolute path part of the url to the given relative path.

=== modified file 'bzrlib/transport/decorator.py'
--- a/bzrlib/transport/decorator.py	2010-06-20 11:18:38 +0000
+++ b/bzrlib/transport/decorator.py	2011-03-17 10:52:31 +0000
@@ -156,6 +156,15 @@
         """See Transport.rmdir."""
         return self._decorated.rmdir(relpath)
 
+    def _get_segment_parameters(self):
+        return self._decorated.segment_parameters
+
+    def _set_segment_parameters(self, value):
+        self._decorated.segment_parameters = value
+
+    segment_parameters = property(_get_segment_parameters,
+        _set_segment_parameters, "See Transport.segment_parameters")
+
     def stat(self, relpath):
         """See Transport.stat()."""
         return self._decorated.stat(relpath)

=== modified file 'bzrlib/transport/http/__init__.py'
--- a/bzrlib/transport/http/__init__.py	2011-08-11 16:24:09 +0000
+++ b/bzrlib/transport/http/__init__.py	2011-08-15 12:32:05 +0000
@@ -148,10 +148,11 @@
 
         user and passwords are not embedded in the path provided to the server.
         """
-        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)
+        url = self._parsed_url.clone(relpath)
+        url.user = url.quoted_user = None
+        url.password = url.quoted_password = None
+        url.scheme = self._unqualified_scheme
+        return str(url)
 
     def _create_auth(self):
         """Returns a dict containing the credentials provided at build time."""
@@ -412,10 +413,9 @@
         """See bzrlib.transport.Transport.external_url."""
         # HTTP URL's are externally usable as long as they don't mention their
         # implementation qualifier
-        return self._unsplit_url(self._unqualified_scheme,
-                                 self._parsed_url.user, self._parsed_url.password,
-                                 self._parsed_url.host, self._parsed_url.port,
-                                 self._parsed_url.path)
+        url = self._parsed_url.clone()
+        url.scheme = self._unqualified_scheme
+        return str(url)
 
     def is_readonly(self):
         """See Transport.is_readonly."""
@@ -538,7 +538,7 @@
         new_transport = None
         parsed_url = self._split_url(target)
         # Recalculate base path. This is needed to ensure that when the
-        # redirected tranport will be used to re-try whatever request was
+        # redirected transport will be used to re-try whatever request was
         # redirected, we end up with the same url
         base_path = parsed_url.path[:-len(relpath)]
         if parsed_url.scheme in ('http', 'https'):

=== modified file 'bzrlib/transport/local.py'
--- a/bzrlib/transport/local.py	2011-07-05 06:41:37 +0000
+++ b/bzrlib/transport/local.py	2011-08-15 14:31:55 +0000
@@ -72,6 +72,8 @@
 
         super(LocalTransport, self).__init__(base)
         self._local_base = urlutils.local_path_from_url(base)
+        if self._local_base[-1] != '/':
+            self._local_base = self._local_base + '/'
 
     def clone(self, offset=None):
         """Return a new LocalTransport with root at self.base + offset

=== modified file 'bzrlib/urlutils.py'
--- a/bzrlib/urlutils.py	2011-08-11 14:46:42 +0000
+++ b/bzrlib/urlutils.py	2011-08-15 13:12:36 +0000
@@ -181,6 +181,7 @@
 # jam 20060502 Sorted to 'l' because the final target is 'local_path_from_url'
 def _posix_local_path_from_url(url):
     """Convert a url like file:///path/to/foo into /path/to/foo"""
+    url = split_segment_parameters_raw(url)[0]
     file_localhost_prefix = 'file://localhost/'
     if url.startswith(file_localhost_prefix):
         path = url[len(file_localhost_prefix) - 1:]
@@ -209,6 +210,7 @@
     if not url.startswith('file://'):
         raise errors.InvalidURL(url, 'local urls must start with file:///, '
                                      'UNC path urls must start with file://')
+    url = split_segment_parameters_raw(url)[0]
     # We strip off all 3 slashes
     win32_url = url[len('file:'):]
     # check for UNC path: //HOST/path

=== modified file 'doc/en/release-notes/bzr-2.5.txt'
--- a/doc/en/release-notes/bzr-2.5.txt	2011-08-17 08:40:16 +0000
+++ b/doc/en/release-notes/bzr-2.5.txt	2011-08-17 18:13:57 +0000
@@ -174,6 +174,10 @@
 .. Major internal changes, unlikely to be visible to users or plugin 
    developers, but interesting for bzr developers.
 
+* New method ``ControlDir._get_selected_branch`` which returns the
+  colocated branch selected using path segment parameters.
+  (Jelmer Vernooij, #380871)
+
 Testing
 *******
 




More information about the bazaar-commits mailing list