/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_shelf.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
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.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2008-2011 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
import os
 
18
 
 
19
from bzrlib import (
 
20
    errors,
 
21
    osutils,
 
22
    pack,
 
23
    shelf,
 
24
    tests,
 
25
    transform,
 
26
    workingtree,
 
27
    )
 
28
from bzrlib.tests import (
 
29
    features,
 
30
    )
 
31
 
 
32
 
 
33
EMPTY_SHELF = ("Bazaar pack format 1 (introduced in 0.18)\n"
 
34
               "B23\n"
 
35
               "metadata\n\n"
 
36
               "d11:revision_id5:null:e"
 
37
               "B159\n"
 
38
               "attribs\n\n"
 
39
               "d10:_id_numberi0e18:_new_executabilityde7:_new_idde"
 
40
               "9:_new_namede11:_new_parentde16:_non_present_idsde"
 
41
               "17:_removed_contentsle11:_removed_idle14:_tree_path_idsdeeE")
 
42
 
 
43
 
 
44
class TestPrepareShelf(tests.TestCaseWithTransport):
 
45
 
 
46
    def prepare_shelve_rename(self):
 
47
        tree = self.make_branch_and_tree('.')
 
48
        self.build_tree(['foo'])
 
49
        tree.add(['foo'], ['foo-id'])
 
50
        tree.commit('foo')
 
51
        tree.rename_one('foo', 'bar')
 
52
        tree.lock_tree_write()
 
53
        self.addCleanup(tree.unlock)
 
54
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
55
        self.addCleanup(creator.finalize)
 
56
        self.assertEqual([('rename', 'foo-id', 'foo', 'bar')],
 
57
                          list(creator.iter_shelvable()))
 
58
        return creator
 
59
 
 
60
    def check_shelve_rename(self, creator):
 
61
        work_trans_id = creator.work_transform.trans_id_file_id('foo-id')
 
62
        self.assertEqual('foo', creator.work_transform.final_name(
 
63
                         work_trans_id))
 
64
        shelf_trans_id = creator.shelf_transform.trans_id_file_id('foo-id')
 
65
        self.assertEqual('bar', creator.shelf_transform.final_name(
 
66
                         shelf_trans_id))
 
67
 
 
68
    def test_shelve_rename(self):
 
69
        creator = self.prepare_shelve_rename()
 
70
        creator.shelve_rename('foo-id')
 
71
        self.check_shelve_rename(creator)
 
72
 
 
73
    def test_shelve_change_handles_rename(self):
 
74
        creator = self.prepare_shelve_rename()
 
75
        creator.shelve_change(('rename', 'foo-id', 'foo', 'bar'))
 
76
        self.check_shelve_rename(creator)
 
77
 
 
78
    def prepare_shelve_move(self):
 
79
        tree = self.make_branch_and_tree('.')
 
80
        self.build_tree(['foo/', 'bar/', 'foo/baz'])
 
81
        tree.add(['foo', 'bar', 'foo/baz'], ['foo-id', 'bar-id', 'baz-id'])
 
82
        tree.commit('foo')
 
83
        tree.rename_one('foo/baz', 'bar/baz')
 
84
        tree.lock_tree_write()
 
85
        self.addCleanup(tree.unlock)
 
86
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
87
        self.addCleanup(creator.finalize)
 
88
        self.assertEqual([('rename', 'baz-id', 'foo/baz', 'bar/baz')],
 
89
                         list(creator.iter_shelvable()))
 
90
        return creator, tree
 
91
 
 
92
    def check_shelve_move(self, creator, tree):
 
93
        work_trans_id = creator.work_transform.trans_id_file_id('baz-id')
 
94
        work_foo = creator.work_transform.trans_id_file_id('foo-id')
 
95
        self.assertEqual(work_foo, creator.work_transform.final_parent(
 
96
                         work_trans_id))
 
97
        shelf_trans_id = creator.shelf_transform.trans_id_file_id('baz-id')
 
98
        shelf_bar = creator.shelf_transform.trans_id_file_id('bar-id')
 
99
        self.assertEqual(shelf_bar, creator.shelf_transform.final_parent(
 
100
                         shelf_trans_id))
 
101
        creator.transform()
 
102
        self.assertEqual('foo/baz', tree.id2path('baz-id'))
 
103
 
 
104
    def test_shelve_move(self):
 
105
        creator, tree = self.prepare_shelve_move()
 
106
        creator.shelve_rename('baz-id')
 
107
        self.check_shelve_move(creator, tree)
 
108
 
 
109
    def test_shelve_change_handles_move(self):
 
110
        creator, tree = self.prepare_shelve_move()
 
111
        creator.shelve_change(('rename', 'baz-id', 'foo/baz', 'bar/baz'))
 
112
        self.check_shelve_move(creator, tree)
 
113
 
 
114
    def test_shelve_changed_root_id(self):
 
115
        tree = self.make_branch_and_tree('.')
 
116
        self.build_tree(['foo'])
 
117
        tree.set_root_id('first-root-id')
 
118
        tree.add(['foo'], ['foo-id'])
 
119
        tree.commit('foo')
 
120
        tree.set_root_id('second-root-id')
 
121
        tree.lock_tree_write()
 
122
        self.addCleanup(tree.unlock)
 
123
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
124
        self.addCleanup(creator.finalize)
 
125
        self.expectFailure('shelf doesn\'t support shelving root changes yet',
 
126
            self.assertEqual, [
 
127
                ('delete file', 'first-root-id', 'directory', ''),
 
128
                ('add file', 'second-root-id', 'directory', ''),
 
129
                ('rename', 'foo-id', u'foo', u'foo'),
 
130
                ], list(creator.iter_shelvable()))
 
131
 
 
132
        self.assertEqual([('delete file', 'first-root-id', 'directory', ''),
 
133
                          ('add file', 'second-root-id', 'directory', ''),
 
134
                          ('rename', 'foo-id', u'foo', u'foo'),
 
135
                         ], list(creator.iter_shelvable()))
 
136
 
 
137
    def assertShelvedFileEqual(self, expected_content, creator, file_id):
 
138
        s_trans_id = creator.shelf_transform.trans_id_file_id(file_id)
 
139
        shelf_file = creator.shelf_transform._limbo_name(s_trans_id)
 
140
        self.assertFileEqual(expected_content, shelf_file)
 
141
 
 
142
    def prepare_content_change(self):
 
143
        tree = self.make_branch_and_tree('.')
 
144
        tree.lock_write()
 
145
        self.addCleanup(tree.unlock)
 
146
        self.build_tree_contents([('foo', 'a\n')])
 
147
        tree.add('foo', 'foo-id')
 
148
        tree.commit('Committed foo')
 
149
        self.build_tree_contents([('foo', 'b\na\nc\n')])
 
150
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
151
        self.addCleanup(creator.finalize)
 
152
        return creator
 
153
 
 
154
    def test_shelve_content_change(self):
 
155
        creator = self.prepare_content_change()
 
156
        self.assertEqual([('modify text', 'foo-id')],
 
157
                         list(creator.iter_shelvable()))
 
158
        creator.shelve_lines('foo-id', ['a\n', 'c\n'])
 
159
        creator.transform()
 
160
        self.assertFileEqual('a\nc\n', 'foo')
 
161
        self.assertShelvedFileEqual('b\na\n', creator, 'foo-id')
 
162
 
 
163
    def test_shelve_change_handles_modify_text(self):
 
164
        creator = self.prepare_content_change()
 
165
        creator.shelve_change(('modify text', 'foo-id'))
 
166
        creator.transform()
 
167
        self.assertFileEqual('a\n', 'foo')
 
168
        self.assertShelvedFileEqual('b\na\nc\n', creator, 'foo-id')
 
169
 
 
170
    def test_shelve_all(self):
 
171
        creator = self.prepare_content_change()
 
172
        creator.shelve_all()
 
173
        creator.transform()
 
174
        self.assertFileEqual('a\n', 'foo')
 
175
        self.assertShelvedFileEqual('b\na\nc\n', creator, 'foo-id')
 
176
 
 
177
    def prepare_shelve_creation(self):
 
178
        tree = self.make_branch_and_tree('.')
 
179
        tree.lock_write()
 
180
        self.addCleanup(tree.unlock)
 
181
        tree.commit('Empty tree')
 
182
        self.build_tree_contents([('foo', 'a\n'), ('bar/',)])
 
183
        tree.add(['foo', 'bar'], ['foo-id', 'bar-id'])
 
184
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
185
        self.addCleanup(creator.finalize)
 
186
        self.assertEqual([('add file', 'bar-id', 'directory', 'bar'),
 
187
                          ('add file', 'foo-id', 'file', 'foo')],
 
188
                          sorted(list(creator.iter_shelvable())))
 
189
        return creator, tree
 
190
 
 
191
    def check_shelve_creation(self, creator, tree):
 
192
        self.assertRaises(StopIteration,
 
193
                          tree.iter_entries_by_dir(['foo-id']).next)
 
194
        s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id')
 
195
        self.assertEqual('foo-id',
 
196
                         creator.shelf_transform.final_file_id(s_trans_id))
 
197
        self.assertPathDoesNotExist('foo')
 
198
        self.assertPathDoesNotExist('bar')
 
199
        self.assertShelvedFileEqual('a\n', creator, 'foo-id')
 
200
        s_bar_trans_id = creator.shelf_transform.trans_id_file_id('bar-id')
 
201
        self.assertEqual('directory',
 
202
            creator.shelf_transform.final_kind(s_bar_trans_id))
 
203
 
 
204
    def test_shelve_creation(self):
 
205
        creator, tree = self.prepare_shelve_creation()
 
206
        creator.shelve_creation('foo-id')
 
207
        creator.shelve_creation('bar-id')
 
208
        creator.transform()
 
209
        self.check_shelve_creation(creator, tree)
 
210
 
 
211
    def test_shelve_change_handles_creation(self):
 
212
        creator, tree = self.prepare_shelve_creation()
 
213
        creator.shelve_change(('add file', 'foo-id', 'file', 'foo'))
 
214
        creator.shelve_change(('add file', 'bar-id', 'directory', 'bar'))
 
215
        creator.transform()
 
216
        self.check_shelve_creation(creator, tree)
 
217
 
 
218
    def _test_shelve_symlink_creation(self, link_name, link_target,
 
219
                                      shelve_change=False):
 
220
        self.requireFeature(features.SymlinkFeature)
 
221
        tree = self.make_branch_and_tree('.')
 
222
        tree.lock_write()
 
223
        self.addCleanup(tree.unlock)
 
224
        tree.commit('Empty tree')
 
225
        os.symlink(link_target, link_name)
 
226
        tree.add(link_name, 'foo-id')
 
227
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
228
        self.addCleanup(creator.finalize)
 
229
        self.assertEqual([('add file', 'foo-id', 'symlink', link_name)],
 
230
                         list(creator.iter_shelvable()))
 
231
        if shelve_change:
 
232
            creator.shelve_change(('add file', 'foo-id', 'symlink', link_name))
 
233
        else:
 
234
            creator.shelve_creation('foo-id')
 
235
        creator.transform()
 
236
        s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id')
 
237
        self.assertPathDoesNotExist(link_name)
 
238
        limbo_name = creator.shelf_transform._limbo_name(s_trans_id)
 
239
        self.assertEqual(link_target, osutils.readlink(limbo_name))
 
240
        ptree = creator.shelf_transform.get_preview_tree()
 
241
        self.assertEqual(link_target, ptree.get_symlink_target('foo-id'))
 
242
 
 
243
    def test_shelve_symlink_creation(self):
 
244
        self._test_shelve_symlink_creation('foo', 'bar')
 
245
 
 
246
    def test_shelve_unicode_symlink_creation(self):
 
247
        self.requireFeature(features.UnicodeFilenameFeature)
 
248
        self._test_shelve_symlink_creation(u'fo\N{Euro Sign}o',
 
249
                                           u'b\N{Euro Sign}ar')
 
250
 
 
251
    def test_shelve_change_handles_symlink_creation(self):
 
252
        self._test_shelve_symlink_creation('foo', 'bar', shelve_change=True)
 
253
 
 
254
    def _test_shelve_symlink_target_change(self, link_name,
 
255
                                           old_target, new_target,
 
256
                                           shelve_change=False):
 
257
        self.requireFeature(features.SymlinkFeature)
 
258
        tree = self.make_branch_and_tree('.')
 
259
        tree.lock_write()
 
260
        self.addCleanup(tree.unlock)
 
261
        os.symlink(old_target, link_name)
 
262
        tree.add(link_name, 'foo-id')
 
263
        tree.commit("commit symlink")
 
264
        os.unlink(link_name)
 
265
        os.symlink(new_target, link_name)
 
266
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
267
        self.addCleanup(creator.finalize)
 
268
        self.assertEqual([('modify target', 'foo-id', link_name,
 
269
                           old_target, new_target)],
 
270
                         list(creator.iter_shelvable()))
 
271
        if shelve_change:
 
272
            creator.shelve_change(('modify target', 'foo-id', link_name,
 
273
                                   old_target, new_target))
 
274
        else:
 
275
            creator.shelve_modify_target('foo-id')
 
276
        creator.transform()
 
277
        self.assertEqual(old_target, osutils.readlink(link_name))
 
278
        s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id')
 
279
        limbo_name = creator.shelf_transform._limbo_name(s_trans_id)
 
280
        self.assertEqual(new_target, osutils.readlink(limbo_name))
 
281
        ptree = creator.shelf_transform.get_preview_tree()
 
282
        self.assertEqual(new_target, ptree.get_symlink_target('foo-id'))
 
283
 
 
284
    def test_shelve_symlink_target_change(self):
 
285
        self._test_shelve_symlink_target_change('foo', 'bar', 'baz')
 
286
 
 
287
    def test_shelve_unicode_symlink_target_change(self):
 
288
        self.requireFeature(features.UnicodeFilenameFeature)
 
289
        self._test_shelve_symlink_target_change(
 
290
            u'fo\N{Euro Sign}o', u'b\N{Euro Sign}ar', u'b\N{Euro Sign}az')
 
291
 
 
292
    def test_shelve_change_handles_symlink_target_change(self):
 
293
        self._test_shelve_symlink_target_change('foo', 'bar', 'baz',
 
294
                                                shelve_change=True)
 
295
 
 
296
    def test_shelve_creation_no_contents(self):
 
297
        tree = self.make_branch_and_tree('.')
 
298
        tree.lock_write()
 
299
        self.addCleanup(tree.unlock)
 
300
        tree.commit('Empty tree')
 
301
        self.build_tree(['foo'])
 
302
        tree.add('foo', 'foo-id')
 
303
        os.unlink('foo')
 
304
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
305
        self.addCleanup(creator.finalize)
 
306
        self.assertEqual([('add file', 'foo-id', None, 'foo')],
 
307
                         sorted(list(creator.iter_shelvable())))
 
308
        creator.shelve_creation('foo-id')
 
309
        creator.transform()
 
310
        self.assertRaises(StopIteration,
 
311
                          tree.iter_entries_by_dir(['foo-id']).next)
 
312
        self.assertShelvedFileEqual('', creator, 'foo-id')
 
313
        s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id')
 
314
        self.assertEqual('foo-id',
 
315
                         creator.shelf_transform.final_file_id(s_trans_id))
 
316
        self.assertPathDoesNotExist('foo')
 
317
 
 
318
    def prepare_shelve_deletion(self):
 
319
        tree = self.make_branch_and_tree('tree')
 
320
        tree.lock_write()
 
321
        self.addCleanup(tree.unlock)
 
322
        self.build_tree_contents([('tree/foo/',), ('tree/foo/bar', 'baz')])
 
323
        tree.add(['foo', 'foo/bar'], ['foo-id', 'bar-id'])
 
324
        tree.commit('Added file and directory')
 
325
        tree.unversion(['foo-id', 'bar-id'])
 
326
        os.unlink('tree/foo/bar')
 
327
        os.rmdir('tree/foo')
 
328
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
329
        self.addCleanup(creator.finalize)
 
330
        self.assertEqual([('delete file', 'bar-id', 'file', 'foo/bar'),
 
331
                          ('delete file', 'foo-id', 'directory', 'foo')],
 
332
                          sorted(list(creator.iter_shelvable())))
 
333
        return creator, tree
 
334
 
 
335
    def check_shelve_deletion(self, tree):
 
336
        self.assertTrue(tree.has_id('foo-id'))
 
337
        self.assertTrue(tree.has_id('bar-id'))
 
338
        self.assertFileEqual('baz', 'tree/foo/bar')
 
339
 
 
340
    def test_shelve_deletion(self):
 
341
        creator, tree = self.prepare_shelve_deletion()
 
342
        creator.shelve_deletion('foo-id')
 
343
        creator.shelve_deletion('bar-id')
 
344
        creator.transform()
 
345
        self.check_shelve_deletion(tree)
 
346
 
 
347
    def test_shelve_change_handles_deletion(self):
 
348
        creator, tree = self.prepare_shelve_deletion()
 
349
        creator.shelve_change(('delete file', 'foo-id', 'directory', 'foo'))
 
350
        creator.shelve_change(('delete file', 'bar-id', 'file', 'foo/bar'))
 
351
        creator.transform()
 
352
        self.check_shelve_deletion(tree)
 
353
 
 
354
    def test_shelve_delete_contents(self):
 
355
        tree = self.make_branch_and_tree('tree')
 
356
        self.build_tree(['tree/foo',])
 
357
        tree.add('foo', 'foo-id')
 
358
        tree.commit('Added file and directory')
 
359
        os.unlink('tree/foo')
 
360
        tree.lock_tree_write()
 
361
        self.addCleanup(tree.unlock)
 
362
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
363
        self.addCleanup(creator.finalize)
 
364
        self.assertEqual([('delete file', 'foo-id', 'file', 'foo')],
 
365
                         sorted(list(creator.iter_shelvable())))
 
366
        creator.shelve_deletion('foo-id')
 
367
        creator.transform()
 
368
        self.assertPathExists('tree/foo')
 
369
 
 
370
    def prepare_shelve_change_kind(self):
 
371
        tree = self.make_branch_and_tree('tree')
 
372
        self.build_tree_contents([('tree/foo', 'bar')])
 
373
        tree.add('foo', 'foo-id')
 
374
        tree.commit('Added file and directory')
 
375
        os.unlink('tree/foo')
 
376
        os.mkdir('tree/foo')
 
377
        tree.lock_tree_write()
 
378
        self.addCleanup(tree.unlock)
 
379
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
380
        self.addCleanup(creator.finalize)
 
381
        self.assertEqual([('change kind', 'foo-id', 'file', 'directory',
 
382
                           'foo')], sorted(list(creator.iter_shelvable())))
 
383
        return creator
 
384
 
 
385
    def check_shelve_change_kind(self, creator):
 
386
        self.assertFileEqual('bar', 'tree/foo')
 
387
        s_trans_id = creator.shelf_transform.trans_id_file_id('foo-id')
 
388
        self.assertEqual('directory',
 
389
                         creator.shelf_transform._new_contents[s_trans_id])
 
390
 
 
391
    def test_shelve_change_kind(self):
 
392
        creator = self.prepare_shelve_change_kind()
 
393
        creator.shelve_content_change('foo-id')
 
394
        creator.transform()
 
395
        self.check_shelve_change_kind(creator)
 
396
 
 
397
    def test_shelve_change_handles_change_kind(self):
 
398
        creator = self.prepare_shelve_change_kind()
 
399
        creator.shelve_change(('change kind', 'foo-id', 'file', 'directory',
 
400
                               'foo'))
 
401
        creator.transform()
 
402
        self.check_shelve_change_kind(creator)
 
403
 
 
404
    def test_shelve_change_unknown_change(self):
 
405
        tree = self.make_branch_and_tree('tree')
 
406
        tree.lock_tree_write()
 
407
        self.addCleanup(tree.unlock)
 
408
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
409
        self.addCleanup(creator.finalize)
 
410
        e = self.assertRaises(ValueError, creator.shelve_change, ('unknown',))
 
411
        self.assertEqual('Unknown change kind: "unknown"', str(e))
 
412
 
 
413
    def test_shelve_unversion(self):
 
414
        tree = self.make_branch_and_tree('tree')
 
415
        self.build_tree(['tree/foo',])
 
416
        tree.add('foo', 'foo-id')
 
417
        tree.commit('Added file and directory')
 
418
        tree.unversion(['foo-id'])
 
419
        tree.lock_tree_write()
 
420
        self.addCleanup(tree.unlock)
 
421
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
422
        self.addCleanup(creator.finalize)
 
423
        self.assertEqual([('delete file', 'foo-id', 'file', 'foo')],
 
424
                         sorted(list(creator.iter_shelvable())))
 
425
        creator.shelve_deletion('foo-id')
 
426
        creator.transform()
 
427
        self.assertPathExists('tree/foo')
 
428
 
 
429
    def test_shelve_serialization(self):
 
430
        tree = self.make_branch_and_tree('.')
 
431
        tree.lock_tree_write()
 
432
        self.addCleanup(tree.unlock)
 
433
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
434
        self.addCleanup(creator.finalize)
 
435
        shelf_file = open('shelf', 'wb')
 
436
        self.addCleanup(shelf_file.close)
 
437
        try:
 
438
            creator.write_shelf(shelf_file)
 
439
        finally:
 
440
            shelf_file.close()
 
441
        self.assertFileEqual(EMPTY_SHELF, 'shelf')
 
442
 
 
443
    def test_write_shelf(self):
 
444
        tree = self.make_branch_and_tree('tree')
 
445
        self.build_tree(['tree/foo'])
 
446
        tree.add('foo', 'foo-id')
 
447
        tree.lock_tree_write()
 
448
        self.addCleanup(tree.unlock)
 
449
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
450
        self.addCleanup(creator.finalize)
 
451
        list(creator.iter_shelvable())
 
452
        creator.shelve_creation('foo-id')
 
453
        shelf_file = open('shelf', 'wb')
 
454
        try:
 
455
            creator.write_shelf(shelf_file)
 
456
        finally:
 
457
            shelf_file.close()
 
458
        parser = pack.ContainerPushParser()
 
459
        shelf_file = open('shelf', 'rb')
 
460
        try:
 
461
            parser.accept_bytes(shelf_file.read())
 
462
        finally:
 
463
            shelf_file.close()
 
464
        tt = transform.TransformPreview(tree)
 
465
        self.addCleanup(tt.finalize)
 
466
        records = iter(parser.read_pending_records())
 
467
        #skip revision-id
 
468
        records.next()
 
469
        tt.deserialize(records)
 
470
 
 
471
    def test_shelve_unversioned(self):
 
472
        tree = self.make_branch_and_tree('tree')
 
473
        tree.lock_tree_write()
 
474
        try:
 
475
            self.assertRaises(errors.PathsNotVersionedError,
 
476
                              shelf.ShelfCreator, tree, tree.basis_tree(), ['foo'])
 
477
        finally:
 
478
            tree.unlock()
 
479
        # We should be able to lock/unlock the tree if ShelfCreator cleaned
 
480
        # after itself.
 
481
        wt = workingtree.WorkingTree.open('tree')
 
482
        wt.lock_tree_write()
 
483
        wt.unlock()
 
484
        # And a second tentative should raise the same error (no
 
485
        # limbo/pending_deletion leftovers).
 
486
        tree.lock_tree_write()
 
487
        try:
 
488
            self.assertRaises(errors.PathsNotVersionedError,
 
489
                              shelf.ShelfCreator, tree, tree.basis_tree(), ['foo'])
 
490
        finally:
 
491
            tree.unlock()
 
492
 
 
493
    def test_shelve_skips_added_root(self):
 
494
        """Skip adds of the root when iterating through shelvable changes."""
 
495
        tree = self.make_branch_and_tree('tree')
 
496
        tree.lock_tree_write()
 
497
        self.addCleanup(tree.unlock)
 
498
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
499
        self.addCleanup(creator.finalize)
 
500
        self.assertEqual([], list(creator.iter_shelvable()))
 
501
 
 
502
    def test_shelve_skips_added_root(self):
 
503
        """Skip adds of the root when iterating through shelvable changes."""
 
504
        tree = self.make_branch_and_tree('tree')
 
505
        tree.lock_tree_write()
 
506
        self.addCleanup(tree.unlock)
 
507
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
508
        self.addCleanup(creator.finalize)
 
509
        self.assertEqual([], list(creator.iter_shelvable()))
 
510
 
 
511
 
 
512
class TestUnshelver(tests.TestCaseWithTransport):
 
513
 
 
514
    def test_make_merger(self):
 
515
        tree = self.make_branch_and_tree('tree')
 
516
        tree.commit('first commit')
 
517
        self.build_tree_contents([('tree/foo', 'bar')])
 
518
        tree.lock_write()
 
519
        self.addCleanup(tree.unlock)
 
520
        tree.add('foo', 'foo-id')
 
521
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
522
        self.addCleanup(creator.finalize)
 
523
        list(creator.iter_shelvable())
 
524
        creator.shelve_creation('foo-id')
 
525
        shelf_file = open('shelf-file', 'w+b')
 
526
        try:
 
527
            creator.write_shelf(shelf_file)
 
528
            creator.transform()
 
529
            shelf_file.seek(0)
 
530
            unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file)
 
531
            unshelver.make_merger().do_merge()
 
532
            self.addCleanup(unshelver.finalize)
 
533
            self.assertFileEqual('bar', 'tree/foo')
 
534
        finally:
 
535
            shelf_file.close()
 
536
 
 
537
    def test_unshelve_changed(self):
 
538
        tree = self.make_branch_and_tree('tree')
 
539
        tree.lock_write()
 
540
        self.addCleanup(tree.unlock)
 
541
        self.build_tree_contents([('tree/foo', 'a\nb\nc\n')])
 
542
        tree.add('foo', 'foo-id')
 
543
        tree.commit('first commit')
 
544
        self.build_tree_contents([('tree/foo', 'a\nb\nd\n')])
 
545
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
546
        self.addCleanup(creator.finalize)
 
547
        list(creator.iter_shelvable())
 
548
        creator.shelve_lines('foo-id', ['a\n', 'b\n', 'c\n'])
 
549
        shelf_file = open('shelf', 'w+b')
 
550
        self.addCleanup(shelf_file.close)
 
551
        creator.write_shelf(shelf_file)
 
552
        creator.transform()
 
553
        self.build_tree_contents([('tree/foo', 'z\na\nb\nc\n')])
 
554
        shelf_file.seek(0)
 
555
        unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file)
 
556
        self.addCleanup(unshelver.finalize)
 
557
        unshelver.make_merger().do_merge()
 
558
        self.assertFileEqual('z\na\nb\nd\n', 'tree/foo')
 
559
 
 
560
    def test_unshelve_deleted(self):
 
561
        tree = self.make_branch_and_tree('tree')
 
562
        tree.lock_write()
 
563
        self.addCleanup(tree.unlock)
 
564
        self.build_tree_contents([('tree/foo/',), ('tree/foo/bar', 'baz')])
 
565
        tree.add(['foo', 'foo/bar'], ['foo-id', 'bar-id'])
 
566
        tree.commit('Added file and directory')
 
567
        tree.unversion(['foo-id', 'bar-id'])
 
568
        os.unlink('tree/foo/bar')
 
569
        os.rmdir('tree/foo')
 
570
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
571
        list(creator.iter_shelvable())
 
572
        creator.shelve_deletion('foo-id')
 
573
        creator.shelve_deletion('bar-id')
 
574
        with open('shelf', 'w+b') as shelf_file:
 
575
            creator.write_shelf(shelf_file)
 
576
            creator.transform()
 
577
            creator.finalize()
 
578
        # validate the test setup
 
579
        self.assertTrue(tree.has_id('foo-id'))
 
580
        self.assertTrue(tree.has_id('bar-id'))
 
581
        self.assertFileEqual('baz', 'tree/foo/bar')
 
582
        with open('shelf', 'r+b') as shelf_file:
 
583
            unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file)
 
584
            self.addCleanup(unshelver.finalize)
 
585
            unshelver.make_merger().do_merge()
 
586
        self.assertFalse(tree.has_id('foo-id'))
 
587
        self.assertFalse(tree.has_id('bar-id'))
 
588
 
 
589
    def test_unshelve_base(self):
 
590
        tree = self.make_branch_and_tree('tree')
 
591
        tree.lock_write()
 
592
        self.addCleanup(tree.unlock)
 
593
        tree.commit('rev1', rev_id='rev1')
 
594
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
595
        self.addCleanup(creator.finalize)
 
596
        manager = tree.get_shelf_manager()
 
597
        shelf_id, shelf_file = manager.new_shelf()
 
598
        try:
 
599
            creator.write_shelf(shelf_file)
 
600
        finally:
 
601
            shelf_file.close()
 
602
        tree.commit('rev2', rev_id='rev2')
 
603
        shelf_file = manager.read_shelf(1)
 
604
        self.addCleanup(shelf_file.close)
 
605
        unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file)
 
606
        self.addCleanup(unshelver.finalize)
 
607
        self.assertEqual('rev1', unshelver.base_tree.get_revision_id())
 
608
 
 
609
    def test_unshelve_serialization(self):
 
610
        tree = self.make_branch_and_tree('.')
 
611
        self.build_tree_contents([('shelf', EMPTY_SHELF)])
 
612
        shelf_file = open('shelf', 'rb')
 
613
        self.addCleanup(shelf_file.close)
 
614
        unshelver = shelf.Unshelver.from_tree_and_shelf(tree, shelf_file)
 
615
        unshelver.finalize()
 
616
 
 
617
    def test_corrupt_shelf(self):
 
618
        tree = self.make_branch_and_tree('.')
 
619
        self.build_tree_contents([('shelf', EMPTY_SHELF.replace('metadata',
 
620
                                                                'foo'))])
 
621
        shelf_file = open('shelf', 'rb')
 
622
        self.addCleanup(shelf_file.close)
 
623
        e = self.assertRaises(errors.ShelfCorrupt,
 
624
                              shelf.Unshelver.from_tree_and_shelf, tree,
 
625
                              shelf_file)
 
626
        self.assertEqual('Shelf corrupt.', str(e))
 
627
 
 
628
    def test_unshelve_subdir_in_now_removed_dir(self):
 
629
        tree = self.make_branch_and_tree('.')
 
630
        self.addCleanup(tree.lock_write().unlock)
 
631
        self.build_tree(['dir/', 'dir/subdir/', 'dir/subdir/foo'])
 
632
        tree.add(['dir'], ['dir-id'])
 
633
        tree.commit('versioned dir')
 
634
        tree.add(['dir/subdir', 'dir/subdir/foo'], ['subdir-id', 'foo-id'])
 
635
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
636
        self.addCleanup(creator.finalize)
 
637
        for change in creator.iter_shelvable():
 
638
            creator.shelve_change(change)
 
639
        shelf_manager = tree.get_shelf_manager()
 
640
        shelf_id = shelf_manager.shelve_changes(creator)
 
641
        self.assertPathDoesNotExist('dir/subdir')
 
642
        tree.remove(['dir'])
 
643
        unshelver = shelf_manager.get_unshelver(shelf_id)
 
644
        self.addCleanup(unshelver.finalize)
 
645
        unshelver.make_merger().do_merge()
 
646
        self.assertPathExists('dir/subdir/foo')
 
647
        self.assertEqual('dir-id', tree.path2id('dir'))
 
648
        self.assertEqual('subdir-id', tree.path2id('dir/subdir'))
 
649
        self.assertEqual('foo-id', tree.path2id('dir/subdir/foo'))
 
650
 
 
651
 
 
652
class TestShelfManager(tests.TestCaseWithTransport):
 
653
 
 
654
    def test_get_shelf_manager(self):
 
655
        tree = self.make_branch_and_tree('.')
 
656
        manager = tree.get_shelf_manager()
 
657
        self.assertEqual(tree._transport.base + 'shelf/',
 
658
                         manager.transport.base)
 
659
 
 
660
    def get_manager(self):
 
661
        return self.make_branch_and_tree('.').get_shelf_manager()
 
662
 
 
663
    def test_get_shelf_filename(self):
 
664
        tree = self.make_branch_and_tree('.')
 
665
        manager = tree.get_shelf_manager()
 
666
        self.assertEqual('shelf-1', manager.get_shelf_filename(1))
 
667
 
 
668
    def test_get_shelf_ids(self):
 
669
        tree = self.make_branch_and_tree('.')
 
670
        manager = tree.get_shelf_manager()
 
671
        self.assertEqual([1, 3], manager.get_shelf_ids(
 
672
                         ['shelf-1', 'shelf-02', 'shelf-3']))
 
673
 
 
674
    def test_new_shelf(self):
 
675
        manager = self.get_manager()
 
676
        shelf_id, shelf_file = manager.new_shelf()
 
677
        shelf_file.close()
 
678
        self.assertEqual(1, shelf_id)
 
679
        shelf_id, shelf_file = manager.new_shelf()
 
680
        shelf_file.close()
 
681
        self.assertEqual(2, shelf_id)
 
682
        manager.delete_shelf(1)
 
683
        shelf_id, shelf_file = manager.new_shelf()
 
684
        shelf_file.close()
 
685
        self.assertEqual(3, shelf_id)
 
686
 
 
687
    def test_active_shelves(self):
 
688
        manager = self.get_manager()
 
689
        self.assertEqual([], manager.active_shelves())
 
690
        shelf_id, shelf_file = manager.new_shelf()
 
691
        shelf_file.close()
 
692
        self.assertEqual([1], manager.active_shelves())
 
693
 
 
694
    def test_delete_shelf(self):
 
695
        manager = self.get_manager()
 
696
        shelf_id, shelf_file = manager.new_shelf()
 
697
        shelf_file.close()
 
698
        self.assertEqual([1], manager.active_shelves())
 
699
        manager.delete_shelf(1)
 
700
        self.assertEqual([], manager.active_shelves())
 
701
 
 
702
    def test_last_shelf(self):
 
703
        manager = self.get_manager()
 
704
        self.assertIs(None, manager.last_shelf())
 
705
        shelf_id, shelf_file = manager.new_shelf()
 
706
        shelf_file.close()
 
707
        self.assertEqual(1, manager.last_shelf())
 
708
 
 
709
    def test_read_shelf(self):
 
710
        manager = self.get_manager()
 
711
        shelf_id, shelf_file = manager.new_shelf()
 
712
        try:
 
713
            shelf_file.write('foo')
 
714
        finally:
 
715
            shelf_file.close()
 
716
        shelf_id, shelf_file = manager.new_shelf()
 
717
        try:
 
718
            shelf_file.write('bar')
 
719
        finally:
 
720
            shelf_file.close()
 
721
        shelf_file = manager.read_shelf(1)
 
722
        try:
 
723
            self.assertEqual('foo', shelf_file.read())
 
724
        finally:
 
725
            shelf_file.close()
 
726
        shelf_file = manager.read_shelf(2)
 
727
        try:
 
728
            self.assertEqual('bar', shelf_file.read())
 
729
        finally:
 
730
            shelf_file.close()
 
731
 
 
732
    def test_read_non_existant(self):
 
733
        manager = self.get_manager()
 
734
        e = self.assertRaises(errors.NoSuchShelfId, manager.read_shelf, 1)
 
735
        self.assertEqual('No changes are shelved with id "1".', str(e))
 
736
 
 
737
    def test_shelve_changes(self):
 
738
        tree = self.make_branch_and_tree('tree')
 
739
        tree.commit('no-change commit')
 
740
        tree.lock_write()
 
741
        self.addCleanup(tree.unlock)
 
742
        self.build_tree_contents([('tree/foo', 'bar')])
 
743
        self.assertFileEqual('bar', 'tree/foo')
 
744
        tree.add('foo', 'foo-id')
 
745
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
746
        self.addCleanup(creator.finalize)
 
747
        list(creator.iter_shelvable())
 
748
        creator.shelve_creation('foo-id')
 
749
        shelf_manager = tree.get_shelf_manager()
 
750
        shelf_id = shelf_manager.shelve_changes(creator)
 
751
        self.assertPathDoesNotExist('tree/foo')
 
752
        unshelver = shelf_manager.get_unshelver(shelf_id)
 
753
        self.addCleanup(unshelver.finalize)
 
754
        unshelver.make_merger().do_merge()
 
755
        self.assertFileEqual('bar', 'tree/foo')
 
756
 
 
757
    def test_get_metadata(self):
 
758
        tree = self.make_branch_and_tree('.')
 
759
        tree.lock_tree_write()
 
760
        self.addCleanup(tree.unlock)
 
761
        creator = shelf.ShelfCreator(tree, tree.basis_tree())
 
762
        self.addCleanup(creator.finalize)
 
763
        shelf_manager = tree.get_shelf_manager()
 
764
        shelf_id = shelf_manager.shelve_changes(creator, 'foo')
 
765
        metadata = shelf_manager.get_metadata(shelf_id)
 
766
        self.assertEqual('foo', metadata['message'])
 
767
        self.assertEqual('null:', metadata['revision_id'])