Merge lp:~jml/bzr/default-stacking-bug-385132 into lp:~bzr/bzr/trunk-old

Proposed by Jonathan Lange
Status: Merged
Merged at revision: not available
Proposed branch: lp:~jml/bzr/default-stacking-bug-385132
Merge into: lp:~bzr/bzr/trunk-old
Diff against target: 165 lines
To merge this branch: bzr merge lp:~jml/bzr/default-stacking-bug-385132
Reviewer Review Type Date Requested Status
Andrew Bennetts Approve
Review via email: mp+7330@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jonathan Lange (jml) wrote :

Bazaar 1.15 added a verb for initialize_ex which broke certain default stacking policies, notably the one that Launchpad uses. This patch attempts to fix this regression by returning relative URLs when the stacking policy itself has a relative URL.

There are two interesting cases. One is where the policy looks like:
  default_stack_on=/foo/bar/baz

and the other where it looks like:
  default_stack_on=trunk

Current versions of Bazaar send these as ('/foo/bar/baz', 'chroot-123124:///') and ('trunk', 'chroot-15245:///). This patch changes them to be sent as ('/foo/bar/baz', '.') and ('trunk', '..').

Note that the fix touches both client and server side. That means that 1.15 clients will forever be broken when pushing new branches to Launchpad. This sucks, can we do something about it?

I think the rest of the patch is fairly simple: it adds some tests, trying to be as direct as possible; it changes the client to handle relative final_stack_pwd; it changes the server to generate relative final_stack & final_stack_pwd; it cleans up some lint & spelling mistakes found along the way.

This bug is blocking the 1.16rc1 release. I would greatly appreciate a swift review.

Thanks,
jml

Revision history for this message
Andrew Bennetts (spiv) wrote :

This feedback has already been given over IRC, but for the record:

38 + full_path = self._root_client_path + final_stack[1:]
39 + final_stack = urlutils.relative_url(
40 + target_transport.base, full_path)

didn't make sense to me.

What would make sense to me would be s/full_path/client_path/, and changing the first arg of relative_url to _root_client_path.

+ self.reset_smart_call_log()

Omit self.reset_smart_call_log() calls if you aren't going to inspect the call log in the test.

Everything else seems ok, I think.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bzrlib/bzrdir.py'
2--- bzrlib/bzrdir.py 2009-06-10 03:56:49 +0000
3+++ bzrlib/bzrdir.py 2009-06-11 11:35:12 +0000
4@@ -3249,6 +3249,9 @@
5 repo_bzr = bzrdir
6 final_stack = response[8] or None
7 final_stack_pwd = response[9] or None
8+ if final_stack_pwd:
9+ final_stack_pwd = urlutils.join(
10+ transport.base, final_stack_pwd)
11 remote_repo = remote.RemoteRepository(repo_bzr, repo_format)
12 if len(response) > 10:
13 # Updated server verb that locks remotely.
14
15=== modified file 'bzrlib/smart/bzrdir.py'
16--- bzrlib/smart/bzrdir.py 2009-04-28 03:55:56 +0000
17+++ bzrlib/smart/bzrdir.py 2009-06-11 11:35:12 +0000
18@@ -17,7 +17,7 @@
19 """Server-side bzrdir related request implmentations."""
20
21
22-from bzrlib import branch, errors, repository
23+from bzrlib import branch, errors, repository, urlutils
24 from bzrlib.bzrdir import (
25 BzrDir,
26 BzrDirFormat,
27@@ -407,6 +407,19 @@
28 repo.unlock()
29 final_stack = final_stack or ''
30 final_stack_pwd = final_stack_pwd or ''
31+
32+ # We want this to be relative to the bzrdir.
33+ if final_stack_pwd:
34+ final_stack_pwd = urlutils.relative_url(
35+ target_transport.base, final_stack_pwd)
36+
37+ # Can't meaningfully return a root path.
38+ if final_stack.startswith('/'):
39+ client_path = self._root_client_path + final_stack[1:]
40+ final_stack = urlutils.relative_url(
41+ self._root_client_path, client_path)
42+ final_stack_pwd = '.'
43+
44 return SuccessfulSmartServerResponse((repo_path, rich_root, tree_ref,
45 external_lookup, repo_name, repo_bzrdir_name,
46 bzrdir._format.network_name(),
47
48=== modified file 'bzrlib/tests/blackbox/test_push.py'
49--- bzrlib/tests/blackbox/test_push.py 2009-06-10 03:56:49 +0000
50+++ bzrlib/tests/blackbox/test_push.py 2009-06-11 11:35:12 +0000
51@@ -215,6 +215,31 @@
52 remote = branch.Branch.open('public')
53 self.assertEndsWith(remote.get_stacked_on_url(), '/parent')
54
55+ def test_push_smart_with_default_stacking_url_path_segment(self):
56+ # If the default stacked-on location is a path element then branches
57+ # we push there over the smart server are stacked and their
58+ # stacked_on_url is that exact path segment. Added to nail bug 385132.
59+ self.setup_smart_server_with_call_log()
60+ self.make_branch('stack-on', format='1.9')
61+ self.make_bzrdir('.').get_config().set_default_stack_on(
62+ '/stack-on')
63+ self.make_branch('from', format='1.9')
64+ out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
65+ b = branch.Branch.open(self.get_url('to'))
66+ self.assertEqual('/extra/stack-on', b.get_stacked_on_url())
67+
68+ def test_push_smart_with_default_stacking_relative_path(self):
69+ # If the default stacked-on location is a relative path then branches
70+ # we push there over the smart server are stacked and their
71+ # stacked_on_url is a relative path. Added to nail bug 385132.
72+ self.setup_smart_server_with_call_log()
73+ self.make_branch('stack-on', format='1.9')
74+ self.make_bzrdir('.').get_config().set_default_stack_on('stack-on')
75+ self.make_branch('from', format='1.9')
76+ out, err = self.run_bzr(['push', '-d', 'from', self.get_url('to')])
77+ b = branch.Branch.open(self.get_url('to'))
78+ self.assertEqual('../stack-on', b.get_stacked_on_url())
79+
80 def create_simple_tree(self):
81 tree = self.make_branch_and_tree('tree')
82 self.build_tree(['tree/a'])
83
84=== modified file 'bzrlib/tests/bzrdir_implementations/test_bzrdir.py'
85--- bzrlib/tests/bzrdir_implementations/test_bzrdir.py 2009-04-28 03:55:56 +0000
86+++ bzrlib/tests/bzrdir_implementations/test_bzrdir.py 2009-06-11 11:35:12 +0000
87@@ -1246,6 +1246,36 @@
88 self.assertTrue(repo.is_write_locked())
89 repo.unlock()
90
91+ def test_format_initialize_on_transport_ex_default_stack_on(self):
92+ # When initialize_on_transport_ex uses a stacked-on branch because of
93+ # a stacking policy on the target, the location of the fallback
94+ # repository is the same as the external location of the stacked-on
95+ # branch.
96+ balloon = self.make_bzrdir('balloon')
97+ if isinstance(balloon, bzrdir.BzrDirMetaFormat1):
98+ stack_on = self.make_branch('stack-on', format='1.9')
99+ else:
100+ stack_on = self.make_branch('stack-on')
101+ config = self.make_bzrdir('.').get_config()
102+ try:
103+ config.set_default_stack_on('stack-on')
104+ except errors.BzrError:
105+ raise TestNotApplicable('Only relevant for stackable formats.')
106+ # Initialize a bzrdir subject to the policy.
107+ t = self.get_transport('stacked')
108+ repo_fmt = bzrdir.format_registry.make_bzrdir('1.9')
109+ repo_name = repo_fmt.repository_format.network_name()
110+ repo, control = self.assertInitializeEx(
111+ t, need_meta=True, repo_format_name=repo_name, stacked_on=None)
112+ if control is None:
113+ # uninitialisable format
114+ return
115+ # There's one fallback repo, with a public location.
116+ self.assertLength(1, repo._fallback_repositories)
117+ fallback_repo = repo._fallback_repositories[0]
118+ self.assertEqual(
119+ stack_on.base, fallback_repo.bzrdir.root_transport.base)
120+
121 def test_format_initialize_on_transport_ex_repo_fmt_name_None(self):
122 t = self.get_transport('dir')
123 repo, control = self.assertInitializeEx(t)
124
125=== modified file 'bzrlib/tests/test_bzrdir.py'
126--- bzrlib/tests/test_bzrdir.py 2009-03-23 14:59:43 +0000
127+++ bzrlib/tests/test_bzrdir.py 2009-06-11 11:35:12 +0000
128@@ -20,8 +20,6 @@
129 """
130
131 import os
132-import os.path
133-from StringIO import StringIO
134 import subprocess
135 import sys
136
137@@ -31,7 +29,6 @@
138 help_topics,
139 repository,
140 osutils,
141- symbol_versioning,
142 remote,
143 urlutils,
144 win32utils,
145@@ -47,7 +44,6 @@
146 TestCaseWithMemoryTransport,
147 TestCaseWithTransport,
148 TestSkipped,
149- test_sftp_transport
150 )
151 from bzrlib.tests import(
152 http_server,
153
154=== modified file 'bzrlib/tests/test_smart.py'
155--- bzrlib/tests/test_smart.py 2009-06-10 03:56:49 +0000
156+++ bzrlib/tests/test_smart.py 2009-06-11 11:35:12 +0000
157@@ -381,7 +381,7 @@
158 'subdir/dir', 'False', 'False', 'False', '', '', '', '', 'False')
159
160 def test_initialized_dir(self):
161- """Initializing an extant dirctory should fail like the bzrdir api."""
162+ """Initializing an extant directory should fail like the bzrdir api."""
163 backing = self.get_transport()
164 name = self.make_bzrdir('reference')._format.network_name()
165 request = smart.bzrdir.SmartServerRequestBzrDirInitializeEx(backing)