Merge lp:~vila/bzr/cached-branch-store into lp:bzr
- cached-branch-store
- Merge into bzr.dev
Status: | Merged |
---|---|
Approved by: | Martin Packman |
Approved revision: | no longer in the source branch. |
Merged at revision: | 6468 |
Proposed branch: | lp:~vila/bzr/cached-branch-store |
Merge into: | lp:bzr |
Diff against target: |
1574 lines (+343/-213) 33 files modified
bzrlib/branch.py (+22/-9) bzrlib/builtins.py (+12/-5) bzrlib/config.py (+48/-19) bzrlib/controldir.py (+3/-1) bzrlib/foreign.py (+2/-1) bzrlib/plugins/launchpad/test_lp_open.py (+11/-9) bzrlib/push.py (+2/-1) bzrlib/remote.py (+19/-18) bzrlib/switch.py (+10/-6) bzrlib/tests/blackbox/test_bound_branches.py (+11/-2) bzrlib/tests/blackbox/test_checkout.py (+1/-1) bzrlib/tests/blackbox/test_commit.py (+1/-1) bzrlib/tests/blackbox/test_dpush.py (+4/-5) bzrlib/tests/blackbox/test_info.py (+3/-3) bzrlib/tests/blackbox/test_log.py (+3/-3) bzrlib/tests/blackbox/test_merge.py (+17/-5) bzrlib/tests/blackbox/test_merge_directive.py (+2/-1) bzrlib/tests/blackbox/test_pull.py (+11/-5) bzrlib/tests/blackbox/test_push.py (+15/-9) bzrlib/tests/blackbox/test_reconfigure.py (+10/-10) bzrlib/tests/blackbox/test_send.py (+9/-10) bzrlib/tests/blackbox/test_switch.py (+5/-2) bzrlib/tests/blackbox/test_whoami.py (+12/-10) bzrlib/tests/per_branch/test_branch.py (+1/-17) bzrlib/tests/per_branch/test_break_lock.py (+3/-2) bzrlib/tests/per_branch/test_create_clone.py (+1/-2) bzrlib/tests/test_branch.py (+3/-3) bzrlib/tests/test_config.py (+34/-3) bzrlib/tests/test_directory_service.py (+21/-23) bzrlib/tests/test_info.py (+9/-5) bzrlib/tests/test_reconfigure.py (+16/-4) bzrlib/tests/test_remote.py (+16/-15) bzrlib/tests/test_smart.py (+6/-3) |
To merge this branch: | bzr merge lp:~vila/bzr/cached-branch-store |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Packman (community) | Approve | ||
Review via email: mp+87985@code.launchpad.net |
Commit message
Cache the branch config store to avoid useless IOs.
Description of the change
This is it !
Well, this doesn't fix bug #832042 yet (the local config files still writes
the config file on every option change but the related fix will be 1) far
simpler than this one, 2) raises different but simpler issues. So I focus on
the branch config here).
Summary: Instead of writing the branch.conf config file on each
modification, it keeps track of the modifications and write the file when
the branch is unlocked (reading it again to guard against users of the old
config API).
I'm confident this proposal is technically correct both in the
implementation and in the implied code and test fixes introduced by the
change in locking. Yet, while these fixes are quite easy once you understand
the issues, it seems a bit risky to land it so late in the series
cycle. Something is missing for that and I'd like feedback about it.
Long story:
To avoid writing the config file for every branch option change, all the
changes are batched and the write happens at the last possible time.
Since this is a write operation on a branch, it requires a locked
branch. Therefore the write happens when the branch is unlocked.
I can't describe it more concisely but this doesn't clearly expose the
fallouts.
The real question here is: when should the branch be *locked* ?
There are two possible answers to that:
1 - before the first change is attempted (set() or remove()),
2 - before the config file needs to be saved.
In the actual implementation (and that's true for both the configobj based
implementation and the stack based one), *every* change takes a lock on the
branch *and* write the file (this is implemented in _CompatibleStack so it
applies to the local config files as well except they use a lockdir instead
of a branch of course).
Avoiding these writes means we keep the changes in memory. As such the
branch doesn't need to be locked which makes (2) compelling.
The main drawback is of course that these changes are not saved to disk and
the main consequence is that blackbox tests become broken: modifying an
option in a branch object is not enough to make it available to a subsequent
run_bzr() call. All config changes should now happen in an explicitely
locked branch.
Likewise, if the run_bzr() call modifies a config option, the config file
needs to be reloaded to see this change. This is a bit more suprising and
requires an additional explanation: the *old* design were reading the config
file for each option and as such was immune from this issue. The new design
caches the config file so a change introduced by a run_bzr() call is not
seen. This happens when a branch config option is migrated to the new design
but not for the other options. It really depends on how and when they are
used but all the cases I've encountered so far make sense, see
bb.test_
acquiring the branch (via its wt) *after* the run rather than before to get
the right behavior. The changes in test_bound_branches are required as soon
as 'bound_location' is using the new design *and* this proposal. Note that
some tests were already aware of similar issues: search for 're-open tree as
external run_bzr modified it' in bb.test_merge for such examples.
So, not a new issue but an almost unknown one that becomes far more common
with this proposal.
Back to the proposal, you'll see four kind of changes:
- implement the caching for the config store in Branch and RemoteBranch,
this includes sharing the same store between a RemoteBranch and its
related _real_branch (the core of this proposal),
- fixes to code so the option changes are saved to disk at the right time
Converter5to6, Converter6to7 in branch.py, cmd_pull, cmd_init, cmd_whoami,
cmd_merge_
controldir.
examples. Special note for the infamous stacked_on_url that needs to be
seen by both the client and the server in all cases.
- fixes blackbox tests that requires a locked branch for option changes to
be saved on disk (the idiom is an added lock_write(
options/finally: unlock(). Suggestions welcome to make this easier to
spell, a context manager thingy to do with locked(branch): ?
- fixes blackbox tests that requires a fresh object to observe option
changes, the idiom is br = br.bzrdir.
So the missing bit I alluded in the introduction is probably something along
the following lines:
- set()/remove() requires a lock and triggers a config file write for
backward compatibility
- we fix the spurious writes above by locking the branch at a higher level
when/where needed as I did here both in code and in tests.
- add a reload() method to stacks so blackbox tests can reload only the
config stack instead of the whole object.
I deleted
bzrlib.
as the trick used in the test is unlikely to be used in real life and not
valid anymore anyway.
Vincent Ladeuil (vila) wrote : | # |
Vincent Ladeuil (vila) wrote : | # |
Forgot to mention: I didn't implement .reload() for stacks, not enough tests will benefit from that and that still needs to be fixed on a case by case basis (where/when it fails).
In the wild, there shouldn't be much cases of people using the new config API while relying on the config files to magically refresh themselves (or expecting to observe a side effect of a bzr command in a different process via a config option).
Martin Packman (gz) wrote : | # |
Much nicer with the reduced lock/unlock requirement, and approach seems good overall.
One thing I'm not clear on is whether all the branch methods like Branch.
If a plugin author wants to reduce the amount of pointless config-writing in their code, how would they go about tracking down where they need to add locking?
Documenting in what's new and landing on 2.5 seems required to me.
Vincent Ladeuil (vila) wrote : | # |
Thanks a lot for the review !
> Much nicer with the reduced lock/unlock requirement, and approach seems good
> overall.
>
> One thing I'm not clear on is whether all the branch methods like
> Branch.
> @needs_write_lock decorator.
No, because ultimately they will call stack.set().
> I guess as BranchStack mutating methods do that
> anyway so it's unimportant.
Indeed.
>
> If a plugin author wants to reduce the amount of pointless config-writing in
> their code, how would they go about tracking down where they need to add
> locking?
That's the main loss of making the behavior "opt-in". There is no obvious failure anymore.
As plugins migrate to the new scheme we'll get more feedback ?
>
> Documenting in what's new and landing on 2.5 seems required to me.
I need to think a bit more about it (I'd like a full fix for bug #832042 first which I'm working on right now, mainly the local config stores should be cached too).
Vincent Ladeuil (vila) wrote : | # |
Branch refreshed, will land to trunk
Vincent Ladeuil (vila) wrote : | # |
Funnily enough, merging trunk made 3 tests fail. Cause ? Less hpss calls !
Vincent Ladeuil (vila) wrote : | # |
sent to pqm by email
Preview Diff
1 | === modified file 'bzrlib/branch.py' |
2 | --- bzrlib/branch.py 2012-01-27 14:56:06 +0000 |
3 | +++ bzrlib/branch.py 2012-02-14 17:36:32 +0000 |
4 | @@ -1,4 +1,4 @@ |
5 | -# Copyright (C) 2005-2011 Canonical Ltd |
6 | +# Copyright (C) 2005-2012 Canonical Ltd |
7 | # |
8 | # This program is free software; you can redistribute it and/or modify |
9 | # it under the terms of the GNU General Public License as published by |
10 | @@ -2481,6 +2481,7 @@ |
11 | self.control_files = _control_files |
12 | self._transport = _control_files._transport |
13 | self.repository = _repository |
14 | + self.conf_store = None |
15 | Branch.__init__(self, possible_transports) |
16 | |
17 | def __str__(self): |
18 | @@ -2502,7 +2503,9 @@ |
19 | return _mod_config.TransportConfig(self._transport, 'branch.conf') |
20 | |
21 | def _get_config_store(self): |
22 | - return _mod_config.BranchStore(self) |
23 | + if self.conf_store is None: |
24 | + self.conf_store = _mod_config.BranchStore(self) |
25 | + return self.conf_store |
26 | |
27 | def is_locked(self): |
28 | return self.control_files.is_locked() |
29 | @@ -2557,6 +2560,8 @@ |
30 | |
31 | @only_raises(errors.LockNotHeld, errors.LockBroken) |
32 | def unlock(self): |
33 | + if self.conf_store is not None: |
34 | + self.conf_store.save_changes() |
35 | try: |
36 | self.control_files.unlock() |
37 | finally: |
38 | @@ -3245,9 +3250,13 @@ |
39 | |
40 | # Copy source data into target |
41 | new_branch._write_last_revision_info(*branch.last_revision_info()) |
42 | - new_branch.set_parent(branch.get_parent()) |
43 | - new_branch.set_bound_location(branch.get_bound_location()) |
44 | - new_branch.set_push_location(branch.get_push_location()) |
45 | + new_branch.lock_write() |
46 | + try: |
47 | + new_branch.set_parent(branch.get_parent()) |
48 | + new_branch.set_bound_location(branch.get_bound_location()) |
49 | + new_branch.set_push_location(branch.get_push_location()) |
50 | + finally: |
51 | + new_branch.unlock() |
52 | |
53 | # New branch has no tags by default |
54 | new_branch.tags._set_tag_dict({}) |
55 | @@ -3259,11 +3268,15 @@ |
56 | |
57 | # Clean up old files |
58 | new_branch._transport.delete('revision-history') |
59 | + branch.lock_write() |
60 | try: |
61 | - branch.set_parent(None) |
62 | - except errors.NoSuchFile: |
63 | - pass |
64 | - branch.set_bound_location(None) |
65 | + try: |
66 | + branch.set_parent(None) |
67 | + except errors.NoSuchFile: |
68 | + pass |
69 | + branch.set_bound_location(None) |
70 | + finally: |
71 | + branch.unlock() |
72 | |
73 | |
74 | class Converter6to7(object): |
75 | |
76 | === modified file 'bzrlib/builtins.py' |
77 | --- bzrlib/builtins.py 2012-02-07 13:18:40 +0000 |
78 | +++ bzrlib/builtins.py 2012-02-14 17:36:32 +0000 |
79 | @@ -1,4 +1,4 @@ |
80 | -# Copyright (C) 2005-2011 Canonical Ltd |
81 | +# Copyright (C) 2005-2012 Canonical Ltd |
82 | # |
83 | # This program is free software; you can redistribute it and/or modify |
84 | # it under the terms of the GNU General Public License as published by |
85 | @@ -1205,6 +1205,8 @@ |
86 | # Remembers if asked explicitly or no previous location is set |
87 | if (remember |
88 | or (remember is None and branch_to.get_parent() is None)): |
89 | + # FIXME: This shouldn't be done before the pull |
90 | + # succeeds... -- vila 2012-01-02 |
91 | branch_to.set_parent(branch_from.base) |
92 | |
93 | if revision is not None: |
94 | @@ -3861,7 +3863,9 @@ |
95 | if directory is None: |
96 | c = Branch.open_containing(u'.')[0].get_config_stack() |
97 | else: |
98 | - c = Branch.open(directory).get_config_stack() |
99 | + b = Branch.open(directory) |
100 | + self.add_cleanup(b.lock_write().unlock) |
101 | + c = b.get_config_stack() |
102 | else: |
103 | c = _mod_config.GlobalStack() |
104 | c.set('email', name) |
105 | @@ -5261,10 +5265,12 @@ |
106 | else: |
107 | if location is None: |
108 | if b.get_bound_location() is not None: |
109 | - raise errors.BzrCommandError(gettext('Branch is already bound')) |
110 | + raise errors.BzrCommandError( |
111 | + gettext('Branch is already bound')) |
112 | else: |
113 | - raise errors.BzrCommandError(gettext('No location supplied ' |
114 | - 'and no previous location known')) |
115 | + raise errors.BzrCommandError( |
116 | + gettext('No location supplied' |
117 | + ' and no previous location known')) |
118 | b_other = Branch.open(location) |
119 | try: |
120 | b.bind(b_other) |
121 | @@ -5680,6 +5686,7 @@ |
122 | if public_branch is None: |
123 | public_branch = stored_public_branch |
124 | elif stored_public_branch is None: |
125 | + # FIXME: Should be done only if we succeed ? -- vila 2012-01-03 |
126 | branch.set_public_branch(public_branch) |
127 | if not include_bundle and public_branch is None: |
128 | raise errors.BzrCommandError(gettext('No public branch specified or' |
129 | |
130 | === modified file 'bzrlib/config.py' |
131 | --- bzrlib/config.py 2012-02-07 00:49:58 +0000 |
132 | +++ bzrlib/config.py 2012-02-14 17:36:32 +0000 |
133 | @@ -3416,20 +3416,6 @@ |
134 | self.branch = branch |
135 | self.id = 'branch' |
136 | |
137 | - def lock_write(self, token=None): |
138 | - return self.branch.lock_write(token) |
139 | - |
140 | - def unlock(self): |
141 | - return self.branch.unlock() |
142 | - |
143 | - @needs_write_lock |
144 | - def save(self): |
145 | - # We need to be able to override the undecorated implementation |
146 | - self.save_without_locking() |
147 | - |
148 | - def save_without_locking(self): |
149 | - super(BranchStore, self).save() |
150 | - |
151 | |
152 | class ControlStore(LockableIniFileStore): |
153 | |
154 | @@ -3939,7 +3925,7 @@ |
155 | lstore, mutable_section_id=location) |
156 | |
157 | |
158 | -class BranchStack(_CompatibleStack): |
159 | +class BranchStack(Stack): |
160 | """Per-location options falling back to branch then global options stack. |
161 | |
162 | The following sections are queried: |
163 | @@ -3970,6 +3956,24 @@ |
164 | bstore) |
165 | self.branch = branch |
166 | |
167 | + def lock_write(self, token=None): |
168 | + return self.branch.lock_write(token) |
169 | + |
170 | + def unlock(self): |
171 | + return self.branch.unlock() |
172 | + |
173 | + @needs_write_lock |
174 | + def set(self, name, value): |
175 | + super(BranchStack, self).set(name, value) |
176 | + # Unlocking the branch will trigger a store.save_changes() so the last |
177 | + # unlock saves all the changes. |
178 | + |
179 | + @needs_write_lock |
180 | + def remove(self, name): |
181 | + super(BranchStack, self).remove(name) |
182 | + # Unlocking the branch will trigger a store.save_changes() so the last |
183 | + # unlock saves all the changes. |
184 | + |
185 | |
186 | class RemoteControlStack(_CompatibleStack): |
187 | """Remote control-only options stack.""" |
188 | @@ -3986,7 +3990,7 @@ |
189 | self.bzrdir = bzrdir |
190 | |
191 | |
192 | -class BranchOnlyStack(_CompatibleStack): |
193 | +class BranchOnlyStack(Stack): |
194 | """Branch-only options stack.""" |
195 | |
196 | # FIXME: _BranchOnlyStack only uses branch.conf and is used only for the |
197 | @@ -4000,6 +4004,24 @@ |
198 | bstore) |
199 | self.branch = branch |
200 | |
201 | + def lock_write(self, token=None): |
202 | + return self.branch.lock_write(token) |
203 | + |
204 | + def unlock(self): |
205 | + return self.branch.unlock() |
206 | + |
207 | + @needs_write_lock |
208 | + def set(self, name, value): |
209 | + super(BranchOnlyStack, self).set(name, value) |
210 | + # Force a write to persistent storage |
211 | + self.store.save_changes() |
212 | + |
213 | + @needs_write_lock |
214 | + def remove(self, name): |
215 | + super(BranchOnlyStack, self).remove(name) |
216 | + # Force a write to persistent storage |
217 | + self.store.save_changes() |
218 | + |
219 | |
220 | # Use a an empty dict to initialize an empty configobj avoiding all |
221 | # parsing and encoding checks |
222 | @@ -4072,12 +4094,15 @@ |
223 | # Set the option value |
224 | self._set_config_option(name, value, directory, scope) |
225 | |
226 | - def _get_stack(self, directory, scope=None): |
227 | + def _get_stack(self, directory, scope=None, write_access=False): |
228 | """Get the configuration stack specified by ``directory`` and ``scope``. |
229 | |
230 | :param directory: Where the configurations are derived from. |
231 | |
232 | :param scope: A specific config to start from. |
233 | + |
234 | + :param write_access: Whether a write access to the stack will be |
235 | + attempted. |
236 | """ |
237 | # FIXME: scope should allow access to plugin-specific stacks (even |
238 | # reduced to the plugin-specific store), related to |
239 | @@ -4091,6 +4116,8 @@ |
240 | (_, br, _) = ( |
241 | controldir.ControlDir.open_containing_tree_or_branch( |
242 | directory)) |
243 | + if write_access: |
244 | + self.add_cleanup(br.lock_write().unlock) |
245 | return br.get_config_stack() |
246 | raise errors.NoSuchConfig(scope) |
247 | else: |
248 | @@ -4098,6 +4125,8 @@ |
249 | (_, br, _) = ( |
250 | controldir.ControlDir.open_containing_tree_or_branch( |
251 | directory)) |
252 | + if write_access: |
253 | + self.add_cleanup(br.lock_write().unlock) |
254 | return br.get_config_stack() |
255 | except errors.NotBranchError: |
256 | return LocationStack(directory) |
257 | @@ -4148,14 +4177,14 @@ |
258 | self.outf.write(' %s = %s\n' % (oname, value)) |
259 | |
260 | def _set_config_option(self, name, value, directory, scope): |
261 | - conf = self._get_stack(directory, scope) |
262 | + conf = self._get_stack(directory, scope, write_access=True) |
263 | conf.set(name, value) |
264 | |
265 | def _remove_config_option(self, name, directory, scope): |
266 | if name is None: |
267 | raise errors.BzrCommandError( |
268 | '--remove expects an option to remove.') |
269 | - conf = self._get_stack(directory, scope) |
270 | + conf = self._get_stack(directory, scope, write_access=True) |
271 | try: |
272 | conf.remove(name) |
273 | except KeyError: |
274 | |
275 | === modified file 'bzrlib/controldir.py' |
276 | --- bzrlib/controldir.py 2012-01-31 15:43:17 +0000 |
277 | +++ bzrlib/controldir.py 2012-02-14 17:36:32 +0000 |
278 | @@ -1,4 +1,4 @@ |
279 | -# Copyright (C) 2010, 2011 Canonical Ltd |
280 | +# Copyright (C) 2010, 2011, 2012 Canonical Ltd |
281 | # |
282 | # This program is free software; you can redistribute it and/or modify |
283 | # it under the terms of the GNU General Public License as published by |
284 | @@ -406,6 +406,7 @@ |
285 | repository_to.fetch(source.repository, revision_id=revision_id) |
286 | br_to = source.clone(self, revision_id=revision_id) |
287 | if source.get_push_location() is None or remember: |
288 | + # FIXME: Should be done only if we succeed ? -- vila 2012-01-18 |
289 | source.set_push_location(br_to.base) |
290 | push_result.stacked_on = None |
291 | push_result.branch_push_result = None |
292 | @@ -417,6 +418,7 @@ |
293 | else: |
294 | # We have successfully opened the branch, remember if necessary: |
295 | if source.get_push_location() is None or remember: |
296 | + # FIXME: Should be done only if we succeed ? -- vila 2012-01-18 |
297 | source.set_push_location(br_to.base) |
298 | try: |
299 | tree_to = self.open_workingtree() |
300 | |
301 | === modified file 'bzrlib/foreign.py' |
302 | --- bzrlib/foreign.py 2011-12-19 13:23:58 +0000 |
303 | +++ bzrlib/foreign.py 2012-02-14 17:36:32 +0000 |
304 | @@ -1,4 +1,4 @@ |
305 | -# Copyright (C) 2008-2011 Canonical Ltd |
306 | +# Copyright (C) 2008-2012 Canonical Ltd |
307 | # |
308 | # This program is free software; you can redistribute it and/or modify |
309 | # it under the terms of the GNU General Public License as published by |
310 | @@ -323,6 +323,7 @@ |
311 | source_branch, target_branch)) |
312 | # We successfully created the target, remember it |
313 | if source_branch.get_push_location() is None or remember: |
314 | + # FIXME: Should be done only if we succeed ? -- vila 2012-01-18 |
315 | source_branch.set_push_location(target_branch.base) |
316 | if not no_rebase: |
317 | old_last_revid = source_branch.last_revision() |
318 | |
319 | === modified file 'bzrlib/plugins/launchpad/test_lp_open.py' |
320 | --- bzrlib/plugins/launchpad/test_lp_open.py 2010-12-02 09:23:10 +0000 |
321 | +++ bzrlib/plugins/launchpad/test_lp_open.py 2012-02-14 17:36:32 +0000 |
322 | @@ -1,4 +1,4 @@ |
323 | -# Copyright (C) 2009, 2010 Canonical Ltd |
324 | +# Copyright (C) 2009, 2010, 2012 Canonical Ltd |
325 | # |
326 | # This program is free software; you can redistribute it and/or modify |
327 | # it under the terms of the GNU General Public License as published by |
328 | @@ -51,8 +51,7 @@ |
329 | |
330 | def test_launchpad_branch_with_public_location(self): |
331 | branch = self.make_branch('lp') |
332 | - branch.set_public_branch( |
333 | - 'bzr+ssh://bazaar.launchpad.net/~foo/bar/baz') |
334 | + branch.set_public_branch('bzr+ssh://bazaar.launchpad.net/~foo/bar/baz') |
335 | self.assertEqual( |
336 | ['Opening https://code.launchpad.net/~foo/bar/baz in web ' |
337 | 'browser'], |
338 | @@ -60,10 +59,14 @@ |
339 | |
340 | def test_launchpad_branch_with_public_and_push_location(self): |
341 | branch = self.make_branch('lp') |
342 | - branch.set_public_branch( |
343 | - 'bzr+ssh://bazaar.launchpad.net/~foo/bar/public') |
344 | - branch.set_push_location( |
345 | - 'bzr+ssh://bazaar.launchpad.net/~foo/bar/push') |
346 | + branch.lock_write() |
347 | + try: |
348 | + branch.set_public_branch( |
349 | + 'bzr+ssh://bazaar.launchpad.net/~foo/bar/public') |
350 | + branch.set_push_location( |
351 | + 'bzr+ssh://bazaar.launchpad.net/~foo/bar/push') |
352 | + finally: |
353 | + branch.unlock() |
354 | self.assertEqual( |
355 | ['Opening https://code.launchpad.net/~foo/bar/public in web ' |
356 | 'browser'], |
357 | @@ -73,8 +76,7 @@ |
358 | # lp-open falls back to the push location if it cannot find a public |
359 | # location. |
360 | branch = self.make_branch('lp') |
361 | - branch.set_push_location( |
362 | - 'bzr+ssh://bazaar.launchpad.net/~foo/bar/baz') |
363 | + branch.set_push_location('bzr+ssh://bazaar.launchpad.net/~foo/bar/baz') |
364 | self.assertEqual( |
365 | ['Opening https://code.launchpad.net/~foo/bar/baz in web ' |
366 | 'browser'], |
367 | |
368 | === modified file 'bzrlib/push.py' |
369 | --- bzrlib/push.py 2012-01-19 17:23:00 +0000 |
370 | +++ bzrlib/push.py 2012-02-14 17:36:32 +0000 |
371 | @@ -1,4 +1,4 @@ |
372 | -# Copyright (C) 2008, 2009, 2010 Canonical Ltd |
373 | +# Copyright (C) 2008-2012 Canonical Ltd |
374 | # |
375 | # This program is free software; you can redistribute it and/or modify |
376 | # it under the terms of the GNU General Public License as published by |
377 | @@ -135,6 +135,7 @@ |
378 | # Remembers if asked explicitly or no previous location is set |
379 | if (remember |
380 | or (remember is None and br_from.get_push_location() is None)): |
381 | + # FIXME: Should be done only if we succeed ? -- vila 2012-01-18 |
382 | br_from.set_push_location(br_to.base) |
383 | else: |
384 | if stacked_on is not None: |
385 | |
386 | === modified file 'bzrlib/remote.py' |
387 | --- bzrlib/remote.py 2012-01-28 00:56:56 +0000 |
388 | +++ bzrlib/remote.py 2012-02-14 17:36:32 +0000 |
389 | @@ -1,4 +1,4 @@ |
390 | -# Copyright (C) 2006-2011 Canonical Ltd |
391 | +# Copyright (C) 2006-2012 Canonical Ltd |
392 | # |
393 | # This program is free software; you can redistribute it and/or modify |
394 | # it under the terms of the GNU General Public License as published by |
395 | @@ -3262,20 +3262,6 @@ |
396 | self.id = "branch" |
397 | self._real_store = None |
398 | |
399 | - def lock_write(self, token=None): |
400 | - return self.branch.lock_write(token) |
401 | - |
402 | - def unlock(self): |
403 | - return self.branch.unlock() |
404 | - |
405 | - @needs_write_lock |
406 | - def save(self): |
407 | - # We need to be able to override the undecorated implementation |
408 | - self.save_without_locking() |
409 | - |
410 | - def save_without_locking(self): |
411 | - super(RemoteBranchStore, self).save() |
412 | - |
413 | def external_url(self): |
414 | return self.branch.user_url |
415 | |
416 | @@ -3366,6 +3352,7 @@ |
417 | self._repo_lock_token = None |
418 | self._lock_count = 0 |
419 | self._leave_lock = False |
420 | + self.conf_store = None |
421 | # Setup a format: note that we cannot call _ensure_real until all the |
422 | # attributes above are set: This code cannot be moved higher up in this |
423 | # function. |
424 | @@ -3414,7 +3401,9 @@ |
425 | return RemoteBranchConfig(self) |
426 | |
427 | def _get_config_store(self): |
428 | - return RemoteBranchStore(self) |
429 | + if self.conf_store is None: |
430 | + self.conf_store = RemoteBranchStore(self) |
431 | + return self.conf_store |
432 | |
433 | def _get_real_transport(self): |
434 | # if we try vfs access, return the real branch's vfs transport |
435 | @@ -3440,6 +3429,10 @@ |
436 | self.bzrdir._ensure_real() |
437 | self._real_branch = self.bzrdir._real_bzrdir.open_branch( |
438 | ignore_fallbacks=self._real_ignore_fallbacks, name=self._name) |
439 | + # The remote branch and the real branch shares the same store. If |
440 | + # we don't, there will always be cases where one of the stores |
441 | + # doesn't see an update made on the other. |
442 | + self._real_branch.conf_store = self.conf_store |
443 | if self.repository._real_repository is None: |
444 | # Give the remote repository the matching real repo. |
445 | real_repo = self._real_branch.repository |
446 | @@ -3523,6 +3516,13 @@ |
447 | |
448 | def set_stacked_on_url(self, url): |
449 | branch.Branch.set_stacked_on_url(self, url) |
450 | + # We need the stacked_on_url to be visible both locally (to not query |
451 | + # it repeatedly) and remotely (so smart verbs can get it server side) |
452 | + # Without the following line, |
453 | + # bzrlib.tests.per_branch.test_create_clone.TestCreateClone |
454 | + # .test_create_clone_on_transport_stacked_hooks_get_stacked_branch |
455 | + # fails for remote branches -- vila 2012-01-04 |
456 | + self.conf_store.save_changes() |
457 | if not url: |
458 | self._is_stacked = False |
459 | else: |
460 | @@ -3656,6 +3656,8 @@ |
461 | try: |
462 | self._lock_count -= 1 |
463 | if not self._lock_count: |
464 | + if self.conf_store is not None: |
465 | + self.conf_store.save_changes() |
466 | self._clear_cached_state() |
467 | mode = self._lock_mode |
468 | self._lock_mode = None |
469 | @@ -3951,8 +3953,7 @@ |
470 | last_rev=last_rev,other_branch=other_branch)) |
471 | |
472 | def set_push_location(self, location): |
473 | - self._ensure_real() |
474 | - return self._real_branch.set_push_location(location) |
475 | + self._set_config_location('push_location', location) |
476 | |
477 | def heads_to_fetch(self): |
478 | if self._format._use_default_local_heads_to_fetch(): |
479 | |
480 | === modified file 'bzrlib/switch.py' |
481 | --- bzrlib/switch.py 2012-01-26 15:31:02 +0000 |
482 | +++ bzrlib/switch.py 2012-02-14 17:36:32 +0000 |
483 | @@ -1,4 +1,4 @@ |
484 | -# Copyright (C) 2007, 2009, 2010 Canonical Ltd. |
485 | +# Copyright (C) 2007, 2009-2012 Canonical Ltd. |
486 | # |
487 | # This program is free software; you can redistribute it and/or modify |
488 | # it under the terms of the GNU General Public License as published by |
489 | @@ -105,11 +105,15 @@ |
490 | 'Unable to connect to current master branch %(target)s: ' |
491 | '%(error)s To switch anyway, use --force.') % |
492 | e.__dict__) |
493 | - b.set_bound_location(None) |
494 | - b.pull(to_branch, overwrite=True, |
495 | - possible_transports=possible_transports) |
496 | - b.set_bound_location(to_branch.base) |
497 | - b.set_parent(b.get_master_branch().get_parent()) |
498 | + b.lock_write() |
499 | + try: |
500 | + b.set_bound_location(None) |
501 | + b.pull(to_branch, overwrite=True, |
502 | + possible_transports=possible_transports) |
503 | + b.set_bound_location(to_branch.base) |
504 | + b.set_parent(b.get_master_branch().get_parent()) |
505 | + finally: |
506 | + b.unlock() |
507 | else: |
508 | # If this is a standalone tree and the new branch |
509 | # is derived from this one, create a lightweight checkout. |
510 | |
511 | === modified file 'bzrlib/tests/blackbox/test_bound_branches.py' |
512 | --- bzrlib/tests/blackbox/test_bound_branches.py 2012-01-05 13:02:31 +0000 |
513 | +++ bzrlib/tests/blackbox/test_bound_branches.py 2012-02-14 17:36:32 +0000 |
514 | @@ -127,12 +127,13 @@ |
515 | |
516 | def test_double_binding(self): |
517 | child_tree = self.create_branches()[1] |
518 | - |
519 | - child2_tree = child_tree.bzrdir.sprout('child2').open_workingtree() |
520 | + child_tree.bzrdir.sprout('child2') |
521 | |
522 | # Double binding succeeds, but committing to child2 should fail |
523 | self.run_bzr('bind ../child', working_dir='child2') |
524 | |
525 | + # Refresh the child tree object as 'unbind' modified it |
526 | + child2_tree = bzrdir.BzrDir.open('child2').open_workingtree() |
527 | self.assertRaises(errors.CommitToDoubleBoundBranch, |
528 | child2_tree.commit, message='child2', allow_pointless=True) |
529 | |
530 | @@ -150,6 +151,8 @@ |
531 | self.run_bzr("commit -m child", retcode=3, working_dir='child') |
532 | self.check_revno(1, 'child') |
533 | self.run_bzr('unbind', working_dir='child') |
534 | + # Refresh the child tree/branch objects as 'unbind' modified them |
535 | + child_tree = child_tree.bzrdir.open_workingtree() |
536 | child_tree.commit(message='child') |
537 | self.check_revno(2, 'child') |
538 | |
539 | @@ -200,6 +203,8 @@ |
540 | |
541 | self.run_bzr('unbind', working_dir='child') |
542 | |
543 | + # Refresh the child tree/branch objects as 'unbind' modified them |
544 | + child_tree = child_tree.bzrdir.open_workingtree() |
545 | child_tree.commit(message='child', allow_pointless=True) |
546 | self.check_revno(2, 'child') |
547 | |
548 | @@ -210,6 +215,8 @@ |
549 | # These branches have diverged, but bind should succeed anyway |
550 | self.run_bzr('bind ../base', working_dir='child') |
551 | |
552 | + # Refresh the child tree/branch objects as 'bind' modified them |
553 | + child_tree = child_tree.bzrdir.open_workingtree() |
554 | # This should turn the local commit into a merge |
555 | child_tree.update() |
556 | child_tree.commit(message='merged') |
557 | @@ -248,6 +255,8 @@ |
558 | child_tree = self.create_branches()[1] |
559 | |
560 | self.run_bzr('unbind', working_dir='child') |
561 | + # Refresh the child tree/branch objects as 'bind' modified them |
562 | + child_tree = child_tree.bzrdir.open_workingtree() |
563 | child_tree.commit(message='child', allow_pointless=True) |
564 | self.check_revno(2, 'child') |
565 | self.check_revno(1, 'base') |
566 | |
567 | === modified file 'bzrlib/tests/blackbox/test_checkout.py' |
568 | --- bzrlib/tests/blackbox/test_checkout.py 2012-01-20 21:33:24 +0000 |
569 | +++ bzrlib/tests/blackbox/test_checkout.py 2012-02-14 17:36:32 +0000 |
570 | @@ -223,5 +223,5 @@ |
571 | # being too low. If rpc_count increases, more network roundtrips have |
572 | # become necessary for this use case. Please do not adjust this number |
573 | # upwards without agreement from bzr's network support maintainers. |
574 | - self.assertLength(15, self.hpss_calls) |
575 | + self.assertLength(13, self.hpss_calls) |
576 | self.assertThat(self.hpss_calls, ContainsNoVfsCalls) |
577 | |
578 | === modified file 'bzrlib/tests/blackbox/test_commit.py' |
579 | --- bzrlib/tests/blackbox/test_commit.py 2012-02-07 00:49:58 +0000 |
580 | +++ bzrlib/tests/blackbox/test_commit.py 2012-02-14 17:36:32 +0000 |
581 | @@ -887,7 +887,7 @@ |
582 | # being too low. If rpc_count increases, more network roundtrips have |
583 | # become necessary for this use case. Please do not adjust this number |
584 | # upwards without agreement from bzr's network support maintainers. |
585 | - self.assertLength(214, self.hpss_calls) |
586 | + self.assertLength(211, self.hpss_calls) |
587 | self.assertLength(2, self.hpss_connections) |
588 | self.expectFailure("commit still uses VFS calls", |
589 | self.assertThat, self.hpss_calls, ContainsNoVfsCalls) |
590 | |
591 | === modified file 'bzrlib/tests/blackbox/test_dpush.py' |
592 | --- bzrlib/tests/blackbox/test_dpush.py 2011-09-22 12:13:12 +0000 |
593 | +++ bzrlib/tests/blackbox/test_dpush.py 2012-02-14 17:36:32 +0000 |
594 | @@ -1,4 +1,4 @@ |
595 | -# Copyright (C) 2009, 2010, 2011 Canonical Ltd |
596 | +# Copyright (C) 2009-2012 Canonical Ltd |
597 | # |
598 | # This program is free software; you can redistribute it and/or modify |
599 | # it under the terms of the GNU General Public License as published by |
600 | @@ -19,6 +19,7 @@ |
601 | |
602 | |
603 | from bzrlib import ( |
604 | + branch, |
605 | tests, |
606 | ) |
607 | from bzrlib.tests import ( |
608 | @@ -144,10 +145,8 @@ |
609 | 'to', format=test_foreign.DummyForeignVcsDirFormat()) |
610 | |
611 | def set_config_push_strict(self, value): |
612 | - # set config var (any of bazaar.conf, locations.conf, branch.conf |
613 | - # should do) |
614 | - conf = self.tree.branch.get_config_stack() |
615 | - conf.set('dpush_strict', value) |
616 | + br = branch.Branch.open('local') |
617 | + br.get_config_stack().set('dpush_strict', value) |
618 | |
619 | _default_command = ['dpush', '../to'] |
620 | |
621 | |
622 | === modified file 'bzrlib/tests/blackbox/test_info.py' |
623 | --- bzrlib/tests/blackbox/test_info.py 2012-01-26 15:36:39 +0000 |
624 | +++ bzrlib/tests/blackbox/test_info.py 2012-02-14 17:36:32 +0000 |
625 | @@ -1,4 +1,4 @@ |
626 | -# Copyright (C) 2006-2010 Canonical Ltd |
627 | +# Copyright (C) 2006-2012 Canonical Ltd |
628 | # |
629 | # This program is free software; you can redistribute it and/or modify |
630 | # it under the terms of the GNU General Public License as published by |
631 | @@ -1548,7 +1548,7 @@ |
632 | # being too low. If rpc_count increases, more network roundtrips have |
633 | # become necessary for this use case. Please do not adjust this number |
634 | # upwards without agreement from bzr's network support maintainers. |
635 | - self.assertLength(12, self.hpss_calls) |
636 | + self.assertLength(10, self.hpss_calls) |
637 | self.assertLength(1, self.hpss_connections) |
638 | self.assertThat(self.hpss_calls, ContainsNoVfsCalls) |
639 | |
640 | @@ -1565,6 +1565,6 @@ |
641 | # being too low. If rpc_count increases, more network roundtrips have |
642 | # become necessary for this use case. Please do not adjust this number |
643 | # upwards without agreement from bzr's network support maintainers. |
644 | - self.assertLength(16, self.hpss_calls) |
645 | + self.assertLength(14, self.hpss_calls) |
646 | self.assertLength(1, self.hpss_connections) |
647 | self.assertThat(self.hpss_calls, ContainsNoVfsCalls) |
648 | |
649 | === modified file 'bzrlib/tests/blackbox/test_log.py' |
650 | --- bzrlib/tests/blackbox/test_log.py 2011-12-21 14:50:43 +0000 |
651 | +++ bzrlib/tests/blackbox/test_log.py 2012-02-14 17:36:32 +0000 |
652 | @@ -1096,7 +1096,7 @@ |
653 | # upwards without agreement from bzr's network support maintainers. |
654 | self.assertThat(self.hpss_calls, ContainsNoVfsCalls) |
655 | self.assertLength(1, self.hpss_connections) |
656 | - self.assertLength(10, self.hpss_calls) |
657 | + self.assertLength(9, self.hpss_calls) |
658 | |
659 | def test_verbose_log(self): |
660 | self.setup_smart_server_with_call_log() |
661 | @@ -1111,7 +1111,7 @@ |
662 | # being too low. If rpc_count increases, more network roundtrips have |
663 | # become necessary for this use case. Please do not adjust this number |
664 | # upwards without agreement from bzr's network support maintainers. |
665 | - self.assertLength(11, self.hpss_calls) |
666 | + self.assertLength(10, self.hpss_calls) |
667 | self.assertLength(1, self.hpss_connections) |
668 | self.assertThat(self.hpss_calls, ContainsNoVfsCalls) |
669 | |
670 | @@ -1128,6 +1128,6 @@ |
671 | # being too low. If rpc_count increases, more network roundtrips have |
672 | # become necessary for this use case. Please do not adjust this number |
673 | # upwards without agreement from bzr's network support maintainers. |
674 | - self.assertLength(15, self.hpss_calls) |
675 | + self.assertLength(14, self.hpss_calls) |
676 | self.assertLength(1, self.hpss_connections) |
677 | self.assertThat(self.hpss_calls, ContainsNoVfsCalls) |
678 | |
679 | === modified file 'bzrlib/tests/blackbox/test_merge.py' |
680 | --- bzrlib/tests/blackbox/test_merge.py 2012-01-05 13:02:31 +0000 |
681 | +++ bzrlib/tests/blackbox/test_merge.py 2012-02-14 17:36:32 +0000 |
682 | @@ -278,6 +278,8 @@ |
683 | |
684 | base = urlutils.local_path_from_url(branch_a.base) |
685 | self.assertEndsWith(err, '+N b\nAll changes applied successfully.\n') |
686 | + # re-open branch as external run_bzr modified it |
687 | + branch_b = branch_b.bzrdir.open_branch() |
688 | self.assertEquals(osutils.abspath(branch_b.get_submit_branch()), |
689 | osutils.abspath(parent)) |
690 | # test implicit --remember when committing new file |
691 | @@ -295,6 +297,8 @@ |
692 | working_dir='branch_b') |
693 | self.assertEquals(out, '') |
694 | self.assertEquals(err, '+N c\nAll changes applied successfully.\n') |
695 | + # re-open branch as external run_bzr modified it |
696 | + branch_b = branch_b.bzrdir.open_branch() |
697 | self.assertEquals(osutils.abspath(branch_b.get_submit_branch()), |
698 | osutils.abspath(branch_c.bzrdir.root_transport.base)) |
699 | # re-open tree as external run_bzr modified it |
700 | @@ -553,10 +557,16 @@ |
701 | tree_b = tree_a.bzrdir.sprout('b').open_workingtree() |
702 | tree_c = tree_a.bzrdir.sprout('c').open_workingtree() |
703 | out, err = self.run_bzr(['merge', '-d', 'c']) |
704 | - self.assertContainsRe(err, 'Merging from remembered parent location .*a\/') |
705 | - tree_c.branch.set_submit_branch(tree_b.bzrdir.root_transport.base) |
706 | + self.assertContainsRe(err, |
707 | + 'Merging from remembered parent location .*a\/') |
708 | + tree_c.branch.lock_write() |
709 | + try: |
710 | + tree_c.branch.set_submit_branch(tree_b.bzrdir.root_transport.base) |
711 | + finally: |
712 | + tree_c.branch.unlock() |
713 | out, err = self.run_bzr(['merge', '-d', 'c']) |
714 | - self.assertContainsRe(err, 'Merging from remembered submit location .*b\/') |
715 | + self.assertContainsRe(err, |
716 | + 'Merging from remembered submit location .*b\/') |
717 | |
718 | def test_remember_sets_submit(self): |
719 | tree_a = self.make_branch_and_tree('a') |
720 | @@ -566,11 +576,13 @@ |
721 | |
722 | # Remember should not happen if using default from parent |
723 | out, err = self.run_bzr(['merge', '-d', 'b']) |
724 | - self.assertIs(tree_b.branch.get_submit_branch(), None) |
725 | + refreshed = workingtree.WorkingTree.open('b') |
726 | + self.assertIs(refreshed.branch.get_submit_branch(), None) |
727 | |
728 | # Remember should happen if user supplies location |
729 | out, err = self.run_bzr(['merge', '-d', 'b', 'a']) |
730 | - self.assertEqual(tree_b.branch.get_submit_branch(), |
731 | + refreshed = workingtree.WorkingTree.open('b') |
732 | + self.assertEqual(refreshed.branch.get_submit_branch(), |
733 | tree_a.bzrdir.root_transport.base) |
734 | |
735 | def test_no_remember_dont_set_submit(self): |
736 | |
737 | === modified file 'bzrlib/tests/blackbox/test_merge_directive.py' |
738 | --- bzrlib/tests/blackbox/test_merge_directive.py 2012-01-05 17:46:44 +0000 |
739 | +++ bzrlib/tests/blackbox/test_merge_directive.py 2012-02-14 17:36:32 +0000 |
740 | @@ -223,7 +223,8 @@ |
741 | |
742 | def test_mail_uses_config(self): |
743 | tree1, tree2 = self.prepare_merge_directive() |
744 | - tree1.branch.get_config_stack().set('smtp_server', 'bogushost') |
745 | + br = tree1.branch |
746 | + br.get_config_stack().set('smtp_server', 'bogushost') |
747 | md_text, errr, connect_calls, sendmail_calls =\ |
748 | self.run_bzr_fakemail('merge-directive --mail-to' |
749 | ' pqm@example.com --plain ../tree2 .') |
750 | |
751 | === modified file 'bzrlib/tests/blackbox/test_pull.py' |
752 | --- bzrlib/tests/blackbox/test_pull.py 2012-01-05 17:46:44 +0000 |
753 | +++ bzrlib/tests/blackbox/test_pull.py 2012-02-14 17:36:32 +0000 |
754 | @@ -236,6 +236,7 @@ |
755 | tree_a.commit('commit b') |
756 | # reset parent |
757 | parent = branch_b.get_parent() |
758 | + branch_b = branch.Branch.open('branch_b') |
759 | branch_b.set_parent(None) |
760 | self.assertEqual(None, branch_b.get_parent()) |
761 | # test pull for failure without parent set |
762 | @@ -252,16 +253,22 @@ |
763 | ('','bzr: ERROR: These branches have diverged.' |
764 | ' Use the missing command to see how.\n' |
765 | 'Use the merge command to reconcile them.\n')) |
766 | - self.assertEqual(branch_b.get_parent(), parent) |
767 | + tree_b = tree_b.bzrdir.open_workingtree() |
768 | + branch_b = tree_b.branch |
769 | + self.assertEqual(parent, branch_b.get_parent()) |
770 | # test implicit --remember after resolving previous failure |
771 | uncommit.uncommit(branch=branch_b, tree=tree_b) |
772 | t.delete('branch_b/d') |
773 | self.run_bzr('pull', working_dir='branch_b') |
774 | + # Refresh the branch object as 'pull' modified it |
775 | + branch_b = branch_b.bzrdir.open_branch() |
776 | self.assertEqual(branch_b.get_parent(), parent) |
777 | # test explicit --remember |
778 | self.run_bzr('pull ../branch_c --remember', working_dir='branch_b') |
779 | - self.assertEqual(branch_b.get_parent(), |
780 | - branch_c.bzrdir.root_transport.base) |
781 | + # Refresh the branch object as 'pull' modified it |
782 | + branch_b = branch_b.bzrdir.open_branch() |
783 | + self.assertEqual(branch_c.bzrdir.root_transport.base, |
784 | + branch_b.get_parent()) |
785 | |
786 | def test_pull_bundle(self): |
787 | from bzrlib.testament import Testament |
788 | @@ -360,8 +367,7 @@ |
789 | def test_pull_verbose_uses_default_log(self): |
790 | tree = self.example_branch('source') |
791 | target = self.make_branch_and_tree('target') |
792 | - target_config = target.branch.get_config_stack() |
793 | - target_config.set('log_format', 'short') |
794 | + target.branch.get_config_stack().set('log_format', 'short') |
795 | out = self.run_bzr('pull -v source -d target')[0] |
796 | self.assertContainsRe(out, r'\n {4}1 .*\n {6}setup\n') |
797 | self.assertNotContainsRe( |
798 | |
799 | === modified file 'bzrlib/tests/blackbox/test_push.py' |
800 | --- bzrlib/tests/blackbox/test_push.py 2011-12-24 10:10:59 +0000 |
801 | +++ bzrlib/tests/blackbox/test_push.py 2012-02-14 17:36:32 +0000 |
802 | @@ -1,4 +1,4 @@ |
803 | -# Copyright (C) 2006-2011 Canonical Ltd |
804 | +# Copyright (C) 2006-2012 Canonical Ltd |
805 | # |
806 | # This program is free software; you can redistribute it and/or modify |
807 | # it under the terms of the GNU General Public License as published by |
808 | @@ -117,6 +117,8 @@ |
809 | self.assertEquals(out, |
810 | ('','bzr: ERROR: These branches have diverged. ' |
811 | 'See "bzr help diverged-branches" for more information.\n')) |
812 | + # Refresh the branch as 'push' modified it |
813 | + branch_a = branch_a.bzrdir.open_branch() |
814 | self.assertEquals(osutils.abspath(branch_a.get_push_location()), |
815 | osutils.abspath(branch_b.bzrdir.root_transport.base)) |
816 | |
817 | @@ -124,6 +126,8 @@ |
818 | uncommit.uncommit(branch=branch_b, tree=tree_b) |
819 | transport.delete('branch_b/c') |
820 | out, err = self.run_bzr('push', working_dir='branch_a') |
821 | + # Refresh the branch as 'push' modified it |
822 | + branch_a = branch_a.bzrdir.open_branch() |
823 | path = branch_a.get_push_location() |
824 | self.assertEqual(err, |
825 | 'Using saved push location: %s\n' |
826 | @@ -134,6 +138,8 @@ |
827 | branch_b.bzrdir.root_transport.base) |
828 | # test explicit --remember |
829 | self.run_bzr('push ../branch_c --remember', working_dir='branch_a') |
830 | + # Refresh the branch as 'push' modified it |
831 | + branch_a = branch_a.bzrdir.open_branch() |
832 | self.assertEquals(branch_a.get_push_location(), |
833 | branch_c.bzrdir.root_transport.base) |
834 | |
835 | @@ -176,11 +182,12 @@ |
836 | t.add('file') |
837 | t.commit('commit 1') |
838 | self.run_bzr('push -d tree pushed-to') |
839 | - path = t.branch.get_push_location() |
840 | + # Refresh the branch as 'push' modified it and get the push location |
841 | + push_loc = t.branch.bzrdir.open_branch().get_push_location() |
842 | out, err = self.run_bzr('push', working_dir="tree") |
843 | self.assertEqual('Using saved push location: %s\n' |
844 | 'No new revisions or tags to push.\n' % |
845 | - urlutils.local_path_from_url(path), err) |
846 | + urlutils.local_path_from_url(push_loc), err) |
847 | out, err = self.run_bzr('push -q', working_dir="tree") |
848 | self.assertEqual('', out) |
849 | self.assertEqual('', err) |
850 | @@ -285,7 +292,7 @@ |
851 | # being too low. If rpc_count increases, more network roundtrips have |
852 | # become necessary for this use case. Please do not adjust this number |
853 | # upwards without agreement from bzr's network support maintainers. |
854 | - self.assertLength(14, self.hpss_calls) |
855 | + self.assertLength(15, self.hpss_calls) |
856 | self.assertLength(1, self.hpss_connections) |
857 | self.assertThat(self.hpss_calls, ContainsNoVfsCalls) |
858 | remote = branch.Branch.open('public') |
859 | @@ -506,7 +513,8 @@ |
860 | trunk_public = self.make_branch('public_trunk', format='1.9') |
861 | trunk_public.pull(trunk_tree.branch) |
862 | trunk_public_url = self.get_readonly_url('public_trunk') |
863 | - trunk_tree.branch.set_public_branch(trunk_public_url) |
864 | + br = trunk_tree.branch |
865 | + br.set_public_branch(trunk_public_url) |
866 | # now we do a stacked push, which should determine the public location |
867 | # for us. |
868 | out, err = self.run_bzr(['push', '--stacked', |
869 | @@ -703,10 +711,8 @@ |
870 | self.tree.commit('modify file', rev_id='modified') |
871 | |
872 | def set_config_push_strict(self, value): |
873 | - # set config var (any of bazaar.conf, locations.conf, branch.conf |
874 | - # should do) |
875 | - conf = self.tree.branch.get_config_stack() |
876 | - conf.set('push_strict', value) |
877 | + br = branch.Branch.open('local') |
878 | + br.get_config_stack().set('push_strict', value) |
879 | |
880 | _default_command = ['push', '../to'] |
881 | _default_wd = 'local' |
882 | |
883 | === modified file 'bzrlib/tests/blackbox/test_reconfigure.py' |
884 | --- bzrlib/tests/blackbox/test_reconfigure.py 2011-09-06 18:37:06 +0000 |
885 | +++ bzrlib/tests/blackbox/test_reconfigure.py 2012-02-14 17:36:32 +0000 |
886 | @@ -1,4 +1,4 @@ |
887 | -# Copyright (C) 2007, 2009 Canonical Ltd |
888 | +# Copyright (C) 2007-2012 Canonical Ltd |
889 | # |
890 | # This program is free software; you can redistribute it and/or modify |
891 | # it under the terms of the GNU General Public License as published by |
892 | @@ -242,20 +242,19 @@ |
893 | branch_2 = tree_2.branch |
894 | # now reconfigure to be stacked |
895 | out, err = self.run_bzr('reconfigure --stacked-on b1 b2') |
896 | - self.assertContainsRe(out, |
897 | - '^.*/b2/ is now stacked on ../b1\n$') |
898 | + self.assertContainsRe(out, '^.*/b2/ is now stacked on ../b1\n$') |
899 | self.assertEquals('', err) |
900 | # can also give the absolute URL of the branch, and it gets stored |
901 | # as a relative path if possible |
902 | out, err = self.run_bzr('reconfigure --stacked-on %s b2' |
903 | - % (self.get_url('b1'),)) |
904 | - self.assertContainsRe(out, |
905 | - '^.*/b2/ is now stacked on ../b1\n$') |
906 | + % (self.get_url('b1'),)) |
907 | + self.assertContainsRe(out, '^.*/b2/ is now stacked on ../b1\n$') |
908 | self.assertEquals('', err) |
909 | + # Refresh the branch as 'reconfigure' modified it |
910 | + branch_2 = branch_2.bzrdir.open_branch() |
911 | # It should be given a relative URL to the destination, if possible, |
912 | # because that's most likely to work across different transports |
913 | - self.assertEquals(branch_2.get_stacked_on_url(), |
914 | - '../b1') |
915 | + self.assertEquals('../b1', branch_2.get_stacked_on_url()) |
916 | # commit, and it should be stored into b2's repo |
917 | self.build_tree_contents([('foo', 'new foo')]) |
918 | tree_2.commit('update foo') |
919 | @@ -264,8 +263,9 @@ |
920 | self.assertContainsRe(out, |
921 | '^.*/b2/ is now not stacked\n$') |
922 | self.assertEquals('', err) |
923 | - self.assertRaises(errors.NotStacked, |
924 | - branch_2.get_stacked_on_url) |
925 | + # Refresh the branch as 'reconfigure' modified it |
926 | + branch_2 = branch_2.bzrdir.open_branch() |
927 | + self.assertRaises(errors.NotStacked, branch_2.get_stacked_on_url) |
928 | |
929 | # XXX: Needs a test for reconfiguring stacking and shape at the same time; |
930 | # no branch at location; stacked-on is not a branch; quiet mode. |
931 | |
932 | === modified file 'bzrlib/tests/blackbox/test_send.py' |
933 | --- bzrlib/tests/blackbox/test_send.py 2012-02-01 19:55:27 +0000 |
934 | +++ bzrlib/tests/blackbox/test_send.py 2012-02-14 17:36:32 +0000 |
935 | @@ -1,4 +1,4 @@ |
936 | -# Copyright (C) 2006-2011 Canonical Ltd |
937 | +# Copyright (C) 2006-2012 Canonical Ltd |
938 | # Authors: Aaron Bentley |
939 | # |
940 | # This program is free software; you can redistribute it and/or modify |
941 | @@ -230,12 +230,13 @@ |
942 | 'send -f branch -o- --format=0.999')[0] |
943 | |
944 | def test_format_child_option(self): |
945 | - parent_config = branch.Branch.open('parent').get_config_stack() |
946 | - parent_config.set('child_submit_format', '4') |
947 | + br = branch.Branch.open('parent') |
948 | + conf = br.get_config_stack() |
949 | + conf.set('child_submit_format', '4') |
950 | md = self.get_MD([]) |
951 | self.assertIs(merge_directive.MergeDirective2, md.__class__) |
952 | |
953 | - parent_config.set('child_submit_format', '0.9') |
954 | + conf.set('child_submit_format', '0.9') |
955 | md = self.get_MD([]) |
956 | self.assertFormatIs('# Bazaar revision bundle v0.9', md) |
957 | |
958 | @@ -243,7 +244,7 @@ |
959 | self.assertFormatIs('# Bazaar revision bundle v0.9', md) |
960 | self.assertIs(merge_directive.MergeDirective, md.__class__) |
961 | |
962 | - parent_config.set('child_submit_format', '0.999') |
963 | + conf.set('child_submit_format', '0.999') |
964 | self.run_bzr_error(["No such send format '0.999'"], |
965 | 'send -f branch -o-')[0] |
966 | |
967 | @@ -293,10 +294,8 @@ |
968 | _default_additional_warning = 'Uncommitted changes will not be sent.' |
969 | |
970 | def set_config_send_strict(self, value): |
971 | - # set config var (any of bazaar.conf, locations.conf, branch.conf |
972 | - # should do) |
973 | - conf = self.local_tree.branch.get_config_stack() |
974 | - conf.set('send_strict', value) |
975 | + br = branch.Branch.open('local') |
976 | + br.get_config_stack().set('send_strict', value) |
977 | |
978 | def assertSendFails(self, args): |
979 | out, err = self.run_send(args, rc=3, err_re=self._default_errors) |
980 | @@ -463,6 +462,6 @@ |
981 | # being too low. If rpc_count increases, more network roundtrips have |
982 | # become necessary for this use case. Please do not adjust this number |
983 | # upwards without agreement from bzr's network support maintainers. |
984 | - self.assertLength(9, self.hpss_calls) |
985 | + self.assertLength(7, self.hpss_calls) |
986 | self.assertLength(1, self.hpss_connections) |
987 | self.assertThat(self.hpss_calls, ContainsNoVfsCalls) |
988 | |
989 | === modified file 'bzrlib/tests/blackbox/test_switch.py' |
990 | --- bzrlib/tests/blackbox/test_switch.py 2012-01-19 12:36:22 +0000 |
991 | +++ bzrlib/tests/blackbox/test_switch.py 2012-02-14 17:36:32 +0000 |
992 | @@ -1,4 +1,4 @@ |
993 | -# Copyright (C) 2007-2010 Canonical Ltd |
994 | +# Copyright (C) 2007-2012 Canonical Ltd |
995 | # -*- coding: utf-8 -*- |
996 | # |
997 | # This program is free software; you can redistribute it and/or modify |
998 | @@ -153,8 +153,11 @@ |
999 | branchb_id = tree2.commit('bar') |
1000 | checkout = tree1.branch.create_checkout('heavyco/a', lightweight=False) |
1001 | self.run_bzr(['switch', 'branchb'], working_dir='heavyco/a') |
1002 | + # Refresh checkout as 'switch' modified it |
1003 | + checkout = checkout.bzrdir.open_workingtree() |
1004 | self.assertEqual(branchb_id, checkout.last_revision()) |
1005 | - self.assertEqual(tree2.branch.base, checkout.branch.get_bound_location()) |
1006 | + self.assertEqual(tree2.branch.base, |
1007 | + checkout.branch.get_bound_location()) |
1008 | |
1009 | def test_switch_finds_relative_unicode_branch(self): |
1010 | """Switch will find 'foo' relative to the branch the checkout is of.""" |
1011 | |
1012 | === modified file 'bzrlib/tests/blackbox/test_whoami.py' |
1013 | --- bzrlib/tests/blackbox/test_whoami.py 2012-01-05 13:43:16 +0000 |
1014 | +++ bzrlib/tests/blackbox/test_whoami.py 2012-02-14 17:36:32 +0000 |
1015 | @@ -19,6 +19,7 @@ |
1016 | |
1017 | import bzrlib |
1018 | from bzrlib import ( |
1019 | + branch, |
1020 | config, |
1021 | errors, |
1022 | tests, |
1023 | @@ -50,11 +51,14 @@ |
1024 | out = self.run_bzr("whoami --email 'foo <foo@example.com>'", 3)[0] |
1025 | self.assertEquals("", out) |
1026 | |
1027 | + def set_branch_email(self, b, email): |
1028 | + b.get_config_stack().set('email', email) |
1029 | + |
1030 | def test_whoami_branch(self): |
1031 | """branch specific user identity works.""" |
1032 | wt = self.make_branch_and_tree('.') |
1033 | b = bzrlib.branch.Branch.open('.') |
1034 | - b.get_config_stack().set('email', 'Branch Identity <branch@identi.ty>') |
1035 | + self.set_branch_email(b, 'Branch Identity <branch@identi.ty>') |
1036 | self.assertWhoAmI('Branch Identity <branch@identi.ty>') |
1037 | self.assertWhoAmI('branch@identi.ty', '--email') |
1038 | |
1039 | @@ -79,8 +83,7 @@ |
1040 | """ |
1041 | wt = self.make_branch_and_tree('.') |
1042 | b = bzrlib.branch.Branch.open('.') |
1043 | - b.get_config_stack().set( |
1044 | - 'email', u'Branch Identity \u20ac ' + '<branch@identi.ty>') |
1045 | + self.set_branch_email(b, u'Branch Identity \u20ac <branch@identi.ty>') |
1046 | self.assertWhoAmI('Branch Identity ? <branch@identi.ty>', |
1047 | encoding='ascii') |
1048 | self.assertWhoAmI('branch@identi.ty', '--email', |
1049 | @@ -100,20 +103,20 @@ |
1050 | self.overrideEnv('EMAIL', None) |
1051 | self.overrideEnv('BZR_EMAIL', None) |
1052 | # Also, make sure that it's not inferred from mailname. |
1053 | - self.overrideAttr(config, '_auto_user_id', |
1054 | - lambda: (None, None)) |
1055 | + self.overrideAttr(config, '_auto_user_id', lambda: (None, None)) |
1056 | out, err = self.run_bzr(['whoami'], 3) |
1057 | self.assertContainsRe(err, 'Unable to determine your name') |
1058 | |
1059 | def test_whoami_directory(self): |
1060 | """Test --directory option.""" |
1061 | wt = self.make_branch_and_tree('subdir') |
1062 | - c = wt.branch.get_config_stack() |
1063 | - c.set('email', 'Branch Identity <branch@identi.ty>') |
1064 | + self.set_branch_email(wt.branch, 'Branch Identity <branch@identi.ty>') |
1065 | self.assertWhoAmI('Branch Identity <branch@identi.ty>', |
1066 | '--directory', 'subdir') |
1067 | self.run_bzr(['whoami', '--directory', 'subdir', '--branch', |
1068 | 'Changed Identity <changed@identi.ty>']) |
1069 | + # Refresh wt as 'whoami' modified it |
1070 | + wt = wt.bzrdir.open_workingtree() |
1071 | c = wt.branch.get_config_stack() |
1072 | self.assertEquals('Changed Identity <changed@identi.ty>', |
1073 | c.get('email')) |
1074 | @@ -121,8 +124,7 @@ |
1075 | def test_whoami_remote_directory(self): |
1076 | """Test --directory option with a remote directory.""" |
1077 | wt = self.make_branch_and_tree('subdir') |
1078 | - c = wt.branch.get_config_stack() |
1079 | - c.set('email', 'Branch Identity <branch@identi.ty>') |
1080 | + self.set_branch_email(wt.branch, 'Branch Identity <branch@identi.ty>') |
1081 | url = self.get_readonly_url() + '/subdir' |
1082 | self.assertWhoAmI('Branch Identity <branch@identi.ty>', |
1083 | '--directory', url) |
1084 | @@ -131,7 +133,7 @@ |
1085 | 'Changed Identity <changed@identi.ty>']) |
1086 | # The identity has been set in the branch config (but not the global |
1087 | # config) |
1088 | - c = wt.branch.get_config_stack() |
1089 | + c = branch.Branch.open(url).get_config_stack() |
1090 | self.assertEquals('Changed Identity <changed@identi.ty>', |
1091 | c.get('email')) |
1092 | # Ensuring that the value does not come from the bazaar.conf file |
1093 | |
1094 | === modified file 'bzrlib/tests/per_branch/test_branch.py' |
1095 | --- bzrlib/tests/per_branch/test_branch.py 2012-02-06 11:36:02 +0000 |
1096 | +++ bzrlib/tests/per_branch/test_branch.py 2012-02-14 17:36:32 +0000 |
1097 | @@ -1,4 +1,4 @@ |
1098 | -# Copyright (C) 2005-2011 Canonical Ltd |
1099 | +# Copyright (C) 2005-2012 Canonical Ltd |
1100 | # |
1101 | # This program is free software; you can redistribute it and/or modify |
1102 | # it under the terms of the GNU General Public License as published by |
1103 | @@ -779,22 +779,6 @@ |
1104 | branch.unbind() |
1105 | self.assertEqual(None, branch.get_master_branch()) |
1106 | |
1107 | - def test_unlocked_does_not_cache_master_branch(self): |
1108 | - """Unlocked branches do not cache the result of get_master_branch.""" |
1109 | - master = self.make_branch('master') |
1110 | - branch1 = self.make_branch('branch') |
1111 | - try: |
1112 | - branch1.bind(master) |
1113 | - except errors.UpgradeRequired: |
1114 | - raise tests.TestNotApplicable('Format does not support binding') |
1115 | - # Open branch1 again |
1116 | - branch2 = branch1.bzrdir.open_branch() |
1117 | - self.assertNotEqual(None, branch1.get_master_branch()) |
1118 | - # Unbind the branch via branch2. branch1 isn't locked so will |
1119 | - # immediately return the new value for get_master_branch. |
1120 | - branch2.unbind() |
1121 | - self.assertEqual(None, branch1.get_master_branch()) |
1122 | - |
1123 | def test_bind_clears_cached_master_branch(self): |
1124 | """b.bind clears any cached value of b.get_master_branch.""" |
1125 | master1 = self.make_branch('master1') |
1126 | |
1127 | === modified file 'bzrlib/tests/per_branch/test_break_lock.py' |
1128 | --- bzrlib/tests/per_branch/test_break_lock.py 2011-09-30 13:35:45 +0000 |
1129 | +++ bzrlib/tests/per_branch/test_break_lock.py 2012-02-14 17:36:32 +0000 |
1130 | @@ -1,4 +1,4 @@ |
1131 | -# Copyright (C) 2006-2010 Canonical Ltd |
1132 | +# Copyright (C) 2006-2012 Canonical Ltd |
1133 | # |
1134 | # This program is free software; you can redistribute it and/or modify |
1135 | # it under the terms of the GNU General Public License as published by |
1136 | @@ -86,7 +86,8 @@ |
1137 | master.lock_write() |
1138 | ui.ui_factory = ui.CannedInputUIFactory([True, True]) |
1139 | try: |
1140 | - self.unused_branch.break_lock() |
1141 | + fresh = _mod_branch.Branch.open(self.unused_branch.base) |
1142 | + fresh.break_lock() |
1143 | except NotImplementedError: |
1144 | # branch does not support break_lock |
1145 | master.unlock() |
1146 | |
1147 | === modified file 'bzrlib/tests/per_branch/test_create_clone.py' |
1148 | --- bzrlib/tests/per_branch/test_create_clone.py 2011-10-04 13:29:25 +0000 |
1149 | +++ bzrlib/tests/per_branch/test_create_clone.py 2012-02-14 17:36:32 +0000 |
1150 | @@ -1,4 +1,4 @@ |
1151 | -# Copyright (C) 2009, 2010 Canonical Ltd |
1152 | +# Copyright (C) 2009-2012 Canonical Ltd |
1153 | # |
1154 | # This program is free software; you can redistribute it and/or modify |
1155 | # it under the terms of the GNU General Public License as published by |
1156 | @@ -133,7 +133,6 @@ |
1157 | trunk = tree.branch.create_clone_on_transport( |
1158 | self.get_transport('trunk')) |
1159 | revid = tree.commit('a second commit') |
1160 | - source = tree.branch |
1161 | target_transport = self.get_transport('target') |
1162 | self.hook_calls = [] |
1163 | branch.Branch.hooks.install_named_hook( |
1164 | |
1165 | === modified file 'bzrlib/tests/test_branch.py' |
1166 | --- bzrlib/tests/test_branch.py 2012-01-18 17:47:06 +0000 |
1167 | +++ bzrlib/tests/test_branch.py 2012-02-14 17:36:32 +0000 |
1168 | @@ -1,4 +1,4 @@ |
1169 | -# Copyright (C) 2006-2011 Canonical Ltd |
1170 | +# Copyright (C) 2006-2012 Canonical Ltd |
1171 | # |
1172 | # This program is free software; you can redistribute it and/or modify |
1173 | # it under the terms of the GNU General Public License as published by |
1174 | @@ -356,8 +356,8 @@ |
1175 | self.assertPathDoesNotExist('a/.bzr/branch/parent') |
1176 | self.assertEqual('http://example.com', branch.get_parent()) |
1177 | branch.set_push_location('sftp://example.com') |
1178 | - config = branch.get_config_stack() |
1179 | - self.assertEqual('sftp://example.com', config.get('push_location')) |
1180 | + conf = branch.get_config_stack() |
1181 | + self.assertEqual('sftp://example.com', conf.get('push_location')) |
1182 | branch.set_bound_location('ftp://example.com') |
1183 | self.assertPathDoesNotExist('a/.bzr/branch/bound') |
1184 | self.assertEqual('ftp://example.com', branch.get_bound_location()) |
1185 | |
1186 | === modified file 'bzrlib/tests/test_config.py' |
1187 | --- bzrlib/tests/test_config.py 2012-02-03 10:28:47 +0000 |
1188 | +++ bzrlib/tests/test_config.py 2012-02-14 17:36:32 +0000 |
1189 | @@ -1,4 +1,4 @@ |
1190 | -# Copyright (C) 2005-2011 Canonical Ltd |
1191 | +# Copyright (C) 2005-2012 Canonical Ltd |
1192 | # |
1193 | # This program is free software; you can redistribute it and/or modify |
1194 | # it under the terms of the GNU General Public License as published by |
1195 | @@ -2924,6 +2924,11 @@ |
1196 | def test_save_emptied_succeeds(self): |
1197 | store = self.get_store(self) |
1198 | store._load_from_string('foo=bar\n') |
1199 | + # FIXME: There should be a better way than relying on the test |
1200 | + # parametrization to identify branch.conf -- vila 2011-0526 |
1201 | + if self.store_id in ('branch', 'remote_branch'): |
1202 | + # branch stores requires write locked branches |
1203 | + self.addCleanup(store.branch.lock_write().unlock) |
1204 | section = store.get_mutable_section(None) |
1205 | section.remove('foo') |
1206 | store.save() |
1207 | @@ -2950,6 +2955,11 @@ |
1208 | |
1209 | def test_set_option_in_empty_store(self): |
1210 | store = self.get_store(self) |
1211 | + # FIXME: There should be a better way than relying on the test |
1212 | + # parametrization to identify branch.conf -- vila 2011-0526 |
1213 | + if self.store_id in ('branch', 'remote_branch'): |
1214 | + # branch stores requires write locked branches |
1215 | + self.addCleanup(store.branch.lock_write().unlock) |
1216 | section = store.get_mutable_section(None) |
1217 | section.set('foo', 'bar') |
1218 | store.save() |
1219 | @@ -2961,6 +2971,11 @@ |
1220 | def test_set_option_in_default_section(self): |
1221 | store = self.get_store(self) |
1222 | store._load_from_string('') |
1223 | + # FIXME: There should be a better way than relying on the test |
1224 | + # parametrization to identify branch.conf -- vila 2011-0526 |
1225 | + if self.store_id in ('branch', 'remote_branch'): |
1226 | + # branch stores requires write locked branches |
1227 | + self.addCleanup(store.branch.lock_write().unlock) |
1228 | section = store.get_mutable_section(None) |
1229 | section.set('foo', 'bar') |
1230 | store.save() |
1231 | @@ -2972,6 +2987,11 @@ |
1232 | def test_set_option_in_named_section(self): |
1233 | store = self.get_store(self) |
1234 | store._load_from_string('') |
1235 | + # FIXME: There should be a better way than relying on the test |
1236 | + # parametrization to identify branch.conf -- vila 2011-0526 |
1237 | + if self.store_id in ('branch', 'remote_branch'): |
1238 | + # branch stores requires write locked branches |
1239 | + self.addCleanup(store.branch.lock_write().unlock) |
1240 | section = store.get_mutable_section('baz') |
1241 | section.set('foo', 'bar') |
1242 | store.save() |
1243 | @@ -2981,8 +3001,13 @@ |
1244 | self.assertSectionContent(('baz', {'foo': 'bar'}), sections[0]) |
1245 | |
1246 | def test_load_hook(self): |
1247 | - # We first needs to ensure that the store exists |
1248 | + # First, we need to ensure that the store exists |
1249 | store = self.get_store(self) |
1250 | + # FIXME: There should be a better way than relying on the test |
1251 | + # parametrization to identify branch.conf -- vila 2011-0526 |
1252 | + if self.store_id in ('branch', 'remote_branch'): |
1253 | + # branch stores requires write locked branches |
1254 | + self.addCleanup(store.branch.lock_write().unlock) |
1255 | section = store.get_mutable_section('baz') |
1256 | section.set('foo', 'bar') |
1257 | store.save() |
1258 | @@ -3004,6 +3029,11 @@ |
1259 | config.ConfigHooks.install_named_hook('save', hook, None) |
1260 | self.assertLength(0, calls) |
1261 | store = self.get_store(self) |
1262 | + # FIXME: There should be a better way than relying on the test |
1263 | + # parametrization to identify branch.conf -- vila 2011-0526 |
1264 | + if self.store_id in ('branch', 'remote_branch'): |
1265 | + # branch stores requires write locked branches |
1266 | + self.addCleanup(store.branch.lock_write().unlock) |
1267 | section = store.get_mutable_section('baz') |
1268 | section.set('foo', 'bar') |
1269 | store.save() |
1270 | @@ -3835,7 +3865,8 @@ |
1271 | super(TestStackExpandOptions, self).setUp() |
1272 | self.overrideAttr(config, 'option_registry', config.OptionRegistry()) |
1273 | self.registry = config.option_registry |
1274 | - self.conf = build_branch_stack(self) |
1275 | + store = config.TransportIniFileStore(self.get_transport(), 'foo.conf') |
1276 | + self.conf = config.Stack([store.get_sections], store) |
1277 | |
1278 | def assertExpansion(self, expected, string, env=None): |
1279 | self.assertEquals(expected, self.conf.expand_options(string, env)) |
1280 | |
1281 | === modified file 'bzrlib/tests/test_directory_service.py' |
1282 | --- bzrlib/tests/test_directory_service.py 2011-11-29 01:35:03 +0000 |
1283 | +++ bzrlib/tests/test_directory_service.py 2012-02-14 17:36:32 +0000 |
1284 | @@ -1,4 +1,4 @@ |
1285 | -# Copyright (C) 2008, 2009, 2010 Canonical Ltd |
1286 | +# Copyright (C) 2008-2012 Canonical Ltd |
1287 | # |
1288 | # This program is free software; you can redistribute it and/or modify |
1289 | # it under the terms of the GNU General Public License as published by |
1290 | @@ -65,55 +65,53 @@ |
1291 | |
1292 | class TestAliasDirectory(TestCaseWithTransport): |
1293 | |
1294 | + def setUp(self): |
1295 | + super(TestAliasDirectory, self).setUp() |
1296 | + self.branch = self.make_branch('.') |
1297 | + |
1298 | + def assertAliasFromBranch(self, setter, value, alias): |
1299 | + setter(value) |
1300 | + self.assertEquals(value, directories.dereference(alias)) |
1301 | + |
1302 | def test_lookup_parent(self): |
1303 | - branch = self.make_branch('.') |
1304 | - branch.set_parent('http://a') |
1305 | - self.assertEqual('http://a', directories.dereference(':parent')) |
1306 | + self.assertAliasFromBranch(self.branch.set_parent, 'http://a', |
1307 | + ':parent') |
1308 | |
1309 | def test_lookup_submit(self): |
1310 | - branch = self.make_branch('.') |
1311 | - branch.set_submit_branch('http://b') |
1312 | - self.assertEqual('http://b', directories.dereference(':submit')) |
1313 | + self.assertAliasFromBranch(self.branch.set_submit_branch, 'http://b', |
1314 | + ':submit') |
1315 | |
1316 | def test_lookup_public(self): |
1317 | - branch = self.make_branch('.') |
1318 | - branch.set_public_branch('http://c') |
1319 | - self.assertEqual('http://c', directories.dereference(':public')) |
1320 | + self.assertAliasFromBranch(self.branch.set_public_branch, 'http://c', |
1321 | + ':public') |
1322 | |
1323 | def test_lookup_bound(self): |
1324 | - branch = self.make_branch('.') |
1325 | - branch.set_bound_location('http://d') |
1326 | - self.assertEqual('http://d', directories.dereference(':bound')) |
1327 | + self.assertAliasFromBranch(self.branch.set_bound_location, 'http://d', |
1328 | + ':bound') |
1329 | |
1330 | def test_lookup_push(self): |
1331 | - branch = self.make_branch('.') |
1332 | - branch.set_push_location('http://e') |
1333 | - self.assertEqual('http://e', directories.dereference(':push')) |
1334 | + self.assertAliasFromBranch(self.branch.set_push_location, 'http://e', |
1335 | + ':push') |
1336 | |
1337 | def test_lookup_this(self): |
1338 | - branch = self.make_branch('.') |
1339 | - self.assertEqual(branch.base, directories.dereference(':this')) |
1340 | + self.assertEqual(self.branch.base, directories.dereference(':this')) |
1341 | |
1342 | def test_extra_path(self): |
1343 | - branch = self.make_branch('.') |
1344 | - self.assertEqual(urlutils.join(branch.base, 'arg'), |
1345 | + self.assertEqual(urlutils.join(self.branch.base, 'arg'), |
1346 | directories.dereference(':this/arg')) |
1347 | |
1348 | def test_lookup_badname(self): |
1349 | - branch = self.make_branch('.') |
1350 | e = self.assertRaises(errors.InvalidLocationAlias, |
1351 | directories.dereference, ':booga') |
1352 | self.assertEqual('":booga" is not a valid location alias.', |
1353 | str(e)) |
1354 | |
1355 | def test_lookup_badvalue(self): |
1356 | - branch = self.make_branch('.') |
1357 | e = self.assertRaises(errors.UnsetLocationAlias, |
1358 | directories.dereference, ':parent') |
1359 | self.assertEqual('No parent location assigned.', str(e)) |
1360 | |
1361 | def test_register_location_alias(self): |
1362 | - branch = self.make_branch('.') |
1363 | self.addCleanup(AliasDirectory.branch_aliases.remove, "booga") |
1364 | AliasDirectory.branch_aliases.register("booga", |
1365 | lambda b: "UHH?", help="Nobody knows") |
1366 | |
1367 | === modified file 'bzrlib/tests/test_info.py' |
1368 | --- bzrlib/tests/test_info.py 2012-01-19 16:23:53 +0000 |
1369 | +++ bzrlib/tests/test_info.py 2012-02-14 17:36:32 +0000 |
1370 | @@ -1,4 +1,4 @@ |
1371 | -# Copyright (C) 2007-2011 Canonical Ltd |
1372 | +# Copyright (C) 2007-2012 Canonical Ltd |
1373 | # |
1374 | # This program is free software; you can redistribute it and/or modify |
1375 | # it under the terms of the GNU General Public License as published by |
1376 | @@ -322,10 +322,14 @@ |
1377 | |
1378 | def test_gather_related_braches(self): |
1379 | branch = self.make_branch('.') |
1380 | - branch.set_public_branch('baz') |
1381 | - branch.set_push_location('bar') |
1382 | - branch.set_parent('foo') |
1383 | - branch.set_submit_branch('qux') |
1384 | + branch.lock_write() |
1385 | + try: |
1386 | + branch.set_public_branch('baz') |
1387 | + branch.set_push_location('bar') |
1388 | + branch.set_parent('foo') |
1389 | + branch.set_submit_branch('qux') |
1390 | + finally: |
1391 | + branch.unlock() |
1392 | self.assertEqual( |
1393 | [('public branch', 'baz'), ('push branch', 'bar'), |
1394 | ('parent branch', 'foo'), ('submit branch', 'qux')], |
1395 | |
1396 | === modified file 'bzrlib/tests/test_reconfigure.py' |
1397 | --- bzrlib/tests/test_reconfigure.py 2011-12-05 17:31:43 +0000 |
1398 | +++ bzrlib/tests/test_reconfigure.py 2012-02-14 17:36:32 +0000 |
1399 | @@ -1,4 +1,4 @@ |
1400 | -# Copyright (C) 2007, 2008, 2009 Canonical Ltd |
1401 | +# Copyright (C) 2007, 2008, 2009, 2011, 2012 Canonical Ltd |
1402 | # |
1403 | # This program is free software; you can redistribute it and/or modify |
1404 | # it under the terms of the GNU General Public License as published by |
1405 | @@ -72,7 +72,8 @@ |
1406 | checkout = branch.create_checkout('checkout') |
1407 | reconfiguration = reconfigure.Reconfigure.to_branch(checkout.bzrdir) |
1408 | reconfiguration.apply() |
1409 | - self.assertIs(None, checkout.branch.get_bound_location()) |
1410 | + reconfigured = bzrdir.BzrDir.open('checkout').open_branch() |
1411 | + self.assertIs(None, reconfigured.get_bound_location()) |
1412 | |
1413 | def prepare_lightweight_checkout_to_branch(self): |
1414 | branch = self.make_branch('branch') |
1415 | @@ -147,16 +148,24 @@ |
1416 | self.assertRaises(errors.NoBindLocation, |
1417 | reconfiguration._select_bind_location) |
1418 | branch.set_parent('http://parent') |
1419 | + reconfiguration = reconfigure.Reconfigure(branch.bzrdir) |
1420 | self.assertEqual('http://parent', |
1421 | reconfiguration._select_bind_location()) |
1422 | branch.set_push_location('sftp://push') |
1423 | + reconfiguration = reconfigure.Reconfigure(branch.bzrdir) |
1424 | self.assertEqual('sftp://push', |
1425 | reconfiguration._select_bind_location()) |
1426 | - branch.set_bound_location('bzr://foo/old-bound') |
1427 | - branch.set_bound_location(None) |
1428 | + branch.lock_write() |
1429 | + try: |
1430 | + branch.set_bound_location('bzr://foo/old-bound') |
1431 | + branch.set_bound_location(None) |
1432 | + finally: |
1433 | + branch.unlock() |
1434 | + reconfiguration = reconfigure.Reconfigure(branch.bzrdir) |
1435 | self.assertEqual('bzr://foo/old-bound', |
1436 | reconfiguration._select_bind_location()) |
1437 | branch.set_bound_location('bzr://foo/cur-bound') |
1438 | + reconfiguration = reconfigure.Reconfigure(branch.bzrdir) |
1439 | self.assertEqual('bzr://foo/cur-bound', |
1440 | reconfiguration._select_bind_location()) |
1441 | reconfiguration.new_bound_location = 'ftp://user-specified' |
1442 | @@ -180,6 +189,7 @@ |
1443 | self.assertRaises(errors.NoBindLocation, reconfiguration.apply) |
1444 | # setting a parent allows it to become a checkout |
1445 | tree.branch.set_parent(parent.base) |
1446 | + reconfiguration = reconfigure.Reconfigure.to_checkout(tree.bzrdir) |
1447 | reconfiguration.apply() |
1448 | # supplying a location allows it to become a checkout |
1449 | tree2 = self.make_branch_and_tree('tree2') |
1450 | @@ -198,6 +208,8 @@ |
1451 | self.assertRaises(errors.NoBindLocation, reconfiguration.apply) |
1452 | # setting a parent allows it to become a checkout |
1453 | tree.branch.set_parent(parent.base) |
1454 | + reconfiguration = reconfigure.Reconfigure.to_lightweight_checkout( |
1455 | + tree.bzrdir) |
1456 | reconfiguration.apply() |
1457 | # supplying a location allows it to become a checkout |
1458 | tree2 = self.make_branch_and_tree('tree2') |
1459 | |
1460 | === modified file 'bzrlib/tests/test_remote.py' |
1461 | --- bzrlib/tests/test_remote.py 2012-01-28 01:43:42 +0000 |
1462 | +++ bzrlib/tests/test_remote.py 2012-02-14 17:36:32 +0000 |
1463 | @@ -1,4 +1,4 @@ |
1464 | -# Copyright (C) 2006-2011 Canonical Ltd |
1465 | +# Copyright (C) 2006-2012 Canonical Ltd |
1466 | # |
1467 | # This program is free software; you can redistribute it and/or modify |
1468 | # it under the terms of the GNU General Public License as published by |
1469 | @@ -1296,7 +1296,7 @@ |
1470 | verb = 'Branch.set_parent_location' |
1471 | self.disable_verb(verb) |
1472 | branch.set_parent('http://foo/') |
1473 | - self.assertLength(13, self.hpss_calls) |
1474 | + self.assertLength(14, self.hpss_calls) |
1475 | |
1476 | |
1477 | class TestBranchGetTagsBytes(RemoteBranchTestCase): |
1478 | @@ -1455,34 +1455,31 @@ |
1479 | return branch |
1480 | |
1481 | def test_backwards_compatible(self): |
1482 | - branch = self.make_branch_with_tags() |
1483 | - c = branch.get_config_stack() |
1484 | - c.set('branch.fetch_tags', True) |
1485 | - self.addCleanup(branch.lock_read().unlock) |
1486 | + br = self.make_branch_with_tags() |
1487 | + br.get_config_stack().set('branch.fetch_tags', True) |
1488 | + self.addCleanup(br.lock_read().unlock) |
1489 | # Disable the heads_to_fetch verb |
1490 | verb = 'Branch.heads_to_fetch' |
1491 | self.disable_verb(verb) |
1492 | self.reset_smart_call_log() |
1493 | - result = branch.heads_to_fetch() |
1494 | + result = br.heads_to_fetch() |
1495 | self.assertEqual((set(['tip']), set(['rev-1', 'rev-2'])), result) |
1496 | self.assertEqual( |
1497 | - ['Branch.last_revision_info', 'Branch.get_config_file', |
1498 | - 'Branch.get_tags_bytes'], |
1499 | + ['Branch.last_revision_info', 'Branch.get_tags_bytes'], |
1500 | [call.call.method for call in self.hpss_calls]) |
1501 | |
1502 | def test_backwards_compatible_no_tags(self): |
1503 | - branch = self.make_branch_with_tags() |
1504 | - c = branch.get_config_stack() |
1505 | - c.set('branch.fetch_tags', False) |
1506 | - self.addCleanup(branch.lock_read().unlock) |
1507 | + br = self.make_branch_with_tags() |
1508 | + br.get_config_stack().set('branch.fetch_tags', False) |
1509 | + self.addCleanup(br.lock_read().unlock) |
1510 | # Disable the heads_to_fetch verb |
1511 | verb = 'Branch.heads_to_fetch' |
1512 | self.disable_verb(verb) |
1513 | self.reset_smart_call_log() |
1514 | - result = branch.heads_to_fetch() |
1515 | + result = br.heads_to_fetch() |
1516 | self.assertEqual((set(['tip']), set()), result) |
1517 | self.assertEqual( |
1518 | - ['Branch.last_revision_info', 'Branch.get_config_file'], |
1519 | + ['Branch.last_revision_info'], |
1520 | [call.call.method for call in self.hpss_calls]) |
1521 | |
1522 | |
1523 | @@ -2073,6 +2070,9 @@ |
1524 | 'Branch.get_config_file', ('memory:///', ), |
1525 | 'success', ('ok', ), "# line 1\n") |
1526 | client.add_expected_call( |
1527 | + 'Branch.get_config_file', ('memory:///', ), |
1528 | + 'success', ('ok', ), "# line 1\n") |
1529 | + client.add_expected_call( |
1530 | 'Branch.put_config_file', ('memory:///', 'branch token', |
1531 | 'repo token'), |
1532 | 'success', ('ok',)) |
1533 | @@ -2090,6 +2090,7 @@ |
1534 | [('call', 'Branch.get_stacked_on_url', ('memory:///',)), |
1535 | ('call', 'Branch.lock_write', ('memory:///', '', '')), |
1536 | ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)), |
1537 | + ('call_expecting_body', 'Branch.get_config_file', ('memory:///',)), |
1538 | ('call_with_body_bytes_expecting_body', 'Branch.put_config_file', |
1539 | ('memory:///', 'branch token', 'repo token'), |
1540 | '# line 1\nemail = The Dude <lebowski@example.com>\n'), |
1541 | |
1542 | === modified file 'bzrlib/tests/test_smart.py' |
1543 | --- bzrlib/tests/test_smart.py 2012-01-30 14:18:22 +0000 |
1544 | +++ bzrlib/tests/test_smart.py 2012-02-14 17:36:32 +0000 |
1545 | @@ -1,4 +1,4 @@ |
1546 | -# Copyright (C) 2006-2011 Canonical Ltd |
1547 | +# Copyright (C) 2006-2012 Canonical Ltd |
1548 | # |
1549 | # This program is free software; you can redistribute it and/or modify |
1550 | # it under the terms of the GNU General Public License as published by |
1551 | @@ -1323,6 +1323,8 @@ |
1552 | finally: |
1553 | branch.unlock() |
1554 | self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response) |
1555 | + # Refresh branch as SetParentLocation modified it |
1556 | + branch = branch.bzrdir.open_branch() |
1557 | self.assertEqual(None, branch.get_parent()) |
1558 | |
1559 | def test_set_parent_something(self): |
1560 | @@ -1332,11 +1334,12 @@ |
1561 | branch_token, repo_token = self.get_lock_tokens(branch) |
1562 | try: |
1563 | response = request.execute('base', branch_token, repo_token, |
1564 | - 'http://bar/') |
1565 | + 'http://bar/') |
1566 | finally: |
1567 | branch.unlock() |
1568 | self.assertEqual(smart_req.SuccessfulSmartServerResponse(()), response) |
1569 | - self.assertEqual('http://bar/', branch.get_parent()) |
1570 | + refreshed = _mod_branch.Branch.open(branch.base) |
1571 | + self.assertEqual('http://bar/', refreshed.get_parent()) |
1572 | |
1573 | |
1574 | class TestSmartServerBranchRequestGetTagsBytes( |
Change set/remove to require a lock for the branch config files.
This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).
This reduces the diff by ~300 lines.
Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.
The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.
If nothing else, once the same change has been made to the local config
files the BranchOnlyStack will be come useless since it's intended purpose
was more to avoid the IOs associated with the locl config files than
forbidding setting stacked_on_location in locl config files (while setting
stacked_on_location from a local file may sound weird, it still makes sense
to allow it on the server side (launchpad excluded given its implementation)
or even for expert users (including from the command line with -O) in
specific cases).
Overall removing the constraint on branch locking sounds less risky to land
especially at the beginning of the 2.6 cycle.
So, please review :)
I'll make a further proposal on top of this one for sharing the local config files.