/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1
# Copyright (C) 2006-2012, 2016 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 errno
18
from io import BytesIO
19
import os
20
import sys
21
import time
22
23
from ... import (
24
    errors,
25
    osutils,
26
    tests,
27
    trace,
28
    transform,
29
    urlutils,
30
    )
7490.133.26 by Jelmer Vernooij
Some fixes.
31
from ...tree import TreeChange
7490.129.8 by Jelmer Vernooij
Fix imports.
32
from ...bzr.conflicts import (
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
33
    DeletingParent,
34
    DuplicateEntry,
35
    DuplicateID,
36
    MissingParent,
37
    NonDirectoryParent,
38
    ParentLoop,
39
    UnversionedParent,
40
)
41
from ...errors import (
42
    DuplicateKey,
43
    ExistingLimbo,
44
    ExistingPendingDeletion,
45
    ImmortalPendingDeletion,
46
    LockError,
47
)
48
from ...osutils import (
49
    file_kind,
50
    pathjoin,
51
)
52
from .. import (
53
    features,
54
    TestSkipped,
55
    )
56
from ..features import (
57
    HardlinkFeature,
58
    SymlinkFeature,
59
    )
60
from ...transform import (
61
    create_from_tree,
62
    FinalPaths,
63
    resolve_conflicts,
64
    ROOT_PARENT,
65
    ImmortalLimbo,
66
    MalformedTransform,
67
    NoFinalPath,
68
    ReusingTransform,
7490.77.11 by Jelmer Vernooij
Merge lp:brz/3.1.
69
    TransformRenameFailed,
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
70
)
71
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
72
from breezy.bzr.inventorytree import InventoryTreeChange
7490.139.9 by Jelmer Vernooij
Fix tests.
73
from breezy.bzr.transform import resolve_checkout
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
74
7490.83.9 by Jelmer Vernooij
Split out per-tree transform preview tests.
75
from breezy.tests.per_workingtree import TestCaseWithWorkingTree
76
77
78
79
class TestTreeTransform(TestCaseWithWorkingTree):
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
80
81
    def setUp(self):
82
        super(TestTreeTransform, self).setUp()
83
        self.wt = self.make_branch_and_tree('wt')
84
85
    def transform(self):
86
        transform = self.wt.transform()
87
        self.addCleanup(transform.finalize)
88
        return transform, transform.root
89
90
    def transform_for_sha1_test(self):
91
        trans, root = self.transform()
7490.133.16 by Jelmer Vernooij
Merge refactor of conflict code.
92
        if getattr(self.wt, '_observed_sha1', None) is None:
93
            raise tests.TestNotApplicable(
94
                'wt format does not use _observed_sha1')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
95
        self.wt.lock_tree_write()
96
        self.addCleanup(self.wt.unlock)
97
        contents = [b'just some content\n']
98
        sha1 = osutils.sha_strings(contents)
99
        # Roll back the clock
100
        trans._creation_mtime = time.time() - 20.0
101
        return trans, root, contents, sha1
102
103
    def test_existing_limbo(self):
104
        transform, root = self.transform()
105
        limbo_name = transform._limbodir
106
        deletion_path = transform._deletiondir
107
        os.mkdir(pathjoin(limbo_name, 'hehe'))
108
        self.assertRaises(ImmortalLimbo, transform.apply)
109
        self.assertRaises(LockError, self.wt.unlock)
110
        self.assertRaises(ExistingLimbo, self.transform)
111
        self.assertRaises(LockError, self.wt.unlock)
112
        os.rmdir(pathjoin(limbo_name, 'hehe'))
113
        os.rmdir(limbo_name)
114
        os.rmdir(deletion_path)
115
        transform, root = self.transform()
116
        transform.apply()
117
118
    def test_existing_pending_deletion(self):
119
        transform, root = self.transform()
120
        deletion_path = self._limbodir = urlutils.local_path_from_url(
121
            transform._tree._transport.abspath('pending-deletion'))
122
        os.mkdir(pathjoin(deletion_path, 'blocking-directory'))
123
        self.assertRaises(ImmortalPendingDeletion, transform.apply)
124
        self.assertRaises(LockError, self.wt.unlock)
125
        self.assertRaises(ExistingPendingDeletion, self.transform)
126
127
    def test_build(self):
128
        transform, root = self.transform()
129
        self.wt.lock_tree_write()
130
        self.addCleanup(self.wt.unlock)
131
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
132
        imaginary_id = transform.trans_id_tree_path('imaginary')
133
        imaginary_id2 = transform.trans_id_tree_path('imaginary/')
134
        self.assertEqual(imaginary_id, imaginary_id2)
135
        self.assertEqual(root, transform.get_tree_parent(imaginary_id))
136
        self.assertEqual('directory', transform.final_kind(root))
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
137
        if self.wt.supports_setting_file_ids():
138
            self.assertEqual(self.wt.path2id(''), transform.final_file_id(root))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
139
        trans_id = transform.create_path('name', root)
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
140
        if self.wt.supports_setting_file_ids():
141
            self.assertIs(transform.final_file_id(trans_id), None)
142
        self.assertFalse(transform.final_is_versioned(trans_id))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
143
        self.assertIs(None, transform.final_kind(trans_id))
144
        transform.create_file([b'contents'], trans_id)
145
        transform.set_executability(True, trans_id)
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
146
        transform.version_file(trans_id, file_id=b'my_pretties')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
147
        self.assertRaises(DuplicateKey, transform.version_file,
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
148
                          trans_id, file_id=b'my_pretties')
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
149
        if self.wt.supports_setting_file_ids():
150
            self.assertEqual(transform.final_file_id(trans_id), b'my_pretties')
151
        self.assertTrue(transform.final_is_versioned(trans_id))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
152
        self.assertEqual(transform.final_parent(trans_id), root)
153
        self.assertIs(transform.final_parent(root), ROOT_PARENT)
154
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
155
        oz_id = transform.create_path('oz', root)
156
        transform.create_directory(oz_id)
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
157
        transform.version_file(oz_id, file_id=b'ozzie')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
158
        trans_id2 = transform.create_path('name2', root)
159
        transform.create_file([b'contents'], trans_id2)
160
        transform.set_executability(False, trans_id2)
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
161
        transform.version_file(trans_id2, file_id=b'my_pretties2')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
162
        modified_paths = transform.apply().modified_paths
163
        with self.wt.get_file('name') as f:
164
            self.assertEqual(b'contents', f.read())
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
165
        if self.wt.supports_setting_file_ids():
166
            self.assertEqual(self.wt.path2id('name'), b'my_pretties')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
167
        self.assertIs(self.wt.is_executable('name'), True)
168
        self.assertIs(self.wt.is_executable('name2'), False)
169
        self.assertEqual('directory', file_kind(self.wt.abspath('oz')))
170
        self.assertEqual(len(modified_paths), 3)
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
171
        if self.wt.supports_setting_file_ids():
172
            tree_mod_paths = [self.wt.abspath(self.wt.id2path(f)) for f in
173
                              (b'ozzie', b'my_pretties', b'my_pretties2')]
174
            self.assertSubset(tree_mod_paths, modified_paths)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
175
        # is it safe to finalize repeatedly?
176
        transform.finalize()
177
        transform.finalize()
178
179
    def test_apply_informs_tree_of_observed_sha1(self):
180
        trans, root, contents, sha1 = self.transform_for_sha1_test()
7490.133.26 by Jelmer Vernooij
Some fixes.
181
        from ...bzr.workingtree import InventoryWorkingTree
182
        if not isinstance(self.wt, InventoryWorkingTree):
183
            self.skipTest('not a bzr working tree')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
184
        trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
185
                                  sha1=sha1)
186
        calls = []
187
        orig = self.wt._observed_sha1
188
189
        def _observed_sha1(*args):
190
            calls.append(args)
191
            orig(*args)
192
        self.wt._observed_sha1 = _observed_sha1
193
        trans.apply()
194
        self.assertEqual([('file1', trans._observed_sha1s[trans_id])],
195
                         calls)
196
197
    def test_create_file_caches_sha1(self):
198
        trans, root, contents, sha1 = self.transform_for_sha1_test()
199
        trans_id = trans.create_path('file1', root)
200
        trans.create_file(contents, trans_id, sha1=sha1)
201
        st_val = osutils.lstat(trans._limbo_name(trans_id))
202
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
203
        self.assertEqual(o_sha1, sha1)
204
        self.assertEqualStat(o_st_val, st_val)
205
206
    def test__apply_insertions_updates_sha1(self):
207
        trans, root, contents, sha1 = self.transform_for_sha1_test()
208
        trans_id = trans.create_path('file1', root)
209
        trans.create_file(contents, trans_id, sha1=sha1)
210
        st_val = osutils.lstat(trans._limbo_name(trans_id))
211
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
212
        self.assertEqual(o_sha1, sha1)
213
        self.assertEqualStat(o_st_val, st_val)
214
        creation_mtime = trans._creation_mtime + 10.0
215
        # We fake a time difference from when the file was created until now it
216
        # is being renamed by using os.utime. Note that the change we actually
217
        # want to see is the real ctime change from 'os.rename()', but as long
218
        # as we observe a new stat value, we should be fine.
219
        os.utime(trans._limbo_name(trans_id), (creation_mtime, creation_mtime))
220
        trans.apply()
221
        new_st_val = osutils.lstat(self.wt.abspath('file1'))
222
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
223
        self.assertEqual(o_sha1, sha1)
224
        self.assertEqualStat(o_st_val, new_st_val)
225
        self.assertNotEqual(st_val.st_mtime, new_st_val.st_mtime)
226
227
    def test_new_file_caches_sha1(self):
228
        trans, root, contents, sha1 = self.transform_for_sha1_test()
229
        trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
230
                                  sha1=sha1)
231
        st_val = osutils.lstat(trans._limbo_name(trans_id))
232
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
233
        self.assertEqual(o_sha1, sha1)
234
        self.assertEqualStat(o_st_val, st_val)
235
236
    def test_cancel_creation_removes_observed_sha1(self):
237
        trans, root, contents, sha1 = self.transform_for_sha1_test()
238
        trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
239
                                  sha1=sha1)
240
        self.assertTrue(trans_id in trans._observed_sha1s)
241
        trans.cancel_creation(trans_id)
242
        self.assertFalse(trans_id in trans._observed_sha1s)
243
244
    def test_create_files_same_timestamp(self):
245
        transform, root = self.transform()
246
        self.wt.lock_tree_write()
247
        self.addCleanup(self.wt.unlock)
248
        # Roll back the clock, so that we know everything is being set to the
249
        # exact time
250
        transform._creation_mtime = creation_mtime = time.time() - 20.0
251
        transform.create_file([b'content-one'],
252
                              transform.create_path('one', root))
253
        time.sleep(1)  # *ugly*
254
        transform.create_file([b'content-two'],
255
                              transform.create_path('two', root))
256
        transform.apply()
257
        fo, st1 = self.wt.get_file_with_stat('one', filtered=False)
258
        fo.close()
259
        fo, st2 = self.wt.get_file_with_stat('two', filtered=False)
260
        fo.close()
261
        # We only guarantee 2s resolution
262
        self.assertTrue(
263
            abs(creation_mtime - st1.st_mtime) < 2.0,
264
            "%s != %s within 2 seconds" % (creation_mtime, st1.st_mtime))
265
        # But if we have more than that, all files should get the same result
266
        self.assertEqual(st1.st_mtime, st2.st_mtime)
267
268
    def test_change_root_id(self):
7490.84.1 by Jelmer Vernooij
Split out git and bzr-specific transform.
269
        if not self.workingtree_format.supports_setting_file_ids:
270
            raise tests.TestNotApplicable(
271
                'format does not support setting file ids')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
272
        transform, root = self.transform()
273
        self.assertNotEqual(b'new-root-id', self.wt.path2id(''))
274
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
275
        transform.delete_contents(root)
276
        transform.unversion_file(root)
277
        transform.fixup_new_roots()
278
        transform.apply()
279
        self.assertEqual(b'new-root-id', self.wt.path2id(''))
280
7490.84.1 by Jelmer Vernooij
Split out git and bzr-specific transform.
281
    def test_replace_root(self):
282
        transform, root = self.transform()
283
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
284
        transform.delete_contents(root)
285
        transform.unversion_file(root)
286
        transform.fixup_new_roots()
287
        transform.apply()
288
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
289
    def test_change_root_id_add_files(self):
7490.84.1 by Jelmer Vernooij
Split out git and bzr-specific transform.
290
        if not self.workingtree_format.supports_setting_file_ids:
291
            raise tests.TestNotApplicable(
292
                'format does not support setting file ids')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
293
        transform, root = self.transform()
294
        self.assertNotEqual(b'new-root-id', self.wt.path2id(''))
295
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
296
        transform.new_file('file', new_trans_id, [b'new-contents\n'],
297
                           b'new-file-id')
298
        transform.delete_contents(root)
299
        transform.unversion_file(root)
300
        transform.fixup_new_roots()
301
        transform.apply()
302
        self.assertEqual(b'new-root-id', self.wt.path2id(''))
303
        self.assertEqual(b'new-file-id', self.wt.path2id('file'))
304
        self.assertFileEqual(b'new-contents\n', self.wt.abspath('file'))
305
306
    def test_add_two_roots(self):
307
        transform, root = self.transform()
308
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
309
        transform.new_directory('', ROOT_PARENT, b'alt-root-id')
310
        self.assertRaises(ValueError, transform.fixup_new_roots)
311
312
    def test_retain_existing_root(self):
313
        tt, root = self.transform()
314
        with tt:
315
            tt.new_directory('', ROOT_PARENT, b'new-root-id')
316
            tt.fixup_new_roots()
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
317
            if self.wt.has_versioned_directories():
318
                self.assertTrue(tt.final_is_versioned(tt.root))
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
319
            if self.wt.supports_setting_file_ids():
320
                self.assertNotEqual(b'new-root-id', tt.final_file_id(tt.root))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
321
322
    def test_retain_existing_root_added_file(self):
323
        tt, root = self.transform()
324
        new_trans_id = tt.new_directory('', ROOT_PARENT, b'new-root-id')
325
        child = tt.new_directory('child', new_trans_id, b'child-id')
326
        tt.fixup_new_roots()
327
        self.assertEqual(tt.root, tt.final_parent(child))
328
329
    def test_add_unversioned_root(self):
330
        transform, root = self.transform()
331
        transform.new_directory('', ROOT_PARENT, None)
332
        transform.delete_contents(transform.root)
333
        transform.fixup_new_roots()
7490.133.4 by Jelmer Vernooij
q
334
        self.assertNotIn(transform.root, getattr(transform, '_new_id', []))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
335
336
    def test_remove_root_fixup(self):
337
        transform, root = self.transform()
338
        old_root_id = self.wt.path2id('')
339
        self.assertNotEqual(b'new-root-id', old_root_id)
340
        transform.delete_contents(root)
341
        transform.unversion_file(root)
342
        transform.fixup_new_roots()
343
        transform.apply()
344
        self.assertEqual(old_root_id, self.wt.path2id(''))
345
346
        transform, root = self.transform()
347
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
348
        transform.new_directory('', ROOT_PARENT, b'alt-root-id')
349
        self.assertRaises(ValueError, transform.fixup_new_roots)
350
351
    def test_fixup_new_roots_permits_empty_tree(self):
352
        transform, root = self.transform()
353
        transform.delete_contents(root)
354
        transform.unversion_file(root)
355
        transform.fixup_new_roots()
356
        self.assertIs(None, transform.final_kind(root))
7490.133.4 by Jelmer Vernooij
q
357
        if self.wt.supports_setting_file_ids():
358
            self.assertIs(None, transform.final_file_id(root))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
359
360
    def test_apply_retains_root_directory(self):
361
        # Do not attempt to delete the physical root directory, because that
362
        # is impossible.
363
        transform, root = self.transform()
364
        with transform:
365
            transform.delete_contents(root)
366
            e = self.assertRaises(AssertionError, self.assertRaises,
7490.77.11 by Jelmer Vernooij
Merge lp:brz/3.1.
367
                                  TransformRenameFailed,
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
368
                                  transform.apply)
369
        self.assertContainsRe('TransformRenameFailed not raised', str(e))
370
371
    def test_apply_retains_file_id(self):
372
        transform, root = self.transform()
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
373
        if not self.wt.supports_setting_file_ids():
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
374
            self.skipTest('format does not support file ids')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
375
        old_root_id = transform.tree_file_id(root)
376
        transform.unversion_file(root)
377
        transform.apply()
378
        self.assertEqual(old_root_id, self.wt.path2id(''))
379
380
    def test_hardlink(self):
381
        self.requireFeature(HardlinkFeature)
382
        transform, root = self.transform()
383
        transform.new_file('file1', root, [b'contents'])
384
        transform.apply()
385
        target = self.make_branch_and_tree('target')
386
        target_transform = target.transform()
387
        trans_id = target_transform.create_path('file1', target_transform.root)
388
        target_transform.create_hardlink(self.wt.abspath('file1'), trans_id)
389
        target_transform.apply()
390
        self.assertPathExists('target/file1')
391
        source_stat = os.stat(self.wt.abspath('file1'))
392
        target_stat = os.stat('target/file1')
393
        self.assertEqual(source_stat, target_stat)
394
395
    def test_convenience(self):
396
        transform, root = self.transform()
397
        self.wt.lock_tree_write()
398
        self.addCleanup(self.wt.unlock)
399
        transform.new_file('name', root, [b'contents'], b'my_pretties', True)
400
        oz = transform.new_directory('oz', root, b'oz-id')
401
        dorothy = transform.new_directory('dorothy', oz, b'dorothy-id')
402
        transform.new_file('toto', dorothy, [b'toto-contents'], b'toto-id',
403
                           False)
404
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
405
        self.assertEqual(len(transform.find_raw_conflicts()), 0)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
406
        transform.apply()
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
407
        self.assertRaises(ReusingTransform, transform.find_raw_conflicts)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
408
        with open(self.wt.abspath('name'), 'r') as f:
409
            self.assertEqual('contents', f.read())
410
        self.assertIs(self.wt.is_executable('name'), True)
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
411
        self.assertTrue(self.wt.is_versioned('name'))
412
        self.assertTrue(self.wt.is_versioned('oz'))
413
        self.assertTrue(self.wt.is_versioned('oz/dorothy'))
414
        self.assertTrue(self.wt.is_versioned('oz/dorothy/toto'))
415
        if self.wt.supports_setting_file_ids():
416
            self.assertEqual(self.wt.path2id('name'), b'my_pretties')
417
            self.assertEqual(self.wt.path2id('oz'), b'oz-id')
418
            self.assertEqual(self.wt.path2id('oz/dorothy'), b'dorothy-id')
419
            self.assertEqual(self.wt.path2id('oz/dorothy/toto'), b'toto-id')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
420
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
421
        with self.wt.get_file('oz/dorothy/toto') as f:
422
            self.assertEqual(b'toto-contents', f.read())
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
423
        self.assertIs(self.wt.is_executable('oz/dorothy/toto'), False)
424
425
    def test_tree_reference(self):
426
        transform, root = self.transform()
427
        tree = transform._tree
7490.83.9 by Jelmer Vernooij
Split out per-tree transform preview tests.
428
        if not tree.supports_tree_reference():
429
            raise tests.TestNotApplicable(
430
                'Tree format does not support references')
7490.133.25 by Jelmer Vernooij
More fixes.
431
        nested_tree = self.make_branch_and_tree('nested')
432
        nested_revid = nested_tree.commit('commit')
7490.83.9 by Jelmer Vernooij
Split out per-tree transform preview tests.
433
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
434
        trans_id = transform.new_directory('reference', root, b'subtree-id')
7490.133.25 by Jelmer Vernooij
More fixes.
435
        transform.set_tree_reference(nested_revid, trans_id)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
436
        transform.apply()
437
        tree.lock_read()
438
        self.addCleanup(tree.unlock)
439
        self.assertEqual(
7490.133.25 by Jelmer Vernooij
More fixes.
440
            nested_revid,
7490.132.1 by Jelmer Vernooij
Fix support for tree revisions in Transform.
441
            tree.get_reference_revision('reference'))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
442
443
    def test_conflicts(self):
444
        transform, root = self.transform()
445
        trans_id = transform.new_file('name', root, [b'contents'],
446
                                      b'my_pretties')
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
447
        self.assertEqual(len(transform.find_raw_conflicts()), 0)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
448
        trans_id2 = transform.new_file('name', root, [b'Crontents'], b'toto')
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
449
        self.assertEqual(transform.find_raw_conflicts(),
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
450
                         [('duplicate', trans_id, trans_id2, 'name')])
451
        self.assertRaises(MalformedTransform, transform.apply)
452
        transform.adjust_path('name', trans_id, trans_id2)
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
453
        self.assertEqual(transform.find_raw_conflicts(),
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
454
                         [('non-directory parent', trans_id)])
455
        tinman_id = transform.trans_id_tree_path('tinman')
456
        transform.adjust_path('name', tinman_id, trans_id2)
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
457
        if self.wt.has_versioned_directories():
7490.133.15 by Jelmer Vernooij
Merge conflict-refactor.
458
            self.assertEqual(transform.find_raw_conflicts(),
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
459
                             [('unversioned parent', tinman_id),
460
                              ('missing parent', tinman_id)])
461
        else:
7490.133.15 by Jelmer Vernooij
Merge conflict-refactor.
462
            self.assertEqual(transform.find_raw_conflicts(),
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
463
                             [('missing parent', tinman_id)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
464
        lion_id = transform.create_path('lion', root)
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
465
        if self.wt.has_versioned_directories():
7490.133.15 by Jelmer Vernooij
Merge conflict-refactor.
466
            self.assertEqual(transform.find_raw_conflicts(),
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
467
                             [('unversioned parent', tinman_id),
468
                              ('missing parent', tinman_id)])
469
        else:
7490.133.15 by Jelmer Vernooij
Merge conflict-refactor.
470
            self.assertEqual(transform.find_raw_conflicts(),
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
471
                             [('missing parent', tinman_id)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
472
        transform.adjust_path('name', lion_id, trans_id2)
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
473
        if self.wt.has_versioned_directories():
7490.133.15 by Jelmer Vernooij
Merge conflict-refactor.
474
            self.assertEqual(transform.find_raw_conflicts(),
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
475
                             [('unversioned parent', lion_id),
476
                              ('missing parent', lion_id)])
477
        else:
7490.133.15 by Jelmer Vernooij
Merge conflict-refactor.
478
            self.assertEqual(transform.find_raw_conflicts(),
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
479
                             [('missing parent', lion_id)])
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
480
        transform.version_file(lion_id, file_id=b"Courage")
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
481
        self.assertEqual(transform.find_raw_conflicts(),
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
482
                         [('missing parent', lion_id),
483
                          ('versioning no contents', lion_id)])
484
        transform.adjust_path('name2', root, trans_id2)
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
485
        self.assertEqual(transform.find_raw_conflicts(),
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
486
                         [('versioning no contents', lion_id)])
487
        transform.create_file([b'Contents, okay?'], lion_id)
488
        transform.adjust_path('name2', trans_id2, trans_id2)
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
489
        self.assertEqual(transform.find_raw_conflicts(),
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
490
                         [('parent loop', trans_id2),
491
                          ('non-directory parent', trans_id2)])
492
        transform.adjust_path('name2', root, trans_id2)
493
        oz_id = transform.new_directory('oz', root)
494
        transform.set_executability(True, oz_id)
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
495
        self.assertEqual(transform.find_raw_conflicts(),
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
496
                         [('unversioned executability', oz_id)])
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
497
        transform.version_file(oz_id, file_id=b'oz-id')
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
498
        self.assertEqual(transform.find_raw_conflicts(),
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
499
                         [('non-file executability', oz_id)])
500
        transform.set_executability(None, oz_id)
501
        tip_id = transform.new_file('tip', oz_id, [b'ozma'], b'tip-id')
502
        transform.apply()
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
503
        if self.wt.supports_setting_file_ids():
504
            self.assertEqual(self.wt.path2id('name'), b'my_pretties')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
505
        with open(self.wt.abspath('name'), 'rb') as f:
506
            self.assertEqual(b'contents', f.read())
507
        transform2, root = self.transform()
508
        oz_id = transform2.trans_id_tree_path('oz')
509
        newtip = transform2.new_file('tip', oz_id, [b'other'], b'tip-id')
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
510
        result = transform2.find_raw_conflicts()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
511
        fp = FinalPaths(transform2)
512
        self.assertTrue('oz/tip' in transform2._tree_path_ids)
513
        self.assertEqual(fp.get_path(newtip), pathjoin('oz', 'tip'))
7490.133.25 by Jelmer Vernooij
More fixes.
514
        if self.wt.supports_setting_file_ids():
515
            self.assertEqual(len(result), 2)
516
            self.assertEqual((result[1][0], result[1][2]),
517
                             ('duplicate id', newtip))
518
        else:
519
            self.assertEqual(len(result), 1)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
520
        self.assertEqual((result[0][0], result[0][1]),
521
                         ('duplicate', newtip))
522
        transform2.finalize()
523
        transform3 = self.wt.transform()
524
        self.addCleanup(transform3.finalize)
525
        oz_id = transform3.trans_id_tree_path('oz')
526
        transform3.delete_contents(oz_id)
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
527
        self.assertEqual(transform3.find_raw_conflicts(),
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
528
                         [('missing parent', oz_id)])
529
        root_id = transform3.root
530
        tip_id = transform3.trans_id_tree_path('oz/tip')
531
        transform3.adjust_path('tip', root_id, tip_id)
532
        transform3.apply()
533
534
    def test_conflict_on_case_insensitive(self):
535
        tree = self.make_branch_and_tree('tree')
536
        # Don't try this at home, kids!
537
        # Force the tree to report that it is case sensitive, for conflict
538
        # resolution tests
539
        tree.case_sensitive = True
540
        transform = tree.transform()
541
        self.addCleanup(transform.finalize)
542
        transform.new_file('file', transform.root, [b'content'])
543
        transform.new_file('FiLe', transform.root, [b'content'])
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
544
        result = transform.find_raw_conflicts()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
545
        self.assertEqual([], result)
546
        transform.finalize()
547
        # Force the tree to report that it is case insensitive, for conflict
548
        # generation tests
549
        tree.case_sensitive = False
550
        transform = tree.transform()
551
        self.addCleanup(transform.finalize)
552
        transform.new_file('file', transform.root, [b'content'])
553
        transform.new_file('FiLe', transform.root, [b'content'])
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
554
        result = transform.find_raw_conflicts()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
555
        self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
556
557
    def test_conflict_on_case_insensitive_existing(self):
558
        tree = self.make_branch_and_tree('tree')
559
        self.build_tree(['tree/FiLe'])
560
        # Don't try this at home, kids!
561
        # Force the tree to report that it is case sensitive, for conflict
562
        # resolution tests
563
        tree.case_sensitive = True
564
        transform = tree.transform()
565
        self.addCleanup(transform.finalize)
566
        transform.new_file('file', transform.root, [b'content'])
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
567
        result = transform.find_raw_conflicts()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
568
        self.assertEqual([], result)
569
        transform.finalize()
570
        # Force the tree to report that it is case insensitive, for conflict
571
        # generation tests
572
        tree.case_sensitive = False
573
        transform = tree.transform()
574
        self.addCleanup(transform.finalize)
575
        transform.new_file('file', transform.root, [b'content'])
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
576
        result = transform.find_raw_conflicts()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
577
        self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
578
579
    def test_resolve_case_insensitive_conflict(self):
580
        tree = self.make_branch_and_tree('tree')
581
        # Don't try this at home, kids!
582
        # Force the tree to report that it is case insensitive, for conflict
583
        # resolution tests
584
        tree.case_sensitive = False
585
        transform = tree.transform()
586
        self.addCleanup(transform.finalize)
587
        transform.new_file('file', transform.root, [b'content'])
588
        transform.new_file('FiLe', transform.root, [b'content'])
589
        resolve_conflicts(transform)
590
        transform.apply()
591
        self.assertPathExists('tree/file')
592
        self.assertPathExists('tree/FiLe.moved')
593
594
    def test_resolve_checkout_case_conflict(self):
595
        tree = self.make_branch_and_tree('tree')
596
        # Don't try this at home, kids!
597
        # Force the tree to report that it is case insensitive, for conflict
598
        # resolution tests
599
        tree.case_sensitive = False
600
        transform = tree.transform()
601
        self.addCleanup(transform.finalize)
602
        transform.new_file('file', transform.root, [b'content'])
603
        transform.new_file('FiLe', transform.root, [b'content'])
604
        resolve_conflicts(transform,
605
                          pass_func=lambda t, c: resolve_checkout(t, c, []))
606
        transform.apply()
607
        self.assertPathExists('tree/file')
608
        self.assertPathExists('tree/FiLe.moved')
609
610
    def test_apply_case_conflict(self):
611
        """Ensure that a transform with case conflicts can always be applied"""
612
        tree = self.make_branch_and_tree('tree')
613
        transform = tree.transform()
614
        self.addCleanup(transform.finalize)
615
        transform.new_file('file', transform.root, [b'content'])
616
        transform.new_file('FiLe', transform.root, [b'content'])
617
        dir = transform.new_directory('dir', transform.root)
618
        transform.new_file('dirfile', dir, [b'content'])
619
        transform.new_file('dirFiLe', dir, [b'content'])
620
        resolve_conflicts(transform)
621
        transform.apply()
622
        self.assertPathExists('tree/file')
623
        if not os.path.exists('tree/FiLe.moved'):
624
            self.assertPathExists('tree/FiLe')
625
        self.assertPathExists('tree/dir/dirfile')
626
        if not os.path.exists('tree/dir/dirFiLe.moved'):
627
            self.assertPathExists('tree/dir/dirFiLe')
628
629
    def test_case_insensitive_limbo(self):
630
        tree = self.make_branch_and_tree('tree')
631
        # Don't try this at home, kids!
632
        # Force the tree to report that it is case insensitive
633
        tree.case_sensitive = False
634
        transform = tree.transform()
635
        self.addCleanup(transform.finalize)
636
        dir = transform.new_directory('dir', transform.root)
637
        first = transform.new_file('file', dir, [b'content'])
638
        second = transform.new_file('FiLe', dir, [b'content'])
639
        self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
640
        self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
641
642
    def test_adjust_path_updates_child_limbo_names(self):
643
        tree = self.make_branch_and_tree('tree')
644
        transform = tree.transform()
645
        self.addCleanup(transform.finalize)
646
        foo_id = transform.new_directory('foo', transform.root)
647
        bar_id = transform.new_directory('bar', foo_id)
648
        baz_id = transform.new_directory('baz', bar_id)
649
        qux_id = transform.new_directory('qux', baz_id)
650
        transform.adjust_path('quxx', foo_id, bar_id)
651
        self.assertStartsWith(transform._limbo_name(qux_id),
652
                              transform._limbo_name(bar_id))
653
654
    def test_add_del(self):
655
        start, root = self.transform()
656
        start.new_directory('a', root, b'a')
657
        start.apply()
658
        transform, root = self.transform()
659
        transform.delete_versioned(transform.trans_id_tree_path('a'))
660
        transform.new_directory('a', root, b'a')
661
        transform.apply()
662
663
    def test_unversioning(self):
664
        create_tree, root = self.transform()
665
        parent_id = create_tree.new_directory('parent', root, b'parent-id')
666
        create_tree.new_file('child', parent_id, [b'child'], b'child-id')
667
        create_tree.apply()
668
        unversion = self.wt.transform()
669
        self.addCleanup(unversion.finalize)
670
        parent = unversion.trans_id_tree_path('parent')
671
        unversion.unversion_file(parent)
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
672
        if self.wt.has_versioned_directories():
7490.133.15 by Jelmer Vernooij
Merge conflict-refactor.
673
            self.assertEqual(unversion.find_raw_conflicts(),
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
674
                             [('unversioned parent', parent_id)])
675
        else:
7490.133.15 by Jelmer Vernooij
Merge conflict-refactor.
676
            self.assertEqual(unversion.find_raw_conflicts(), [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
677
        file_id = unversion.trans_id_tree_path('parent/child')
678
        unversion.unversion_file(file_id)
679
        unversion.apply()
680
681
    def test_name_invariants(self):
682
        create_tree, root = self.transform()
683
        # prepare tree
684
        root = create_tree.root
685
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
686
        create_tree.new_file('name2', root, [b'hello2'], b'name2')
687
        ddir = create_tree.new_directory('dying_directory', root, b'ddir')
688
        create_tree.new_file('dying_file', ddir, [b'goodbye1'], b'dfile')
689
        create_tree.new_file('moving_file', ddir, [b'later1'], b'mfile')
690
        create_tree.new_file('moving_file2', root, [b'later2'], b'mfile2')
691
        create_tree.apply()
692
693
        mangle_tree, root = self.transform()
694
        root = mangle_tree.root
695
        # swap names
696
        name1 = mangle_tree.trans_id_tree_path('name1')
697
        name2 = mangle_tree.trans_id_tree_path('name2')
698
        mangle_tree.adjust_path('name2', root, name1)
699
        mangle_tree.adjust_path('name1', root, name2)
700
701
        # tests for deleting parent directories
702
        ddir = mangle_tree.trans_id_tree_path('dying_directory')
703
        mangle_tree.delete_contents(ddir)
704
        dfile = mangle_tree.trans_id_tree_path('dying_directory/dying_file')
705
        mangle_tree.delete_versioned(dfile)
706
        mangle_tree.unversion_file(dfile)
707
        mfile = mangle_tree.trans_id_tree_path('dying_directory/moving_file')
708
        mangle_tree.adjust_path('mfile', root, mfile)
709
710
        # tests for adding parent directories
711
        newdir = mangle_tree.new_directory('new_directory', root, b'newdir')
712
        mfile2 = mangle_tree.trans_id_tree_path('moving_file2')
713
        mangle_tree.adjust_path('mfile2', newdir, mfile2)
714
        mangle_tree.new_file('newfile', newdir, [b'hello3'], b'dfile')
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
715
        if self.wt.supports_setting_file_ids():
716
            self.assertEqual(mangle_tree.final_file_id(mfile2), b'mfile2')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
717
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
718
        mangle_tree.apply()
719
        with open(self.wt.abspath('name1'), 'r') as f:
720
            self.assertEqual(f.read(), 'hello2')
721
        with open(self.wt.abspath('name2'), 'r') as f:
722
            self.assertEqual(f.read(), 'hello1')
723
        mfile2_path = self.wt.abspath(pathjoin('new_directory', 'mfile2'))
724
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
725
        with open(mfile2_path, 'r') as f:
726
            self.assertEqual(f.read(), 'later2')
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
727
        if self.wt.supports_setting_file_ids():
728
            self.assertEqual(self.wt.id2path(b'mfile2'), 'new_directory/mfile2')
729
            self.assertEqual(self.wt.path2id('new_directory/mfile2'), b'mfile2')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
730
        newfile_path = self.wt.abspath(pathjoin('new_directory', 'newfile'))
731
        with open(newfile_path, 'r') as f:
732
            self.assertEqual(f.read(), 'hello3')
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
733
        if self.wt.supports_setting_file_ids():
734
            self.assertEqual(self.wt.path2id('dying_directory'), b'ddir')
735
            self.assertIs(self.wt.path2id('dying_directory/dying_file'), None)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
736
        mfile2_path = self.wt.abspath(pathjoin('new_directory', 'mfile2'))
737
738
    def test_both_rename(self):
739
        create_tree, root = self.transform()
740
        newdir = create_tree.new_directory('selftest', root, b'selftest-id')
741
        create_tree.new_file('blackbox.py', newdir, [
742
                             b'hello1'], b'blackbox-id')
743
        create_tree.apply()
744
        mangle_tree, root = self.transform()
745
        selftest = mangle_tree.trans_id_tree_path('selftest')
746
        blackbox = mangle_tree.trans_id_tree_path('selftest/blackbox.py')
747
        mangle_tree.adjust_path('test', root, selftest)
748
        mangle_tree.adjust_path('test_too_much', root, selftest)
749
        mangle_tree.set_executability(True, blackbox)
750
        mangle_tree.apply()
751
752
    def test_both_rename2(self):
753
        create_tree, root = self.transform()
754
        breezy = create_tree.new_directory('breezy', root, b'breezy-id')
755
        tests = create_tree.new_directory('tests', breezy, b'tests-id')
756
        blackbox = create_tree.new_directory('blackbox', tests, b'blackbox-id')
757
        create_tree.new_file('test_too_much.py', blackbox, [b'hello1'],
758
                             b'test_too_much-id')
759
        create_tree.apply()
760
        mangle_tree, root = self.transform()
761
        breezy = mangle_tree.trans_id_tree_path('breezy')
762
        tests = mangle_tree.trans_id_tree_path('breezy/tests')
763
        test_too_much = mangle_tree.trans_id_tree_path(
764
            'breezy/tests/blackbox/test_too_much.py')
765
        mangle_tree.adjust_path('selftest', breezy, tests)
766
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
767
        mangle_tree.set_executability(True, test_too_much)
768
        mangle_tree.apply()
769
770
    def test_both_rename3(self):
771
        create_tree, root = self.transform()
772
        tests = create_tree.new_directory('tests', root, b'tests-id')
773
        create_tree.new_file('test_too_much.py', tests, [b'hello1'],
774
                             b'test_too_much-id')
775
        create_tree.apply()
776
        mangle_tree, root = self.transform()
777
        tests = mangle_tree.trans_id_tree_path('tests')
778
        test_too_much = mangle_tree.trans_id_tree_path(
779
            'tests/test_too_much.py')
780
        mangle_tree.adjust_path('selftest', root, tests)
781
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
782
        mangle_tree.set_executability(True, test_too_much)
783
        mangle_tree.apply()
784
785
    def test_move_dangling_ie(self):
786
        create_tree, root = self.transform()
787
        # prepare tree
788
        root = create_tree.root
789
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
790
        create_tree.apply()
791
        delete_contents, root = self.transform()
792
        file = delete_contents.trans_id_tree_path('name1')
793
        delete_contents.delete_contents(file)
794
        delete_contents.apply()
795
        move_id, root = self.transform()
796
        name1 = move_id.trans_id_tree_path('name1')
797
        newdir = move_id.new_directory('dir', root, b'newdir')
798
        move_id.adjust_path('name2', newdir, name1)
799
        move_id.apply()
800
801
    def test_replace_dangling_ie(self):
802
        create_tree, root = self.transform()
803
        # prepare tree
804
        root = create_tree.root
805
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
806
        create_tree.apply()
807
        delete_contents = self.wt.transform()
808
        self.addCleanup(delete_contents.finalize)
809
        file = delete_contents.trans_id_tree_path('name1')
810
        delete_contents.delete_contents(file)
811
        delete_contents.apply()
812
        delete_contents.finalize()
813
        replace = self.wt.transform()
814
        self.addCleanup(replace.finalize)
815
        name2 = replace.new_file('name2', root, [b'hello2'], b'name1')
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
816
        conflicts = replace.find_raw_conflicts()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
817
        name1 = replace.trans_id_tree_path('name1')
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
818
        if self.wt.supports_setting_file_ids():
819
            self.assertEqual(conflicts, [('duplicate id', name1, name2)])
820
        else:
821
            self.assertEqual(conflicts, [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
822
        resolve_conflicts(replace)
823
        replace.apply()
824
825
    def _test_symlinks(self, link_name1, link_target1,
826
                       link_name2, link_target2):
827
828
        def ozpath(p):
829
            return 'oz/' + p
830
831
        self.requireFeature(SymlinkFeature)
832
        transform, root = self.transform()
833
        oz_id = transform.new_directory('oz', root, b'oz-id')
834
        transform.new_symlink(link_name1, oz_id, link_target1, b'wizard-id')
835
        wiz_id = transform.create_path(link_name2, oz_id)
836
        transform.create_symlink(link_target2, wiz_id)
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
837
        transform.version_file(wiz_id, file_id=b'wiz-id2')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
838
        transform.set_executability(True, wiz_id)
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
839
        self.assertEqual(transform.find_raw_conflicts(),
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
840
                         [('non-file executability', wiz_id)])
841
        transform.set_executability(None, wiz_id)
842
        transform.apply()
7490.133.4 by Jelmer Vernooij
q
843
        if self.wt.supports_setting_file_ids():
844
            self.assertEqual(self.wt.path2id(ozpath(link_name1)), b'wizard-id')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
845
        self.assertEqual('symlink',
846
                         file_kind(self.wt.abspath(ozpath(link_name1))))
847
        self.assertEqual(link_target2,
848
                         osutils.readlink(self.wt.abspath(ozpath(link_name2))))
849
        self.assertEqual(link_target1,
850
                         osutils.readlink(self.wt.abspath(ozpath(link_name1))))
851
852
    def test_symlinks(self):
853
        self._test_symlinks('wizard', 'wizard-target',
854
                            'wizard2', 'behind_curtain')
855
856
    def test_symlinks_unicode(self):
857
        self.requireFeature(features.UnicodeFilenameFeature)
858
        self._test_symlinks(u'\N{Euro Sign}wizard',
859
                            u'wizard-targ\N{Euro Sign}t',
860
                            u'\N{Euro Sign}wizard2',
861
                            u'b\N{Euro Sign}hind_curtain')
862
863
    def test_unsupported_symlink_no_conflict(self):
864
        def tt_helper():
865
            wt = self.make_branch_and_tree('.')
866
            tt = wt.transform()
867
            self.addCleanup(tt.finalize)
868
            tt.new_symlink('foo', tt.root, 'bar')
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
869
            result = tt.find_raw_conflicts()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
870
            self.assertEqual([], result)
871
        os_symlink = getattr(os, 'symlink', None)
872
        os.symlink = None
873
        try:
874
            tt_helper()
875
        finally:
876
            if os_symlink:
877
                os.symlink = os_symlink
878
879
    def get_conflicted(self):
880
        create, root = self.transform()
881
        create.new_file('dorothy', root, [b'dorothy'], b'dorothy-id')
882
        oz = create.new_directory('oz', root, b'oz-id')
883
        create.new_directory('emeraldcity', oz, b'emerald-id')
884
        create.apply()
885
        conflicts, root = self.transform()
886
        # set up duplicate entry, duplicate id
887
        new_dorothy = conflicts.new_file('dorothy', root, [b'dorothy'],
888
                                         b'dorothy-id')
889
        old_dorothy = conflicts.trans_id_tree_path('dorothy')
890
        oz = conflicts.trans_id_tree_path('oz')
891
        # set up DeletedParent parent conflict
892
        conflicts.delete_versioned(oz)
893
        emerald = conflicts.trans_id_tree_path('oz/emeraldcity')
894
        # set up MissingParent conflict
7490.133.25 by Jelmer Vernooij
More fixes.
895
        if conflicts._tree.supports_setting_file_ids():
896
            munchkincity = conflicts.trans_id_file_id(b'munchkincity-id')
897
        else:
898
            munchkincity = conflicts.assign_id()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
899
        conflicts.adjust_path('munchkincity', root, munchkincity)
900
        conflicts.new_directory('auntem', munchkincity, b'auntem-id')
901
        # set up parent loop
902
        conflicts.adjust_path('emeraldcity', emerald, emerald)
7490.133.25 by Jelmer Vernooij
More fixes.
903
        return conflicts, emerald, oz, old_dorothy, new_dorothy, munchkincity
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
904
905
    def test_conflict_resolution(self):
7490.133.25 by Jelmer Vernooij
More fixes.
906
        conflicts, emerald, oz, old_dorothy, new_dorothy, munchkincity =\
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
907
            self.get_conflicted()
908
        resolve_conflicts(conflicts)
909
        self.assertEqual(conflicts.final_name(old_dorothy), 'dorothy.moved')
7490.133.26 by Jelmer Vernooij
Some fixes.
910
        if self.wt.supports_setting_file_ids():
911
            self.assertIs(conflicts.final_file_id(old_dorothy), None)
912
            self.assertEqual(conflicts.final_file_id(new_dorothy), b'dorothy-id')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
913
        self.assertEqual(conflicts.final_name(new_dorothy), 'dorothy')
914
        self.assertEqual(conflicts.final_parent(emerald), oz)
915
        conflicts.apply()
916
917
    def test_cook_conflicts(self):
7490.133.25 by Jelmer Vernooij
More fixes.
918
        tt, emerald, oz, old_dorothy, new_dorothy, munchkincity = self.get_conflicted()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
919
        raw_conflicts = resolve_conflicts(tt)
7490.133.26 by Jelmer Vernooij
Some fixes.
920
        cooked_conflicts = list(tt.cook_conflicts(raw_conflicts))
921
        if self.wt.supports_setting_file_ids():
922
            duplicate = DuplicateEntry('Moved existing file to', 'dorothy.moved',
923
                                       'dorothy', None, b'dorothy-id')
924
            self.assertEqual(cooked_conflicts[0], duplicate)
925
            duplicate_id = DuplicateID('Unversioned existing file',
926
                                       'dorothy.moved', 'dorothy', None,
927
                                       b'dorothy-id')
928
            self.assertEqual(cooked_conflicts[1], duplicate_id)
929
            missing_parent = MissingParent('Created directory', 'munchkincity',
930
                                           b'munchkincity-id')
931
            deleted_parent = DeletingParent('Not deleting', 'oz', b'oz-id')
932
            self.assertEqual(cooked_conflicts[2], missing_parent)
933
            unversioned_parent = UnversionedParent('Versioned directory',
934
                                                   'munchkincity',
935
                                                   b'munchkincity-id')
936
            unversioned_parent2 = UnversionedParent('Versioned directory', 'oz',
937
                                                    b'oz-id')
938
            self.assertEqual(cooked_conflicts[3], unversioned_parent)
939
            parent_loop = ParentLoop(
940
                'Cancelled move', 'oz/emeraldcity',
941
                'oz/emeraldcity', b'emerald-id', b'emerald-id')
942
            self.assertEqual(cooked_conflicts[4], deleted_parent)
943
            self.assertEqual(cooked_conflicts[5], unversioned_parent2)
944
            self.assertEqual(cooked_conflicts[6], parent_loop)
945
            self.assertEqual(len(cooked_conflicts), 7)
946
        else:
947
            self.assertEqual(
948
                set([c.path for c in cooked_conflicts]),
949
                set(['oz/emeraldcity', 'oz', 'munchkincity', 'dorothy.moved']))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
950
        tt.finalize()
951
952
    def test_string_conflicts(self):
7490.133.25 by Jelmer Vernooij
More fixes.
953
        tt, emerald, oz, old_dorothy, new_dorothy, munchkincity = self.get_conflicted()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
954
        raw_conflicts = resolve_conflicts(tt)
7490.133.27 by Jelmer Vernooij
Fix some more tests.
955
        cooked_conflicts = list(tt.cook_conflicts(raw_conflicts))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
956
        tt.finalize()
7518.1.2 by Jelmer Vernooij
Fix imports of sixish.
957
        conflicts_s = [str(c) for c in cooked_conflicts]
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
958
        self.assertEqual(len(cooked_conflicts), len(conflicts_s))
7490.133.27 by Jelmer Vernooij
Fix some more tests.
959
        if self.wt.supports_setting_file_ids():
960
            self.assertEqual(conflicts_s[0], 'Conflict adding file dorothy.  '
961
                                             'Moved existing file to '
962
                                             'dorothy.moved.')
963
            self.assertEqual(conflicts_s[1], 'Conflict adding id to dorothy.  '
964
                                             'Unversioned existing file '
965
                                             'dorothy.moved.')
966
            self.assertEqual(conflicts_s[2], 'Conflict adding files to'
967
                                             ' munchkincity.  Created directory.')
968
            self.assertEqual(conflicts_s[3], 'Conflict because munchkincity is not'
969
                                             ' versioned, but has versioned'
970
                                             ' children.  Versioned directory.')
971
            self.assertEqualDiff(
972
                conflicts_s[4], "Conflict: can't delete oz because it"
973
                                " is not empty.  Not deleting.")
974
            self.assertEqual(conflicts_s[5], 'Conflict because oz is not'
975
                                             ' versioned, but has versioned'
976
                                             ' children.  Versioned directory.')
977
            self.assertEqual(conflicts_s[6], 'Conflict moving oz/emeraldcity into'
978
                                             ' oz/emeraldcity. Cancelled move.')
979
        else:
980
            self.assertEqual(
981
                {'Text conflict in dorothy.moved',
982
                 'Text conflict in munchkincity',
983
                 'Text conflict in oz',
984
                 'Text conflict in oz/emeraldcity'},
985
                set([c for c in conflicts_s]))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
986
987
    def prepare_wrong_parent_kind(self):
988
        tt, root = self.transform()
989
        tt.new_file('parent', root, [b'contents'], b'parent-id')
990
        tt.apply()
991
        tt, root = self.transform()
7490.133.4 by Jelmer Vernooij
q
992
        parent_id = tt.trans_id_tree_path('parent')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
993
        tt.new_file('child,', parent_id, [b'contents2'], b'file-id')
994
        return tt
995
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
996
    def test_find_raw_conflicts_wrong_parent_kind(self):
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
997
        tt = self.prepare_wrong_parent_kind()
7490.129.2 by Jelmer Vernooij
Move cook conflict implementation into breezy.bzr.transform.
998
        tt.find_raw_conflicts()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
999
1000
    def test_resolve_conflicts_wrong_existing_parent_kind(self):
1001
        tt = self.prepare_wrong_parent_kind()
1002
        raw_conflicts = resolve_conflicts(tt)
1003
        self.assertEqual({('non-directory parent', 'Created directory',
1004
                           'new-3')}, raw_conflicts)
7490.133.20 by Jelmer Vernooij
Some more test fixes.
1005
        cooked_conflicts = list(tt.cook_conflicts(raw_conflicts))
7490.133.25 by Jelmer Vernooij
More fixes.
1006
        from ...bzr.workingtree import InventoryWorkingTree
1007
        if isinstance(tt._tree, InventoryWorkingTree):
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
1008
            self.assertEqual([NonDirectoryParent('Created directory', 'parent.new',
1009
                                                 b'parent-id')], cooked_conflicts)
1010
        else:
7490.133.25 by Jelmer Vernooij
More fixes.
1011
            self.assertEqual(1, len(cooked_conflicts))
1012
            self.assertEqual('parent.new', cooked_conflicts[0].path)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1013
        tt.apply()
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
1014
        if self.wt.has_versioned_directories():
1015
            self.assertFalse(self.wt.is_versioned('parent'))
1016
        if self.wt.supports_setting_file_ids():
1017
            self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1018
1019
    def test_resolve_conflicts_wrong_new_parent_kind(self):
1020
        tt, root = self.transform()
1021
        parent_id = tt.new_directory('parent', root, b'parent-id')
1022
        tt.new_file('child,', parent_id, [b'contents2'], b'file-id')
1023
        tt.apply()
1024
        tt, root = self.transform()
7490.133.4 by Jelmer Vernooij
q
1025
        parent_id = tt.trans_id_tree_path('parent')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1026
        tt.delete_contents(parent_id)
1027
        tt.create_file([b'contents'], parent_id)
1028
        raw_conflicts = resolve_conflicts(tt)
1029
        self.assertEqual({('non-directory parent', 'Created directory',
1030
                           'new-3')}, raw_conflicts)
1031
        tt.apply()
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
1032
        if self.wt.has_versioned_directories():
1033
            self.assertFalse(self.wt.is_versioned('parent'))
1034
            self.assertTrue(self.wt.is_versioned('parent.new'))
7490.133.4 by Jelmer Vernooij
q
1035
        if self.wt.supports_setting_file_ids():
1036
            self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1037
1038
    def test_resolve_conflicts_wrong_parent_kind_unversioned(self):
1039
        tt, root = self.transform()
1040
        parent_id = tt.new_directory('parent', root)
1041
        tt.new_file('child,', parent_id, [b'contents2'])
1042
        tt.apply()
1043
        tt, root = self.transform()
1044
        parent_id = tt.trans_id_tree_path('parent')
1045
        tt.delete_contents(parent_id)
1046
        tt.create_file([b'contents'], parent_id)
1047
        resolve_conflicts(tt)
1048
        tt.apply()
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
1049
        if self.wt.has_versioned_directories():
1050
            self.assertFalse(self.wt.is_versioned('parent'))
1051
            self.assertFalse(self.wt.is_versioned('parent.new'))
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1052
1053
    def test_resolve_conflicts_missing_parent(self):
1054
        wt = self.make_branch_and_tree('.')
1055
        tt = wt.transform()
1056
        self.addCleanup(tt.finalize)
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
1057
        parent = tt.assign_id()
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1058
        tt.new_file('file', parent, [b'Contents'])
1059
        raw_conflicts = resolve_conflicts(tt)
1060
        # Since the directory doesn't exist it's seen as 'missing'.  So
1061
        # 'resolve_conflicts' create a conflict asking for it to be created.
1062
        self.assertLength(1, raw_conflicts)
1063
        self.assertEqual(('missing parent', 'Created directory', 'new-1'),
1064
                         raw_conflicts.pop())
1065
        # apply fail since the missing directory doesn't exist
1066
        self.assertRaises(NoFinalPath, tt.apply)
1067
1068
    def test_moving_versioned_directories(self):
1069
        create, root = self.transform()
1070
        kansas = create.new_directory('kansas', root, b'kansas-id')
1071
        create.new_directory('house', kansas, b'house-id')
1072
        create.new_directory('oz', root, b'oz-id')
1073
        create.apply()
1074
        cyclone, root = self.transform()
1075
        oz = cyclone.trans_id_tree_path('oz')
1076
        house = cyclone.trans_id_tree_path('house')
1077
        cyclone.adjust_path('house', oz, house)
1078
        cyclone.apply()
1079
1080
    def test_moving_root(self):
1081
        create, root = self.transform()
1082
        fun = create.new_directory('fun', root, b'fun-id')
1083
        create.new_directory('sun', root, b'sun-id')
1084
        create.new_directory('moon', root, b'moon')
1085
        create.apply()
1086
        transform, root = self.transform()
1087
        transform.adjust_root_path('oldroot', fun)
1088
        new_root = transform.trans_id_tree_path('')
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
1089
        transform.version_file(new_root, file_id=b'new-root')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1090
        transform.apply()
1091
1092
    def test_renames(self):
1093
        create, root = self.transform()
1094
        old = create.new_directory('old-parent', root, b'old-id')
1095
        intermediate = create.new_directory('intermediate', old, b'im-id')
1096
        myfile = create.new_file('myfile', intermediate, [b'myfile-text'],
1097
                                 b'myfile-id')
1098
        create.apply()
1099
        rename, root = self.transform()
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
1100
        old = rename.trans_id_tree_path('old-parent')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1101
        rename.adjust_path('new', root, old)
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
1102
        myfile = rename.trans_id_tree_path('old-parent/intermediate/myfile')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1103
        rename.set_executability(True, myfile)
1104
        rename.apply()
1105
1106
    def test_rename_fails(self):
1107
        self.requireFeature(features.not_running_as_root)
1108
        # see https://bugs.launchpad.net/bzr/+bug/491763
1109
        create, root_id = self.transform()
1110
        create.new_directory('first-dir', root_id, b'first-id')
1111
        create.new_file('myfile', root_id, [b'myfile-text'], b'myfile-id')
1112
        create.apply()
1113
        if os.name == "posix" and sys.platform != "cygwin":
1114
            # posix filesystems fail on renaming if the readonly bit is set
1115
            osutils.make_readonly(self.wt.abspath('first-dir'))
1116
        elif os.name == "nt":
1117
            # windows filesystems fail on renaming open files
1118
            self.addCleanup(open(self.wt.abspath('myfile')).close)
1119
        else:
1120
            self.skipTest("Can't force a permissions error on rename")
1121
        # now transform to rename
1122
        rename_transform, root_id = self.transform()
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
1123
        file_trans_id = rename_transform.trans_id_tree_path('myfile')
1124
        dir_id = rename_transform.trans_id_tree_path('first-dir')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1125
        rename_transform.adjust_path('newname', dir_id, file_trans_id)
7490.77.11 by Jelmer Vernooij
Merge lp:brz/3.1.
1126
        e = self.assertRaises(TransformRenameFailed,
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1127
                              rename_transform.apply)
1128
        # On nix looks like:
1129
        # "Failed to rename .../work/.bzr/checkout/limbo/new-1
1130
        # to .../first-dir/newname: [Errno 13] Permission denied"
1131
        # On windows looks like:
1132
        # "Failed to rename .../work/myfile to
1133
        # .../work/.bzr/checkout/limbo/new-1: [Errno 13] Permission denied"
1134
        # This test isn't concerned with exactly what the error looks like,
1135
        # and the strerror will vary across OS and locales, but the assert
1136
        # that the exeception attributes are what we expect
1137
        self.assertEqual(e.errno, errno.EACCES)
1138
        if os.name == "posix":
1139
            self.assertEndsWith(e.to_path, "/first-dir/newname")
1140
        else:
1141
            self.assertEqual(os.path.basename(e.from_path), "myfile")
1142
1143
    def test_set_executability_order(self):
1144
        """Ensure that executability behaves the same, no matter what order.
1145
1146
        - create file and set executability simultaneously
1147
        - create file and set executability afterward
1148
        - unsetting the executability of a file whose executability has not
1149
          been
1150
        declared should throw an exception (this may happen when a
1151
        merge attempts to create a file with a duplicate ID)
1152
        """
1153
        transform, root = self.transform()
1154
        wt = transform._tree
1155
        wt.lock_read()
1156
        self.addCleanup(wt.unlock)
1157
        transform.new_file('set_on_creation', root, [b'Set on creation'],
1158
                           b'soc', True)
1159
        sac = transform.new_file('set_after_creation', root,
1160
                                 [b'Set after creation'], b'sac')
1161
        transform.set_executability(True, sac)
1162
        uws = transform.new_file('unset_without_set', root, [b'Unset badly'],
1163
                                 b'uws')
1164
        self.assertRaises(KeyError, transform.set_executability, None, uws)
1165
        transform.apply()
1166
        self.assertTrue(wt.is_executable('set_on_creation'))
1167
        self.assertTrue(wt.is_executable('set_after_creation'))
1168
1169
    def test_preserve_mode(self):
1170
        """File mode is preserved when replacing content"""
1171
        if sys.platform == 'win32':
1172
            raise TestSkipped('chmod has no effect on win32')
1173
        transform, root = self.transform()
1174
        transform.new_file('file1', root, [b'contents'], b'file1-id', True)
1175
        transform.apply()
1176
        self.wt.lock_write()
1177
        self.addCleanup(self.wt.unlock)
1178
        self.assertTrue(self.wt.is_executable('file1'))
1179
        transform, root = self.transform()
1180
        file1_id = transform.trans_id_tree_path('file1')
1181
        transform.delete_contents(file1_id)
1182
        transform.create_file([b'contents2'], file1_id)
1183
        transform.apply()
1184
        self.assertTrue(self.wt.is_executable('file1'))
1185
1186
    def test__set_mode_stats_correctly(self):
1187
        """_set_mode stats to determine file mode."""
1188
        if sys.platform == 'win32':
1189
            raise TestSkipped('chmod has no effect on win32')
1190
1191
        stat_paths = []
1192
        real_stat = os.stat
1193
1194
        def instrumented_stat(path):
1195
            stat_paths.append(path)
1196
            return real_stat(path)
1197
1198
        transform, root = self.transform()
1199
1200
        bar1_id = transform.new_file('bar', root, [b'bar contents 1\n'],
1201
                                     file_id=b'bar-id-1', executable=False)
1202
        transform.apply()
1203
1204
        transform, root = self.transform()
1205
        bar1_id = transform.trans_id_tree_path('bar')
1206
        bar2_id = transform.trans_id_tree_path('bar2')
1207
        try:
1208
            os.stat = instrumented_stat
1209
            transform.create_file([b'bar2 contents\n'],
1210
                                  bar2_id, mode_id=bar1_id)
1211
        finally:
1212
            os.stat = real_stat
1213
            transform.finalize()
1214
1215
        bar1_abspath = self.wt.abspath('bar')
1216
        self.assertEqual([bar1_abspath], stat_paths)
1217
1218
    def test_iter_changes(self):
7490.85.3 by Jelmer Vernooij
Avoid setting root.
1219
        root_id = self.wt.path2id('')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1220
        transform, root = self.transform()
1221
        transform.new_file('old', root, [b'blah'], b'id-1', True)
1222
        transform.apply()
1223
        transform, root = self.transform()
1224
        try:
7490.133.25 by Jelmer Vernooij
More fixes.
1225
            self.assertTreeChanges(transform, [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1226
            old = transform.trans_id_tree_path('old')
1227
            transform.unversion_file(old)
7490.133.25 by Jelmer Vernooij
More fixes.
1228
            self.assertTreeChanges(
1229
                transform, [
1230
                    InventoryTreeChange(
1231
                        b'id-1', ('old', None), False, (True, False),
1232
                        (root_id, root_id), ('old', 'old'), ('file', 'file'),
1233
                        (True, True), False)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1234
            transform.new_directory('new', root, b'id-1')
7490.133.30 by Jelmer Vernooij
Fix the remaining test.
1235
            if transform._tree.supports_setting_file_ids():
1236
                self.assertTreeChanges(
1237
                    transform,
1238
                    [InventoryTreeChange(
1239
                        b'id-1', ('old', 'new'), True, (True, True),
1240
                        (root_id, root_id), ('old', 'new'),
1241
                        ('file', 'directory'),
1242
                        (True, False), False)])
1243
            else:
1244
                self.assertTreeChanges(
1245
                    transform,
1246
                    [TreeChange(
1247
                        (None, 'new'), False, (False, True),
1248
                        (None, 'new'), (None, 'directory'),
1249
                        (False, False), False),
1250
                     TreeChange(
1251
                        ('old', None), False, (True, False),
1252
                        ('old', 'old'), ('file', 'file'),
1253
                        (True, True), False)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1254
        finally:
1255
            transform.finalize()
1256
1257
    def test_iter_changes_new(self):
7490.85.3 by Jelmer Vernooij
Avoid setting root.
1258
        root_id = self.wt.path2id('')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1259
        transform, root = self.transform()
1260
        transform.new_file('old', root, [b'blah'])
1261
        transform.apply()
1262
        transform, root = self.transform()
1263
        try:
1264
            old = transform.trans_id_tree_path('old')
7490.83.5 by Jelmer Vernooij
Fix import tariff test.
1265
            transform.version_file(old, file_id=b'id-1')
7490.133.4 by Jelmer Vernooij
q
1266
            changes = list(transform.iter_changes())
1267
            self.assertEqual(1, len(changes))
1268
            self.assertEqual((None, 'old'), changes[0].path)
1269
            self.assertEqual(False, changes[0].changed_content)
1270
            self.assertEqual((False, True), changes[0].versioned)
1271
            self.assertEqual((False, False), changes[0].executable)
1272
            if self.wt.supports_setting_file_ids():
1273
                self.assertEqual((root_id, root_id), changes[0].parent_id)
1274
                self.assertEqual(b'id-1', changes[0].file_id)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1275
        finally:
1276
            transform.finalize()
1277
1278
    def test_iter_changes_modifications(self):
7490.85.3 by Jelmer Vernooij
Avoid setting root.
1279
        root_id = self.wt.path2id('')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1280
        transform, root = self.transform()
1281
        transform.new_file('old', root, [b'blah'], b'id-1')
1282
        transform.new_file('new', root, [b'blah'])
1283
        transform.new_directory('subdir', root, b'subdir-id')
1284
        transform.apply()
1285
        transform, root = self.transform()
1286
        try:
1287
            old = transform.trans_id_tree_path('old')
1288
            subdir = transform.trans_id_tree_path('subdir')
1289
            new = transform.trans_id_tree_path('new')
7490.133.25 by Jelmer Vernooij
More fixes.
1290
            self.assertTreeChanges(transform, [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1291
1292
            # content deletion
1293
            transform.delete_contents(old)
7490.133.25 by Jelmer Vernooij
More fixes.
1294
            self.assertTreeChanges(
1295
                transform,
1296
                [InventoryTreeChange(
1297
                    b'id-1', ('old', 'old'), True, (True, True),
1298
                    (root_id, root_id),
1299
                    ('old', 'old'), ('file', None),
1300
                    (False, False), False)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1301
1302
            # content change
1303
            transform.create_file([b'blah'], old)
7490.133.25 by Jelmer Vernooij
More fixes.
1304
            self.assertTreeChanges(
1305
                transform,
1306
                [InventoryTreeChange(
1307
                    b'id-1', ('old', 'old'), True, (True, True),
1308
                    (root_id, root_id),
1309
                    ('old', 'old'), ('file', 'file'),
1310
                    (False, False), False)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1311
            transform.cancel_deletion(old)
7490.133.25 by Jelmer Vernooij
More fixes.
1312
            self.assertTreeChanges(
1313
                transform,
1314
                [InventoryTreeChange(
1315
                    b'id-1', ('old', 'old'), True, (True, True),
1316
                    (root_id, root_id),
1317
                    ('old', 'old'), ('file', 'file'),
1318
                    (False, False), False)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1319
            transform.cancel_creation(old)
1320
1321
            # move file_id to a different file
7490.133.25 by Jelmer Vernooij
More fixes.
1322
            self.assertTreeChanges(transform, [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1323
            transform.unversion_file(old)
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
1324
            transform.version_file(new, file_id=b'id-1')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1325
            transform.adjust_path('old', root, new)
7490.133.30 by Jelmer Vernooij
Fix the remaining test.
1326
            if transform._tree.supports_setting_file_ids():
1327
                self.assertTreeChanges(
1328
                    transform,
1329
                    [InventoryTreeChange(
1330
                        b'id-1', ('old', 'old'), True, (True, True),
1331
                        (root_id, root_id),
1332
                        ('old', 'old'), ('file', 'file'),
1333
                        (False, False), False)])
1334
            else:
1335
                self.assertTreeChanges(
1336
                    transform,
1337
                    [TreeChange(
1338
                        (None, 'old'), False, (False, True),
1339
                        (None, 'old'), (None, 'file'), (False, False), False),
1340
                     TreeChange(
1341
                         ('old', None), False, (True, False), ('old', 'old'),
1342
                         ('file', 'file'), (False, False), False)])
1343
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1344
            transform.cancel_versioning(new)
1345
            transform._removed_id = set()
1346
1347
            # execute bit
7490.133.25 by Jelmer Vernooij
More fixes.
1348
            self.assertTreeChanges(transform, [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1349
            transform.set_executability(True, old)
7490.133.25 by Jelmer Vernooij
More fixes.
1350
            self.assertTreeChanges(
1351
                transform,
1352
                [InventoryTreeChange(
1353
                    b'id-1', ('old', 'old'), False, (True, True),
1354
                    (root_id, root_id),
1355
                    ('old', 'old'), ('file', 'file'),
1356
                    (False, True), False)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1357
            transform.set_executability(None, old)
1358
1359
            # filename
7490.133.25 by Jelmer Vernooij
More fixes.
1360
            self.assertTreeChanges(transform, [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1361
            transform.adjust_path('new', root, old)
1362
            transform._new_parent = {}
7490.133.25 by Jelmer Vernooij
More fixes.
1363
            self.assertTreeChanges(
1364
                transform,
1365
                [InventoryTreeChange(
1366
                    b'id-1', ('old', 'new'), False, (True, True),
1367
                    (root_id, root_id),
1368
                    ('old', 'new'), ('file', 'file'),
1369
                    (False, False), False)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1370
            transform._new_name = {}
1371
1372
            # parent directory
7490.133.25 by Jelmer Vernooij
More fixes.
1373
            self.assertTreeChanges(transform, [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1374
            transform.adjust_path('new', subdir, old)
1375
            transform._new_name = {}
7490.133.25 by Jelmer Vernooij
More fixes.
1376
            self.assertTreeChanges(
1377
                transform, [
1378
                    InventoryTreeChange(
1379
                        b'id-1', ('old', 'subdir/old'), False,
1380
                        (True, True), (root_id, b'subdir-id'), ('old', 'old'),
1381
                        ('file', 'file'), (False, False), False)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1382
            transform._new_path = {}
1383
        finally:
1384
            transform.finalize()
1385
7490.133.20 by Jelmer Vernooij
Some more test fixes.
1386
    def assertTreeChanges(self, tt, expected):
1387
        # TODO(jelmer): Turn this into a matcher?
1388
        actual = list(tt.iter_changes())
1389
        if tt._tree.supports_setting_file_ids():
1390
            self.assertEqual(expected, actual)
1391
        else:
7490.133.26 by Jelmer Vernooij
Some fixes.
1392
            expected = [
1393
                TreeChange(path=c.path, changed_content=c.changed_content,
1394
                           versioned=c.versioned, name=c.name,
1395
                           kind=c.kind, executable=c.executable,
1396
                           copied=c.copied) for c in expected]
1397
            actual = [
1398
                TreeChange(path=c.path, changed_content=c.changed_content,
1399
                           versioned=c.versioned, name=c.name,
1400
                           kind=c.kind, executable=c.executable,
1401
                           copied=c.copied) for c in actual]
7490.133.20 by Jelmer Vernooij
Some more test fixes.
1402
            self.assertEqual(expected, actual)
1403
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1404
    def test_iter_changes_modified_bleed(self):
7490.85.3 by Jelmer Vernooij
Avoid setting root.
1405
        root_id = self.wt.path2id('')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1406
        """Modified flag should not bleed from one change to another"""
1407
        # unfortunately, we have no guarantee that file1 (which is modified)
1408
        # will be applied before file2.  And if it's applied after file2, it
1409
        # obviously can't bleed into file2's change output.  But for now, it
1410
        # works.
1411
        transform, root = self.transform()
1412
        transform.new_file('file1', root, [b'blah'], b'id-1')
1413
        transform.new_file('file2', root, [b'blah'], b'id-2')
1414
        transform.apply()
1415
        transform, root = self.transform()
1416
        try:
7490.133.4 by Jelmer Vernooij
q
1417
            transform.delete_contents(transform.trans_id_tree_path('file1'))
7490.133.9 by Jelmer Vernooij
More improvements to the Git transform implementation.
1418
            transform.set_executability(True, transform.trans_id_tree_path('file2'))
7490.133.25 by Jelmer Vernooij
More fixes.
1419
            self.assertTreeChanges(transform, [
1420
                InventoryTreeChange(
1421
                b'id-1', (u'file1', u'file1'), True, (True, True),
1422
                (root_id, root_id), ('file1', u'file1'),
1423
                ('file', None), (False, False), False),
1424
                InventoryTreeChange(
1425
                b'id-2', (u'file2', u'file2'), False, (True, True),
1426
                (root_id, root_id), ('file2', u'file2'),
1427
                ('file', 'file'), (False, True), False)])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1428
        finally:
1429
            transform.finalize()
1430
1431
    def test_iter_changes_move_missing(self):
1432
        """Test moving ids with no files around"""
7490.85.3 by Jelmer Vernooij
Avoid setting root.
1433
        root_id = self.wt.path2id('')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1434
        # Need two steps because versioning a non-existant file is a conflict.
1435
        transform, root = self.transform()
1436
        transform.new_directory('floater', root, b'floater-id')
1437
        transform.apply()
1438
        transform, root = self.transform()
1439
        transform.delete_contents(transform.trans_id_tree_path('floater'))
1440
        transform.apply()
1441
        transform, root = self.transform()
1442
        floater = transform.trans_id_tree_path('floater')
1443
        try:
1444
            transform.adjust_path('flitter', root, floater)
7490.133.26 by Jelmer Vernooij
Some fixes.
1445
            if self.wt.has_versioned_directories():
1446
                self.assertTreeChanges(
1447
                    transform,
1448
                    [InventoryTreeChange(
1449
                        b'floater-id', ('floater', 'flitter'), False,
1450
                        (True, True),
1451
                        (root_id, root_id),
1452
                        ('floater', 'flitter'),
1453
                        (None, None), (False, False), False)])
1454
            else:
1455
                self.assertTreeChanges(transform, [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1456
        finally:
1457
            transform.finalize()
1458
1459
    def test_iter_changes_pointless(self):
1460
        """Ensure that no-ops are not treated as modifications"""
1461
        transform, root = self.transform()
1462
        transform.new_file('old', root, [b'blah'], b'id-1')
1463
        transform.new_directory('subdir', root, b'subdir-id')
1464
        transform.apply()
1465
        transform, root = self.transform()
1466
        try:
1467
            old = transform.trans_id_tree_path('old')
1468
            subdir = transform.trans_id_tree_path('subdir')
7490.133.25 by Jelmer Vernooij
More fixes.
1469
            self.assertTreeChanges(transform, [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1470
            transform.delete_contents(subdir)
1471
            transform.create_directory(subdir)
1472
            transform.set_executability(False, old)
1473
            transform.unversion_file(old)
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
1474
            transform.version_file(old, file_id=b'id-1')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1475
            transform.adjust_path('old', root, old)
7490.133.25 by Jelmer Vernooij
More fixes.
1476
            self.assertTreeChanges(transform, [])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1477
        finally:
1478
            transform.finalize()
1479
1480
    def test_rename_count(self):
1481
        transform, root = self.transform()
1482
        transform.new_file('name1', root, [b'contents'])
7490.77.16 by Jelmer Vernooij
Move more generic code.
1483
        result = transform.apply()
1484
        self.assertEqual(result.rename_count, 1)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1485
        transform2, root = self.transform()
1486
        transform2.adjust_path('name2', root,
1487
                               transform2.trans_id_tree_path('name1'))
7490.77.16 by Jelmer Vernooij
Move more generic code.
1488
        result = transform2.apply()
1489
        self.assertEqual(result.rename_count, 2)
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1490
1491
    def test_change_parent(self):
1492
        """Ensure that after we change a parent, the results are still right.
1493
1494
        Renames and parent changes on pending transforms can happen as part
1495
        of conflict resolution, and are explicitly permitted by the
1496
        TreeTransform API.
1497
1498
        This test ensures they work correctly with the rename-avoidance
1499
        optimization.
1500
        """
1501
        transform, root = self.transform()
1502
        parent1 = transform.new_directory('parent1', root)
1503
        child1 = transform.new_file('child1', parent1, [b'contents'])
1504
        parent2 = transform.new_directory('parent2', root)
1505
        transform.adjust_path('child1', parent2, child1)
1506
        transform.apply()
1507
        self.assertPathDoesNotExist(self.wt.abspath('parent1/child1'))
1508
        self.assertPathExists(self.wt.abspath('parent2/child1'))
1509
        # rename limbo/new-1 => parent1, rename limbo/new-3 => parent2
1510
        # no rename for child1 (counting only renames during apply)
1511
        self.assertEqual(2, transform.rename_count)
1512
1513
    def test_cancel_parent(self):
1514
        """Cancelling a parent doesn't cause deletion of a non-empty directory
1515
1516
        This is like the test_change_parent, except that we cancel the parent
1517
        before adjusting the path.  The transform must detect that the
1518
        directory is non-empty, and move children to safe locations.
1519
        """
1520
        transform, root = self.transform()
1521
        parent1 = transform.new_directory('parent1', root)
1522
        child1 = transform.new_file('child1', parent1, [b'contents'])
1523
        child2 = transform.new_file('child2', parent1, [b'contents'])
1524
        try:
1525
            transform.cancel_creation(parent1)
1526
        except OSError:
1527
            self.fail('Failed to move child1 before deleting parent1')
1528
        transform.cancel_creation(child2)
1529
        transform.create_directory(parent1)
1530
        try:
1531
            transform.cancel_creation(parent1)
1532
        # If the transform incorrectly believes that child2 is still in
1533
        # parent1's limbo directory, it will try to rename it and fail
1534
        # because was already moved by the first cancel_creation.
1535
        except OSError:
1536
            self.fail('Transform still thinks child2 is a child of parent1')
1537
        parent2 = transform.new_directory('parent2', root)
1538
        transform.adjust_path('child1', parent2, child1)
1539
        transform.apply()
1540
        self.assertPathDoesNotExist(self.wt.abspath('parent1'))
1541
        self.assertPathExists(self.wt.abspath('parent2/child1'))
1542
        # rename limbo/new-3 => parent2, rename limbo/new-2 => child1
1543
        self.assertEqual(2, transform.rename_count)
1544
1545
    def test_adjust_and_cancel(self):
1546
        """Make sure adjust_path keeps track of limbo children properly"""
1547
        transform, root = self.transform()
1548
        parent1 = transform.new_directory('parent1', root)
1549
        child1 = transform.new_file('child1', parent1, [b'contents'])
1550
        parent2 = transform.new_directory('parent2', root)
1551
        transform.adjust_path('child1', parent2, child1)
1552
        transform.cancel_creation(child1)
1553
        try:
1554
            transform.cancel_creation(parent1)
1555
        # if the transform thinks child1 is still in parent1's limbo
1556
        # directory, it will attempt to move it and fail.
1557
        except OSError:
1558
            self.fail('Transform still thinks child1 is a child of parent1')
1559
        transform.finalize()
1560
1561
    def test_noname_contents(self):
1562
        """TreeTransform should permit deferring naming files."""
1563
        transform, root = self.transform()
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
1564
        parent = transform.trans_id_tree_path('parent')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1565
        try:
1566
            transform.create_directory(parent)
1567
        except KeyError:
1568
            self.fail("Can't handle contents with no name")
1569
        transform.finalize()
1570
1571
    def test_noname_contents_nested(self):
1572
        """TreeTransform should permit deferring naming files."""
1573
        transform, root = self.transform()
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
1574
        parent = transform.trans_id_tree_path('parent-early')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1575
        try:
1576
            transform.create_directory(parent)
1577
        except KeyError:
1578
            self.fail("Can't handle contents with no name")
1579
        transform.new_directory('child', parent)
1580
        transform.adjust_path('parent', root, parent)
1581
        transform.apply()
1582
        self.assertPathExists(self.wt.abspath('parent/child'))
1583
        self.assertEqual(1, transform.rename_count)
1584
1585
    def test_reuse_name(self):
1586
        """Avoid reusing the same limbo name for different files"""
1587
        transform, root = self.transform()
1588
        parent = transform.new_directory('parent', root)
1589
        transform.new_directory('child', parent)
1590
        try:
1591
            child2 = transform.new_directory('child', parent)
1592
        except OSError:
1593
            self.fail('Tranform tried to use the same limbo name twice')
1594
        transform.adjust_path('child2', parent, child2)
1595
        transform.apply()
1596
        # limbo/new-1 => parent, limbo/new-3 => parent/child2
1597
        # child2 is put into top-level limbo because child1 has already
1598
        # claimed the direct limbo path when child2 is created.  There is no
1599
        # advantage in renaming files once they're in top-level limbo, except
1600
        # as part of apply.
1601
        self.assertEqual(2, transform.rename_count)
1602
1603
    def test_reuse_when_first_moved(self):
1604
        """Don't avoid direct paths when it is safe to use them"""
1605
        transform, root = self.transform()
1606
        parent = transform.new_directory('parent', root)
1607
        child1 = transform.new_directory('child', parent)
1608
        transform.adjust_path('child1', parent, child1)
1609
        transform.new_directory('child', parent)
1610
        transform.apply()
1611
        # limbo/new-1 => parent
1612
        self.assertEqual(1, transform.rename_count)
1613
1614
    def test_reuse_after_cancel(self):
1615
        """Don't avoid direct paths when it is safe to use them"""
1616
        transform, root = self.transform()
1617
        parent2 = transform.new_directory('parent2', root)
1618
        child1 = transform.new_directory('child1', parent2)
1619
        transform.cancel_creation(parent2)
1620
        transform.create_directory(parent2)
1621
        transform.new_directory('child1', parent2)
1622
        transform.adjust_path('child2', parent2, child1)
1623
        transform.apply()
1624
        # limbo/new-1 => parent2, limbo/new-2 => parent2/child1
1625
        self.assertEqual(2, transform.rename_count)
1626
1627
    def test_finalize_order(self):
1628
        """Finalize must be done in child-to-parent order"""
1629
        transform, root = self.transform()
1630
        parent = transform.new_directory('parent', root)
1631
        transform.new_directory('child', parent)
1632
        try:
1633
            transform.finalize()
1634
        except OSError:
1635
            self.fail('Tried to remove parent before child1')
1636
1637
    def test_cancel_with_cancelled_child_should_succeed(self):
1638
        transform, root = self.transform()
1639
        parent = transform.new_directory('parent', root)
1640
        child = transform.new_directory('child', parent)
1641
        transform.cancel_creation(child)
1642
        transform.cancel_creation(parent)
1643
        transform.finalize()
1644
1645
    def test_rollback_on_directory_clash(self):
1646
        def tt_helper():
1647
            wt = self.make_branch_and_tree('.')
1648
            tt = wt.transform()  # TreeTransform obtains write lock
1649
            try:
1650
                foo = tt.new_directory('foo', tt.root)
1651
                tt.new_file('bar', foo, [b'foobar'])
1652
                baz = tt.new_directory('baz', tt.root)
1653
                tt.new_file('qux', baz, [b'quux'])
1654
                # Ask for a rename 'foo' -> 'baz'
1655
                tt.adjust_path('baz', tt.root, foo)
1656
                # Lie to tt that we've already resolved all conflicts.
1657
                tt.apply(no_conflicts=True)
1658
            except BaseException:
1659
                wt.unlock()
1660
                raise
1661
        # The rename will fail because the target directory is not empty (but
1662
        # raises FileExists anyway).
1663
        err = self.assertRaises(errors.FileExists, tt_helper)
1664
        self.assertEndsWith(err.path, "/baz")
1665
1666
    def test_two_directories_clash(self):
1667
        def tt_helper():
1668
            wt = self.make_branch_and_tree('.')
1669
            tt = wt.transform()  # TreeTransform obtains write lock
1670
            try:
1671
                foo_1 = tt.new_directory('foo', tt.root)
1672
                tt.new_directory('bar', foo_1)
1673
                # Adding the same directory with a different content
1674
                foo_2 = tt.new_directory('foo', tt.root)
1675
                tt.new_directory('baz', foo_2)
1676
                # Lie to tt that we've already resolved all conflicts.
1677
                tt.apply(no_conflicts=True)
1678
            except BaseException:
1679
                wt.unlock()
1680
                raise
1681
        err = self.assertRaises(errors.FileExists, tt_helper)
1682
        self.assertEndsWith(err.path, "/foo")
1683
1684
    def test_two_directories_clash_finalize(self):
1685
        def tt_helper():
1686
            wt = self.make_branch_and_tree('.')
1687
            tt = wt.transform()  # TreeTransform obtains write lock
1688
            try:
1689
                foo_1 = tt.new_directory('foo', tt.root)
1690
                tt.new_directory('bar', foo_1)
1691
                # Adding the same directory with a different content
1692
                foo_2 = tt.new_directory('foo', tt.root)
1693
                tt.new_directory('baz', foo_2)
1694
                # Lie to tt that we've already resolved all conflicts.
1695
                tt.apply(no_conflicts=True)
1696
            except BaseException:
1697
                tt.finalize()
1698
                raise
1699
        err = self.assertRaises(errors.FileExists, tt_helper)
1700
        self.assertEndsWith(err.path, "/foo")
1701
1702
    def test_file_to_directory(self):
1703
        wt = self.make_branch_and_tree('.')
1704
        self.build_tree(['foo'])
1705
        wt.add(['foo'])
1706
        wt.commit("one")
1707
        tt = wt.transform()
1708
        self.addCleanup(tt.finalize)
1709
        foo_trans_id = tt.trans_id_tree_path("foo")
1710
        tt.delete_contents(foo_trans_id)
1711
        tt.create_directory(foo_trans_id)
1712
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1713
        tt.create_file([b"aa\n"], bar_trans_id)
7490.83.4 by Jelmer Vernooij
Merge lp:brz/3.1.
1714
        tt.version_file(bar_trans_id, file_id=b"bar-1")
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1715
        tt.apply()
1716
        self.assertPathExists("foo/bar")
1717
        with wt.lock_read():
1718
            self.assertEqual(wt.kind("foo"), "directory")
1719
        wt.commit("two")
1720
        changes = wt.changes_from(wt.basis_tree())
1721
        self.assertFalse(changes.has_changed(), changes)
1722
1723
    def test_file_to_symlink(self):
1724
        self.requireFeature(SymlinkFeature)
1725
        wt = self.make_branch_and_tree('.')
1726
        self.build_tree(['foo'])
1727
        wt.add(['foo'])
1728
        wt.commit("one")
1729
        tt = wt.transform()
1730
        self.addCleanup(tt.finalize)
1731
        foo_trans_id = tt.trans_id_tree_path("foo")
1732
        tt.delete_contents(foo_trans_id)
1733
        tt.create_symlink("bar", foo_trans_id)
1734
        tt.apply()
1735
        self.assertPathExists("foo")
1736
        wt.lock_read()
1737
        self.addCleanup(wt.unlock)
1738
        self.assertEqual(wt.kind("foo"), "symlink")
1739
1740
    def test_file_to_symlink_unsupported(self):
1741
        wt = self.make_branch_and_tree('.')
1742
        self.build_tree(['foo'])
1743
        wt.add(['foo'])
1744
        wt.commit("one")
1745
        self.overrideAttr(osutils, 'supports_symlinks', lambda p: False)
1746
        tt = wt.transform()
1747
        self.addCleanup(tt.finalize)
1748
        foo_trans_id = tt.trans_id_tree_path("foo")
1749
        tt.delete_contents(foo_trans_id)
1750
        log = BytesIO()
1751
        trace.push_log_file(log)
1752
        tt.create_symlink("bar", foo_trans_id)
1753
        tt.apply()
1754
        self.assertContainsRe(
1755
            log.getvalue(),
1756
            b'Unable to create symlink "foo" on this filesystem')
1757
1758
    def test_dir_to_file(self):
1759
        wt = self.make_branch_and_tree('.')
1760
        self.build_tree(['foo/', 'foo/bar'])
1761
        wt.add(['foo', 'foo/bar'])
1762
        wt.commit("one")
1763
        tt = wt.transform()
1764
        self.addCleanup(tt.finalize)
1765
        foo_trans_id = tt.trans_id_tree_path("foo")
1766
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1767
        tt.delete_contents(foo_trans_id)
1768
        tt.delete_versioned(bar_trans_id)
1769
        tt.create_file([b"aa\n"], foo_trans_id)
1770
        tt.apply()
1771
        self.assertPathExists("foo")
1772
        wt.lock_read()
1773
        self.addCleanup(wt.unlock)
1774
        self.assertEqual(wt.kind("foo"), "file")
1775
1776
    def test_dir_to_hardlink(self):
1777
        self.requireFeature(HardlinkFeature)
1778
        wt = self.make_branch_and_tree('.')
1779
        self.build_tree(['foo/', 'foo/bar'])
1780
        wt.add(['foo', 'foo/bar'])
1781
        wt.commit("one")
1782
        tt = wt.transform()
1783
        self.addCleanup(tt.finalize)
1784
        foo_trans_id = tt.trans_id_tree_path("foo")
1785
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1786
        tt.delete_contents(foo_trans_id)
1787
        tt.delete_versioned(bar_trans_id)
1788
        self.build_tree(['baz'])
1789
        tt.create_hardlink("baz", foo_trans_id)
1790
        tt.apply()
1791
        self.assertPathExists("foo")
1792
        self.assertPathExists("baz")
1793
        wt.lock_read()
1794
        self.addCleanup(wt.unlock)
1795
        self.assertEqual(wt.kind("foo"), "file")
1796
1797
    def test_no_final_path(self):
1798
        transform, root = self.transform()
7490.133.5 by Jelmer Vernooij
Make assign_id public, fix some more GitTransform tests.
1799
        trans_id = transform.trans_id_tree_path('foo')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1800
        transform.create_file([b'bar'], trans_id)
1801
        transform.cancel_creation(trans_id)
1802
        transform.apply()
1803
1804
    def test_create_from_tree(self):
1805
        tree1 = self.make_branch_and_tree('tree1')
1806
        self.build_tree_contents([('tree1/foo/',), ('tree1/bar', b'baz')])
7490.83.9 by Jelmer Vernooij
Split out per-tree transform preview tests.
1807
        tree1.add(['foo', 'bar'])
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1808
        tree2 = self.make_branch_and_tree('tree2')
1809
        tt = tree2.transform()
1810
        foo_trans_id = tt.create_path('foo', tt.root)
1811
        create_from_tree(tt, foo_trans_id, tree1, 'foo')
1812
        bar_trans_id = tt.create_path('bar', tt.root)
1813
        create_from_tree(tt, bar_trans_id, tree1, 'bar')
1814
        tt.apply()
1815
        self.assertEqual('directory', osutils.file_kind('tree2/foo'))
1816
        self.assertFileEqual(b'baz', 'tree2/bar')
1817
1818
    def test_create_from_tree_bytes(self):
1819
        """Provided lines are used instead of tree content."""
1820
        tree1 = self.make_branch_and_tree('tree1')
1821
        self.build_tree_contents([('tree1/foo', b'bar'), ])
7490.83.9 by Jelmer Vernooij
Split out per-tree transform preview tests.
1822
        tree1.add('foo')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1823
        tree2 = self.make_branch_and_tree('tree2')
1824
        tt = tree2.transform()
1825
        foo_trans_id = tt.create_path('foo', tt.root)
1826
        create_from_tree(tt, foo_trans_id, tree1, 'foo', chunks=[b'qux'])
1827
        tt.apply()
1828
        self.assertFileEqual(b'qux', 'tree2/foo')
1829
1830
    def test_create_from_tree_symlink(self):
1831
        self.requireFeature(SymlinkFeature)
1832
        tree1 = self.make_branch_and_tree('tree1')
1833
        os.symlink('bar', 'tree1/foo')
7490.83.9 by Jelmer Vernooij
Split out per-tree transform preview tests.
1834
        tree1.add('foo')
7490.80.1 by Jelmer Vernooij
Run transform tests per working tree.
1835
        tt = self.make_branch_and_tree('tree2').transform()
1836
        foo_trans_id = tt.create_path('foo', tt.root)
1837
        create_from_tree(tt, foo_trans_id, tree1, 'foo')
1838
        tt.apply()
1839
        self.assertEqual('bar', os.readlink('tree2/foo'))