Merge lp:~bialix/bzr/bzr-1.18-oslocks-win32 into lp:bzr/1.18
- bzr-1.18-oslocks-win32
- Merge into 1.18
Proposed by
Alexander Belchenko
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp:~bialix/bzr/bzr-1.18-oslocks-win32 |
Merge into: | lp:bzr/1.18 |
Diff against target: | 755 lines |
To merge this branch: | bzr merge lp:~bialix/bzr/bzr-1.18-oslocks-win32 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Vincent Ladeuil (community) | Approve | ||
Robert Collins | Pending | ||
Review via email:
|
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Alexander Belchenko (bialix) wrote : | # |
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Robert Collins (lifeless) wrote : | # |
review +1
Revision history for this message
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Vincent Ladeuil (vila) wrote : | # |
Robert forgets the leading space so his votes get ignored.
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'NEWS' |
2 | --- NEWS 2009-08-25 05:32:07 +0000 |
3 | +++ NEWS 2009-08-27 08:35:10 +0000 |
4 | @@ -17,9 +17,22 @@ |
5 | conversion will commit too many copies a file. |
6 | (Martin Pool, #415508) |
7 | |
8 | +Improvements |
9 | +************ |
10 | + |
11 | +* ``bzr push`` locally on windows will no longer give a locking error with |
12 | + dirstate based formats. (Robert Collins) |
13 | + |
14 | +* ``bzr shelve`` and ``bzr unshelve`` now work on windows. |
15 | + (Robert Collins, #305006) |
16 | + |
17 | API Changes |
18 | *********** |
19 | |
20 | +* ``bzrlib.shelf_ui`` has had the ``from_args`` convenience methods of its |
21 | + classes changed to manage lock lifetime of the trees they open in a way |
22 | + consistent with reader-exclusive locks. (Robert Collins, #305006) |
23 | + |
24 | * ``Tree.path_content_summary`` may return a size of None, when called on |
25 | a tree with content filtering where the size of the canonical form |
26 | cannot be cheaply determined. (Martin Pool) |
27 | |
28 | === modified file 'bzrlib/builtins.py' |
29 | --- bzrlib/builtins.py 2009-07-27 06:22:57 +0000 |
30 | +++ bzrlib/builtins.py 2009-08-27 08:35:10 +0000 |
31 | @@ -120,6 +120,15 @@ |
32 | |
33 | |
34 | def _get_one_revision_tree(command_name, revisions, branch=None, tree=None): |
35 | + """Get a revision tree. Not suitable for commands that change the tree. |
36 | + |
37 | + Specifically, the basis tree in dirstate trees is coupled to the dirstate |
38 | + and doing a commit/uncommit/pull will at best fail due to changing the |
39 | + basis revision data. |
40 | + |
41 | + If tree is passed in, it should be already locked, for lifetime management |
42 | + of the trees internal cached state. |
43 | + """ |
44 | if branch is None: |
45 | branch = tree.branch |
46 | if revisions is None: |
47 | @@ -5627,8 +5636,12 @@ |
48 | if writer is None: |
49 | writer = bzrlib.option.diff_writer_registry.get() |
50 | try: |
51 | - Shelver.from_args(writer(sys.stdout), revision, all, file_list, |
52 | - message, destroy=destroy).run() |
53 | + shelver = Shelver.from_args(writer(sys.stdout), revision, all, |
54 | + file_list, message, destroy=destroy) |
55 | + try: |
56 | + shelver.run() |
57 | + finally: |
58 | + shelver.work_tree.unlock() |
59 | except errors.UserAbort: |
60 | return 0 |
61 | |
62 | @@ -5673,7 +5686,11 @@ |
63 | |
64 | def run(self, shelf_id=None, action='apply'): |
65 | from bzrlib.shelf_ui import Unshelver |
66 | - Unshelver.from_args(shelf_id, action).run() |
67 | + unshelver = Unshelver.from_args(shelf_id, action) |
68 | + try: |
69 | + unshelver.run() |
70 | + finally: |
71 | + unshelver.tree.unlock() |
72 | |
73 | |
74 | class cmd_clean_tree(Command): |
75 | |
76 | === modified file 'bzrlib/merge.py' |
77 | --- bzrlib/merge.py 2009-07-02 13:07:14 +0000 |
78 | +++ bzrlib/merge.py 2009-08-27 08:35:10 +0000 |
79 | @@ -64,8 +64,12 @@ |
80 | |
81 | |
82 | def transform_tree(from_tree, to_tree, interesting_ids=None): |
83 | - merge_inner(from_tree.branch, to_tree, from_tree, ignore_zero=True, |
84 | - interesting_ids=interesting_ids, this_tree=from_tree) |
85 | + from_tree.lock_tree_write() |
86 | + try: |
87 | + merge_inner(from_tree.branch, to_tree, from_tree, ignore_zero=True, |
88 | + interesting_ids=interesting_ids, this_tree=from_tree) |
89 | + finally: |
90 | + from_tree.unlock() |
91 | |
92 | |
93 | class Merger(object): |
94 | @@ -102,6 +106,17 @@ |
95 | self._is_criss_cross = None |
96 | self._lca_trees = None |
97 | |
98 | + def cache_trees_with_revision_ids(self, trees): |
99 | + """Cache any tree in trees if it has a revision_id.""" |
100 | + for maybe_tree in trees: |
101 | + if maybe_tree is None: |
102 | + continue |
103 | + try: |
104 | + rev_id = maybe_tree.get_revision_id() |
105 | + except AttributeError: |
106 | + continue |
107 | + self._cached_trees[rev_id] = maybe_tree |
108 | + |
109 | @property |
110 | def revision_graph(self): |
111 | if self._revision_graph is None: |
112 | @@ -1516,6 +1531,7 @@ |
113 | get_revision_id = getattr(base_tree, 'get_revision_id', None) |
114 | if get_revision_id is None: |
115 | get_revision_id = base_tree.last_revision |
116 | + merger.cache_trees_with_revision_ids([other_tree, base_tree, this_tree]) |
117 | merger.set_base_revision(get_revision_id(), this_branch) |
118 | return merger.do_merge() |
119 | |
120 | |
121 | === modified file 'bzrlib/shelf.py' |
122 | --- bzrlib/shelf.py 2009-07-13 17:35:09 +0000 |
123 | +++ bzrlib/shelf.py 2009-08-27 08:35:10 +0000 |
124 | @@ -37,8 +37,10 @@ |
125 | def __init__(self, work_tree, target_tree, file_list=None): |
126 | """Constructor. |
127 | |
128 | - :param work_tree: The working tree to apply changes to |
129 | + :param work_tree: The working tree to apply changes to. This is not |
130 | + required to be locked - a tree_write lock will be taken out. |
131 | :param target_tree: The tree to make the working tree more similar to. |
132 | + This is not required to be locked - a read_lock will be taken out. |
133 | :param file_list: The files to make more similar to the target. |
134 | """ |
135 | self.work_tree = work_tree |
136 | |
137 | === modified file 'bzrlib/shelf_ui.py' |
138 | --- bzrlib/shelf_ui.py 2009-07-13 13:00:27 +0000 |
139 | +++ bzrlib/shelf_ui.py 2009-08-27 08:35:10 +0000 |
140 | @@ -149,6 +149,9 @@ |
141 | message=None, directory='.', destroy=False): |
142 | """Create a shelver from commandline arguments. |
143 | |
144 | + The returned shelver wil have a work_tree that is locked and should |
145 | + be unlocked. |
146 | + |
147 | :param revision: RevisionSpec of the revision to compare to. |
148 | :param all: If True, shelve all changes without prompting. |
149 | :param file_list: If supplied, only files in this list may be shelved. |
150 | @@ -158,9 +161,16 @@ |
151 | changes. |
152 | """ |
153 | tree, path = workingtree.WorkingTree.open_containing(directory) |
154 | - target_tree = builtins._get_one_revision_tree('shelf2', revision, |
155 | - tree.branch, tree) |
156 | - files = builtins.safe_relpath_files(tree, file_list) |
157 | + # Ensure that tree is locked for the lifetime of target_tree, as |
158 | + # target tree may be reading from the same dirstate. |
159 | + tree.lock_tree_write() |
160 | + try: |
161 | + target_tree = builtins._get_one_revision_tree('shelf2', revision, |
162 | + tree.branch, tree) |
163 | + files = builtins.safe_relpath_files(tree, file_list) |
164 | + except: |
165 | + tree.unlock() |
166 | + raise |
167 | return klass(tree, target_tree, diff_writer, all, all, files, message, |
168 | destroy) |
169 | |
170 | @@ -313,32 +323,40 @@ |
171 | def from_args(klass, shelf_id=None, action='apply', directory='.'): |
172 | """Create an unshelver from commandline arguments. |
173 | |
174 | + The returned shelver wil have a tree that is locked and should |
175 | + be unlocked. |
176 | + |
177 | :param shelf_id: Integer id of the shelf, as a string. |
178 | :param action: action to perform. May be 'apply', 'dry-run', |
179 | 'delete'. |
180 | :param directory: The directory to unshelve changes into. |
181 | """ |
182 | tree, path = workingtree.WorkingTree.open_containing(directory) |
183 | - manager = tree.get_shelf_manager() |
184 | - if shelf_id is not None: |
185 | - try: |
186 | - shelf_id = int(shelf_id) |
187 | - except ValueError: |
188 | - raise errors.InvalidShelfId(shelf_id) |
189 | - else: |
190 | - shelf_id = manager.last_shelf() |
191 | - if shelf_id is None: |
192 | - raise errors.BzrCommandError('No changes are shelved.') |
193 | - trace.note('Unshelving changes with id "%d".' % shelf_id) |
194 | - apply_changes = True |
195 | - delete_shelf = True |
196 | - read_shelf = True |
197 | - if action == 'dry-run': |
198 | - apply_changes = False |
199 | - delete_shelf = False |
200 | - if action == 'delete-only': |
201 | - apply_changes = False |
202 | - read_shelf = False |
203 | + tree.lock_tree_write() |
204 | + try: |
205 | + manager = tree.get_shelf_manager() |
206 | + if shelf_id is not None: |
207 | + try: |
208 | + shelf_id = int(shelf_id) |
209 | + except ValueError: |
210 | + raise errors.InvalidShelfId(shelf_id) |
211 | + else: |
212 | + shelf_id = manager.last_shelf() |
213 | + if shelf_id is None: |
214 | + raise errors.BzrCommandError('No changes are shelved.') |
215 | + trace.note('Unshelving changes with id "%d".' % shelf_id) |
216 | + apply_changes = True |
217 | + delete_shelf = True |
218 | + read_shelf = True |
219 | + if action == 'dry-run': |
220 | + apply_changes = False |
221 | + delete_shelf = False |
222 | + if action == 'delete-only': |
223 | + apply_changes = False |
224 | + read_shelf = False |
225 | + except: |
226 | + tree.unlock() |
227 | + raise |
228 | return klass(tree, manager, shelf_id, apply_changes, delete_shelf, |
229 | read_shelf) |
230 | |
231 | @@ -364,7 +382,7 @@ |
232 | |
233 | def run(self): |
234 | """Perform the unshelving operation.""" |
235 | - self.tree.lock_write() |
236 | + self.tree.lock_tree_write() |
237 | cleanups = [self.tree.unlock] |
238 | try: |
239 | if self.read_shelf: |
240 | |
241 | === modified file 'bzrlib/tests/per_workingtree/test_executable.py' |
242 | --- bzrlib/tests/per_workingtree/test_executable.py 2009-07-10 07:14:02 +0000 |
243 | +++ bzrlib/tests/per_workingtree/test_executable.py 2009-08-27 08:35:10 +0000 |
244 | @@ -30,7 +30,6 @@ |
245 | |
246 | def setUp(self): |
247 | super(TestExecutable, self).setUp() |
248 | - |
249 | self.a_id = "a-20051208024829-849e76f7968d7a86" |
250 | self.b_id = "b-20051208024829-849e76f7968d7a86" |
251 | wt = self.make_branch_and_tree('b1') |
252 | |
253 | === modified file 'bzrlib/tests/per_workingtree/test_set_root_id.py' |
254 | --- bzrlib/tests/per_workingtree/test_set_root_id.py 2009-07-10 07:14:02 +0000 |
255 | +++ bzrlib/tests/per_workingtree/test_set_root_id.py 2009-08-27 08:35:10 +0000 |
256 | @@ -23,6 +23,8 @@ |
257 | class TestSetRootId(TestCaseWithWorkingTree): |
258 | |
259 | def test_set_and_read_unicode(self): |
260 | + # This test tests that setting the root doesn't flush, so it |
261 | + # deliberately tests concurrent access that isn't possible on windows. |
262 | tree = self.make_branch_and_tree('a-tree') |
263 | # setting the root id allows it to be read via get_root_id. |
264 | root_id = u'\xe5n-id'.encode('utf8') |
265 | |
266 | === modified file 'bzrlib/tests/test_merge.py' |
267 | --- bzrlib/tests/test_merge.py 2009-04-29 17:02:36 +0000 |
268 | +++ bzrlib/tests/test_merge.py 2009-08-27 08:35:10 +0000 |
269 | @@ -218,13 +218,15 @@ |
270 | tree_a.add('file') |
271 | tree_a.commit('commit base') |
272 | # basis_tree() is only guaranteed to be valid as long as it is actually |
273 | - # the basis tree. This mutates the tree after grabbing basis, so go to |
274 | - # the repository. |
275 | + # the basis tree. This test commits to the tree after grabbing basis, |
276 | + # so we go to the repository. |
277 | base_tree = tree_a.branch.repository.revision_tree(tree_a.last_revision()) |
278 | tree_b = tree_a.bzrdir.sprout('tree_b').open_workingtree() |
279 | self.build_tree_contents([('tree_a/file', 'content_2')]) |
280 | tree_a.commit('commit other') |
281 | other_tree = tree_a.basis_tree() |
282 | + # 'file' is now missing but isn't altered in any commit in b so no |
283 | + # change should be applied. |
284 | os.unlink('tree_b/file') |
285 | merge_inner(tree_b.branch, other_tree, base_tree, this_tree=tree_b) |
286 | |
287 | @@ -1232,6 +1234,27 @@ |
288 | |
289 | class TestMergerInMemory(TestMergerBase): |
290 | |
291 | + def test_cache_trees_with_revision_ids_None(self): |
292 | + merger = self.make_Merger(self.setup_simple_graph(), 'C-id') |
293 | + original_cache = dict(merger._cached_trees) |
294 | + merger.cache_trees_with_revision_ids([None]) |
295 | + self.assertEqual(original_cache, merger._cached_trees) |
296 | + |
297 | + def test_cache_trees_with_revision_ids_no_revision_id(self): |
298 | + merger = self.make_Merger(self.setup_simple_graph(), 'C-id') |
299 | + original_cache = dict(merger._cached_trees) |
300 | + tree = self.make_branch_and_memory_tree('tree') |
301 | + merger.cache_trees_with_revision_ids([tree]) |
302 | + self.assertEqual(original_cache, merger._cached_trees) |
303 | + |
304 | + def test_cache_trees_with_revision_ids_having_revision_id(self): |
305 | + merger = self.make_Merger(self.setup_simple_graph(), 'C-id') |
306 | + original_cache = dict(merger._cached_trees) |
307 | + tree = merger.this_branch.repository.revision_tree('B-id') |
308 | + original_cache['B-id'] = tree |
309 | + merger.cache_trees_with_revision_ids([tree]) |
310 | + self.assertEqual(original_cache, merger._cached_trees) |
311 | + |
312 | def test_find_base(self): |
313 | merger = self.make_Merger(self.setup_simple_graph(), 'C-id') |
314 | self.assertEqual('A-id', merger.base_rev_id) |
315 | |
316 | === modified file 'bzrlib/tests/test_shelf.py' |
317 | --- bzrlib/tests/test_shelf.py 2009-07-13 17:35:09 +0000 |
318 | +++ bzrlib/tests/test_shelf.py 2009-08-27 08:35:10 +0000 |
319 | @@ -46,6 +46,8 @@ |
320 | tree.add(['foo'], ['foo-id']) |
321 | tree.commit('foo') |
322 | tree.rename_one('foo', 'bar') |
323 | + tree.lock_tree_write() |
324 | + self.addCleanup(tree.unlock) |
325 | creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
326 | self.addCleanup(creator.finalize) |
327 | self.assertEqual([('rename', 'foo-id', 'foo', 'bar')], |
328 | @@ -76,6 +78,8 @@ |
329 | tree.add(['foo', 'bar', 'foo/baz'], ['foo-id', 'bar-id', 'baz-id']) |
330 | tree.commit('foo') |
331 | tree.rename_one('foo/baz', 'bar/baz') |
332 | + tree.lock_tree_write() |
333 | + self.addCleanup(tree.unlock) |
334 | creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
335 | self.addCleanup(creator.finalize) |
336 | self.assertEqual([('rename', 'baz-id', 'foo/baz', 'bar/baz')], |
337 | @@ -310,6 +314,8 @@ |
338 | tree.add('foo', 'foo-id') |
339 | tree.commit('Added file and directory') |
340 | os.unlink('tree/foo') |
341 | + tree.lock_tree_write() |
342 | + self.addCleanup(tree.unlock) |
343 | creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
344 | self.addCleanup(creator.finalize) |
345 | self.assertEqual([('delete file', 'foo-id', 'file', 'foo')], |
346 | @@ -325,6 +331,8 @@ |
347 | tree.commit('Added file and directory') |
348 | os.unlink('tree/foo') |
349 | os.mkdir('tree/foo') |
350 | + tree.lock_tree_write() |
351 | + self.addCleanup(tree.unlock) |
352 | creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
353 | self.addCleanup(creator.finalize) |
354 | self.assertEqual([('change kind', 'foo-id', 'file', 'directory', |
355 | @@ -352,6 +360,8 @@ |
356 | |
357 | def test_shelve_change_unknown_change(self): |
358 | tree = self.make_branch_and_tree('tree') |
359 | + tree.lock_tree_write() |
360 | + self.addCleanup(tree.unlock) |
361 | creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
362 | self.addCleanup(creator.finalize) |
363 | e = self.assertRaises(ValueError, creator.shelve_change, ('unknown',)) |
364 | @@ -363,6 +373,8 @@ |
365 | tree.add('foo', 'foo-id') |
366 | tree.commit('Added file and directory') |
367 | tree.unversion(['foo-id']) |
368 | + tree.lock_tree_write() |
369 | + self.addCleanup(tree.unlock) |
370 | creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
371 | self.addCleanup(creator.finalize) |
372 | self.assertEqual([('delete file', 'foo-id', 'file', 'foo')], |
373 | @@ -373,6 +385,8 @@ |
374 | |
375 | def test_shelve_serialization(self): |
376 | tree = self.make_branch_and_tree('.') |
377 | + tree.lock_tree_write() |
378 | + self.addCleanup(tree.unlock) |
379 | creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
380 | self.addCleanup(creator.finalize) |
381 | shelf_file = open('shelf', 'wb') |
382 | @@ -387,6 +401,8 @@ |
383 | tree = self.make_branch_and_tree('tree') |
384 | self.build_tree(['tree/foo']) |
385 | tree.add('foo', 'foo-id') |
386 | + tree.lock_tree_write() |
387 | + self.addCleanup(tree.unlock) |
388 | creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
389 | self.addCleanup(creator.finalize) |
390 | list(creator.iter_shelvable()) |
391 | @@ -411,8 +427,12 @@ |
392 | |
393 | def test_shelve_unversioned(self): |
394 | tree = self.make_branch_and_tree('tree') |
395 | - self.assertRaises(errors.PathsNotVersionedError, |
396 | - shelf.ShelfCreator, tree, tree.basis_tree(), ['foo']) |
397 | + tree.lock_tree_write() |
398 | + try: |
399 | + self.assertRaises(errors.PathsNotVersionedError, |
400 | + shelf.ShelfCreator, tree, tree.basis_tree(), ['foo']) |
401 | + finally: |
402 | + tree.unlock() |
403 | # We should be able to lock/unlock the tree if ShelfCreator cleaned |
404 | # after itself. |
405 | wt = workingtree.WorkingTree.open('tree') |
406 | @@ -420,8 +440,15 @@ |
407 | wt.unlock() |
408 | # And a second tentative should raise the same error (no |
409 | # limbo/pending_deletion leftovers). |
410 | - self.assertRaises(errors.PathsNotVersionedError, |
411 | - shelf.ShelfCreator, tree, tree.basis_tree(), ['foo']) |
412 | + tree.lock_tree_write() |
413 | + try: |
414 | + self.assertRaises(errors.PathsNotVersionedError, |
415 | + shelf.ShelfCreator, tree, tree.basis_tree(), ['foo']) |
416 | + finally: |
417 | + tree.unlock() |
418 | + |
419 | + tree.lock_tree_write() |
420 | + self.addCleanup(tree.unlock) |
421 | |
422 | |
423 | class TestUnshelver(tests.TestCaseWithTransport): |
424 | @@ -525,6 +552,7 @@ |
425 | shelf_file = open('shelf', 'rb') |
426 | self.addCleanup(shelf_file.close) |
427 | unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file) |
428 | + unshelver.finalize() |
429 | |
430 | def test_corrupt_shelf(self): |
431 | tree = self.make_branch_and_tree('.') |
432 | @@ -644,7 +672,10 @@ |
433 | |
434 | def test_get_metadata(self): |
435 | tree = self.make_branch_and_tree('.') |
436 | + tree.lock_tree_write() |
437 | + self.addCleanup(tree.unlock) |
438 | creator = shelf.ShelfCreator(tree, tree.basis_tree()) |
439 | + self.addCleanup(creator.finalize) |
440 | shelf_manager = tree.get_shelf_manager() |
441 | shelf_id = shelf_manager.shelve_changes(creator, 'foo') |
442 | metadata = shelf_manager.get_metadata(shelf_id) |
443 | |
444 | === modified file 'bzrlib/tests/test_shelf_ui.py' |
445 | --- bzrlib/tests/test_shelf_ui.py 2009-07-14 13:19:52 +0000 |
446 | +++ bzrlib/tests/test_shelf_ui.py 2009-08-27 08:35:10 +0000 |
447 | @@ -68,12 +68,16 @@ |
448 | |
449 | def test_unexpected_prompt_failure(self): |
450 | tree = self.create_shelvable_tree() |
451 | + tree.lock_tree_write() |
452 | + self.addCleanup(tree.unlock) |
453 | shelver = ExpectShelver(tree, tree.basis_tree()) |
454 | e = self.assertRaises(AssertionError, shelver.run) |
455 | self.assertEqual('Unexpected prompt: Shelve? [yNfq?]', str(e)) |
456 | |
457 | def test_wrong_prompt_failure(self): |
458 | tree = self.create_shelvable_tree() |
459 | + tree.lock_tree_write() |
460 | + self.addCleanup(tree.unlock) |
461 | shelver = ExpectShelver(tree, tree.basis_tree()) |
462 | shelver.expect('foo', 'y') |
463 | e = self.assertRaises(AssertionError, shelver.run) |
464 | @@ -81,6 +85,8 @@ |
465 | |
466 | def test_shelve_not_diff(self): |
467 | tree = self.create_shelvable_tree() |
468 | + tree.lock_tree_write() |
469 | + self.addCleanup(tree.unlock) |
470 | shelver = ExpectShelver(tree, tree.basis_tree()) |
471 | shelver.expect('Shelve? [yNfq?]', 'n') |
472 | shelver.expect('Shelve? [yNfq?]', 'n') |
473 | @@ -90,6 +96,8 @@ |
474 | |
475 | def test_shelve_diff_no(self): |
476 | tree = self.create_shelvable_tree() |
477 | + tree.lock_tree_write() |
478 | + self.addCleanup(tree.unlock) |
479 | shelver = ExpectShelver(tree, tree.basis_tree()) |
480 | shelver.expect('Shelve? [yNfq?]', 'y') |
481 | shelver.expect('Shelve? [yNfq?]', 'y') |
482 | @@ -99,6 +107,8 @@ |
483 | |
484 | def test_shelve_diff(self): |
485 | tree = self.create_shelvable_tree() |
486 | + tree.lock_tree_write() |
487 | + self.addCleanup(tree.unlock) |
488 | shelver = ExpectShelver(tree, tree.basis_tree()) |
489 | shelver.expect('Shelve? [yNfq?]', 'y') |
490 | shelver.expect('Shelve? [yNfq?]', 'y') |
491 | @@ -108,6 +118,8 @@ |
492 | |
493 | def test_shelve_one_diff(self): |
494 | tree = self.create_shelvable_tree() |
495 | + tree.lock_tree_write() |
496 | + self.addCleanup(tree.unlock) |
497 | shelver = ExpectShelver(tree, tree.basis_tree()) |
498 | shelver.expect('Shelve? [yNfq?]', 'y') |
499 | shelver.expect('Shelve? [yNfq?]', 'n') |
500 | @@ -118,6 +130,8 @@ |
501 | def test_shelve_binary_change(self): |
502 | tree = self.create_shelvable_tree() |
503 | self.build_tree_contents([('tree/foo', '\x00')]) |
504 | + tree.lock_tree_write() |
505 | + self.addCleanup(tree.unlock) |
506 | shelver = ExpectShelver(tree, tree.basis_tree()) |
507 | shelver.expect('Shelve binary changes? [yNfq?]', 'y') |
508 | shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y') |
509 | @@ -127,6 +141,8 @@ |
510 | def test_shelve_rename(self): |
511 | tree = self.create_shelvable_tree() |
512 | tree.rename_one('foo', 'bar') |
513 | + tree.lock_tree_write() |
514 | + self.addCleanup(tree.unlock) |
515 | shelver = ExpectShelver(tree, tree.basis_tree()) |
516 | shelver.expect('Shelve renaming "foo" => "bar"? [yNfq?]', 'y') |
517 | shelver.expect('Shelve? [yNfq?]', 'y') |
518 | @@ -138,6 +154,8 @@ |
519 | def test_shelve_deletion(self): |
520 | tree = self.create_shelvable_tree() |
521 | os.unlink('tree/foo') |
522 | + tree.lock_tree_write() |
523 | + self.addCleanup(tree.unlock) |
524 | shelver = ExpectShelver(tree, tree.basis_tree()) |
525 | shelver.expect('Shelve removing file "foo"? [yNfq?]', 'y') |
526 | shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y') |
527 | @@ -149,6 +167,8 @@ |
528 | tree.commit('add tree root') |
529 | self.build_tree(['tree/foo']) |
530 | tree.add('foo') |
531 | + tree.lock_tree_write() |
532 | + self.addCleanup(tree.unlock) |
533 | shelver = ExpectShelver(tree, tree.basis_tree()) |
534 | shelver.expect('Shelve adding file "foo"? [yNfq?]', 'y') |
535 | shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y') |
536 | @@ -159,6 +179,8 @@ |
537 | tree = self.create_shelvable_tree() |
538 | os.unlink('tree/foo') |
539 | os.mkdir('tree/foo') |
540 | + tree.lock_tree_write() |
541 | + self.addCleanup(tree.unlock) |
542 | shelver = ExpectShelver(tree, tree.basis_tree()) |
543 | shelver.expect('Shelve changing "foo" from file to directory? [yNfq?]', |
544 | 'y') |
545 | @@ -172,6 +194,8 @@ |
546 | tree.commit("Add symlink") |
547 | os.unlink('tree/baz') |
548 | os.symlink('vax', 'tree/baz') |
549 | + tree.lock_tree_write() |
550 | + self.addCleanup(tree.unlock) |
551 | shelver = ExpectShelver(tree, tree.basis_tree()) |
552 | shelver.expect('Shelve changing target of "baz" from "bar" to ' |
553 | '"vax"? [yNfq?]', 'y') |
554 | @@ -181,6 +205,8 @@ |
555 | |
556 | def test_shelve_finish(self): |
557 | tree = self.create_shelvable_tree() |
558 | + tree.lock_tree_write() |
559 | + self.addCleanup(tree.unlock) |
560 | shelver = ExpectShelver(tree, tree.basis_tree()) |
561 | shelver.expect('Shelve? [yNfq?]', 'f') |
562 | shelver.expect('Shelve 2 change(s)? [yNfq?]', 'y') |
563 | @@ -189,6 +215,8 @@ |
564 | |
565 | def test_shelve_quit(self): |
566 | tree = self.create_shelvable_tree() |
567 | + tree.lock_tree_write() |
568 | + self.addCleanup(tree.unlock) |
569 | shelver = ExpectShelver(tree, tree.basis_tree()) |
570 | shelver.expect('Shelve? [yNfq?]', 'q') |
571 | self.assertRaises(errors.UserAbort, shelver.run) |
572 | @@ -196,13 +224,20 @@ |
573 | |
574 | def test_shelve_all(self): |
575 | tree = self.create_shelvable_tree() |
576 | - ExpectShelver.from_args(sys.stdout, all=True, directory='tree').run() |
577 | + shelver = ExpectShelver.from_args(sys.stdout, all=True, |
578 | + directory='tree') |
579 | + try: |
580 | + shelver.run() |
581 | + finally: |
582 | + shelver.work_tree.unlock() |
583 | self.assertFileEqual(LINES_AJ, 'tree/foo') |
584 | |
585 | def test_shelve_filename(self): |
586 | tree = self.create_shelvable_tree() |
587 | self.build_tree(['tree/bar']) |
588 | tree.add('bar') |
589 | + tree.lock_tree_write() |
590 | + self.addCleanup(tree.unlock) |
591 | shelver = ExpectShelver(tree, tree.basis_tree(), file_list=['bar']) |
592 | shelver.expect('Shelve adding file "bar"? [yNfq?]', 'y') |
593 | shelver.expect('Shelve 1 change(s)? [yNfq?]', 'y') |
594 | @@ -210,6 +245,8 @@ |
595 | |
596 | def test_shelve_help(self): |
597 | tree = self.create_shelvable_tree() |
598 | + tree.lock_tree_write() |
599 | + self.addCleanup(tree.unlock) |
600 | shelver = ExpectShelver(tree, tree.basis_tree()) |
601 | shelver.expect('Shelve? [yNfq?]', '?') |
602 | shelver.expect('Shelve? [(y)es, (N)o, (f)inish, or (q)uit]', 'f') |
603 | @@ -220,7 +257,10 @@ |
604 | tree = self.create_shelvable_tree() |
605 | shelver = shelf_ui.Shelver.from_args(sys.stdout, all=True, |
606 | directory='tree', destroy=True) |
607 | - shelver.run() |
608 | + try: |
609 | + shelver.run() |
610 | + finally: |
611 | + shelver.work_tree.unlock() |
612 | self.assertIs(None, tree.get_shelf_manager().last_shelf()) |
613 | self.assertFileEqual(LINES_AJ, 'tree/foo') |
614 | |
615 | @@ -229,6 +269,8 @@ |
616 | |
617 | def test_shelve_not_diff(self): |
618 | tree = self.create_shelvable_tree() |
619 | + tree.lock_tree_write() |
620 | + self.addCleanup(tree.unlock) |
621 | shelver = ExpectShelver(tree, tree.basis_tree(), |
622 | reporter=shelf_ui.ApplyReporter()) |
623 | shelver.expect('Apply change? [yNfq?]', 'n') |
624 | @@ -239,6 +281,8 @@ |
625 | |
626 | def test_shelve_diff_no(self): |
627 | tree = self.create_shelvable_tree() |
628 | + tree.lock_tree_write() |
629 | + self.addCleanup(tree.unlock) |
630 | shelver = ExpectShelver(tree, tree.basis_tree(), |
631 | reporter=shelf_ui.ApplyReporter()) |
632 | shelver.expect('Apply change? [yNfq?]', 'y') |
633 | @@ -249,6 +293,8 @@ |
634 | |
635 | def test_shelve_diff(self): |
636 | tree = self.create_shelvable_tree() |
637 | + tree.lock_tree_write() |
638 | + self.addCleanup(tree.unlock) |
639 | shelver = ExpectShelver(tree, tree.basis_tree(), |
640 | reporter=shelf_ui.ApplyReporter()) |
641 | shelver.expect('Apply change? [yNfq?]', 'y') |
642 | @@ -260,6 +306,8 @@ |
643 | def test_shelve_binary_change(self): |
644 | tree = self.create_shelvable_tree() |
645 | self.build_tree_contents([('tree/foo', '\x00')]) |
646 | + tree.lock_tree_write() |
647 | + self.addCleanup(tree.unlock) |
648 | shelver = ExpectShelver(tree, tree.basis_tree(), |
649 | reporter=shelf_ui.ApplyReporter()) |
650 | shelver.expect('Apply binary changes? [yNfq?]', 'y') |
651 | @@ -270,6 +318,8 @@ |
652 | def test_shelve_rename(self): |
653 | tree = self.create_shelvable_tree() |
654 | tree.rename_one('foo', 'bar') |
655 | + tree.lock_tree_write() |
656 | + self.addCleanup(tree.unlock) |
657 | shelver = ExpectShelver(tree, tree.basis_tree(), |
658 | reporter=shelf_ui.ApplyReporter()) |
659 | shelver.expect('Rename "bar" => "foo"? [yNfq?]', 'y') |
660 | @@ -282,6 +332,8 @@ |
661 | def test_shelve_deletion(self): |
662 | tree = self.create_shelvable_tree() |
663 | os.unlink('tree/foo') |
664 | + tree.lock_tree_write() |
665 | + self.addCleanup(tree.unlock) |
666 | shelver = ExpectShelver(tree, tree.basis_tree(), |
667 | reporter=shelf_ui.ApplyReporter()) |
668 | shelver.expect('Add file "foo"? [yNfq?]', 'y') |
669 | @@ -294,6 +346,8 @@ |
670 | tree.commit('add tree root') |
671 | self.build_tree(['tree/foo']) |
672 | tree.add('foo') |
673 | + tree.lock_tree_write() |
674 | + self.addCleanup(tree.unlock) |
675 | shelver = ExpectShelver(tree, tree.basis_tree(), |
676 | reporter=shelf_ui.ApplyReporter()) |
677 | shelver.expect('Delete file "foo"? [yNfq?]', 'y') |
678 | @@ -305,6 +359,8 @@ |
679 | tree = self.create_shelvable_tree() |
680 | os.unlink('tree/foo') |
681 | os.mkdir('tree/foo') |
682 | + tree.lock_tree_write() |
683 | + self.addCleanup(tree.unlock) |
684 | shelver = ExpectShelver(tree, tree.basis_tree(), |
685 | reporter=shelf_ui.ApplyReporter()) |
686 | shelver.expect('Change "foo" from directory to a file? [yNfq?]', 'y') |
687 | @@ -318,6 +374,8 @@ |
688 | tree.commit("Add symlink") |
689 | os.unlink('tree/baz') |
690 | os.symlink('vax', 'tree/baz') |
691 | + tree.lock_tree_write() |
692 | + self.addCleanup(tree.unlock) |
693 | shelver = ExpectShelver(tree, tree.basis_tree(), |
694 | reporter=shelf_ui.ApplyReporter()) |
695 | shelver.expect('Change target of "baz" from "vax" to "bar"? [yNfq?]', |
696 | @@ -331,12 +389,16 @@ |
697 | |
698 | def create_tree_with_shelf(self): |
699 | tree = self.make_branch_and_tree('tree') |
700 | - self.build_tree_contents([('tree/foo', LINES_AJ)]) |
701 | - tree.add('foo', 'foo-id') |
702 | - tree.commit('added foo') |
703 | - self.build_tree_contents([('tree/foo', LINES_ZY)]) |
704 | - shelf_ui.Shelver(tree, tree.basis_tree(), auto_apply=True, |
705 | - auto=True).run() |
706 | + tree.lock_write() |
707 | + try: |
708 | + self.build_tree_contents([('tree/foo', LINES_AJ)]) |
709 | + tree.add('foo', 'foo-id') |
710 | + tree.commit('added foo') |
711 | + self.build_tree_contents([('tree/foo', LINES_ZY)]) |
712 | + shelf_ui.Shelver(tree, tree.basis_tree(), auto_apply=True, |
713 | + auto=True).run() |
714 | + finally: |
715 | + tree.unlock() |
716 | return tree |
717 | |
718 | def test_unshelve(self): |
719 | @@ -349,13 +411,22 @@ |
720 | |
721 | def test_unshelve_args(self): |
722 | tree = self.create_tree_with_shelf() |
723 | - shelf_ui.Unshelver.from_args(directory='tree').run() |
724 | + unshelver = shelf_ui.Unshelver.from_args(directory='tree') |
725 | + try: |
726 | + unshelver.run() |
727 | + finally: |
728 | + unshelver.tree.unlock() |
729 | self.assertFileEqual(LINES_ZY, 'tree/foo') |
730 | self.assertIs(None, tree.get_shelf_manager().last_shelf()) |
731 | |
732 | def test_unshelve_args_dry_run(self): |
733 | tree = self.create_tree_with_shelf() |
734 | - shelf_ui.Unshelver.from_args(directory='tree', action='dry-run').run() |
735 | + unshelver = shelf_ui.Unshelver.from_args(directory='tree', |
736 | + action='dry-run') |
737 | + try: |
738 | + unshelver.run() |
739 | + finally: |
740 | + unshelver.tree.unlock() |
741 | self.assertFileEqual(LINES_AJ, 'tree/foo') |
742 | self.assertEqual(1, tree.get_shelf_manager().last_shelf()) |
743 | |
744 | @@ -369,7 +440,10 @@ |
745 | shelf_file.close() |
746 | unshelver = shelf_ui.Unshelver.from_args(directory='tree', |
747 | action='delete-only') |
748 | - unshelver.run() |
749 | + try: |
750 | + unshelver.run() |
751 | + finally: |
752 | + unshelver.tree.unlock() |
753 | self.assertIs(None, manager.last_shelf()) |
754 | |
755 | def test_unshelve_args_invalid_shelf_id(self): |
I've cherrypicked 2 revisions from bzr.dev (4635 and 4650) which contains fixes for OS locks problems on Windows (local push and shelve).
Will be nice if Robert will review result of cherrypick and then I'd like to propose merge it back to 1.18 branch and prepare 1.18.1 release soon. Even if this will be win32-only release.
I think this will help to get more testing of these changes and provides more windows users benefits of fixes.