Merge lp:~bialix/bzr/bzr-1.18-oslocks-win32 into lp:bzr/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
Reviewer Review Type Date Requested Status
Vincent Ladeuil (community) Approve
Robert Collins Pending
Review via email: mp+10793@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Alexander Belchenko (bialix) wrote :

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.

Revision history for this message
Robert Collins (lifeless) wrote :

review +1

Revision history for this message
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):

Subscribers

People subscribed via source and target branches