/brz/remove-bazaar

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

« back to all changes in this revision

Viewing changes to breezy/tests/test_transform.py

  • Committer: Jelmer Vernooij
  • Date: 2018-05-06 11:48:54 UTC
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@jelmer.uk-20180506114854-h4qd9ojaqy8wxjsd
Move .mailmap to root.

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
 
import codecs
18
17
import errno
19
 
from io import BytesIO, StringIO
20
18
import os
21
19
import sys
22
20
import time
25
23
    bencode,
26
24
    errors,
27
25
    filters,
 
26
    generate_ids,
28
27
    osutils,
29
28
    revision as _mod_revision,
30
29
    rules,
33
32
    transform,
34
33
    urlutils,
35
34
    )
36
 
from ..bzr import (
37
 
    generate_ids,
38
 
    )
39
35
from ..conflicts import (
40
36
    DeletingParent,
41
37
    DuplicateEntry,
65
61
from ..mutabletree import MutableTree
66
62
from ..sixish import (
67
63
    BytesIO,
68
 
    PY3,
69
 
    text_type,
70
64
    )
71
65
from . import (
72
66
    features,
107
101
        trans, root = self.get_transform()
108
102
        self.wt.lock_tree_write()
109
103
        self.addCleanup(self.wt.unlock)
110
 
        contents = [b'just some content\n']
 
104
        contents = ['just some content\n']
111
105
        sha1 = osutils.sha_strings(contents)
112
106
        # Roll back the clock
113
107
        trans._creation_mtime = time.time() - 20.0
147
141
        self.assertEqual(imaginary_id, imaginary_id2)
148
142
        self.assertEqual(root, transform.get_tree_parent(imaginary_id))
149
143
        self.assertEqual('directory', transform.final_kind(root))
150
 
        self.assertEqual(self.wt.path2id(''), transform.final_file_id(root))
 
144
        self.assertEqual(self.wt.get_root_id(), transform.final_file_id(root))
151
145
        trans_id = transform.create_path('name', root)
152
146
        self.assertIs(transform.final_file_id(trans_id), None)
153
147
        self.assertIs(None, transform.final_kind(trans_id))
154
 
        transform.create_file([b'contents'], trans_id)
 
148
        transform.create_file('contents', trans_id)
155
149
        transform.set_executability(True, trans_id)
156
 
        transform.version_file(b'my_pretties', trans_id)
 
150
        transform.version_file('my_pretties', trans_id)
157
151
        self.assertRaises(DuplicateKey, transform.version_file,
158
 
                          b'my_pretties', trans_id)
159
 
        self.assertEqual(transform.final_file_id(trans_id), b'my_pretties')
 
152
                          'my_pretties', trans_id)
 
153
        self.assertEqual(transform.final_file_id(trans_id), 'my_pretties')
160
154
        self.assertEqual(transform.final_parent(trans_id), root)
161
155
        self.assertIs(transform.final_parent(root), ROOT_PARENT)
162
156
        self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
163
157
        oz_id = transform.create_path('oz', root)
164
158
        transform.create_directory(oz_id)
165
 
        transform.version_file(b'ozzie', oz_id)
 
159
        transform.version_file('ozzie', oz_id)
166
160
        trans_id2 = transform.create_path('name2', root)
167
 
        transform.create_file([b'contents'], trans_id2)
 
161
        transform.create_file('contents', trans_id2)
168
162
        transform.set_executability(False, trans_id2)
169
 
        transform.version_file(b'my_pretties2', trans_id2)
 
163
        transform.version_file('my_pretties2', trans_id2)
170
164
        modified_paths = transform.apply().modified_paths
171
 
        with self.wt.get_file('name') as f:
172
 
            self.assertEqual(b'contents', f.read())
173
 
        self.assertEqual(self.wt.path2id('name'), b'my_pretties')
 
165
        self.assertEqual('contents', self.wt.get_file('name').read())
 
166
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
174
167
        self.assertIs(self.wt.is_executable('name'), True)
175
168
        self.assertIs(self.wt.is_executable('name2'), False)
176
169
        self.assertEqual('directory', file_kind(self.wt.abspath('oz')))
177
170
        self.assertEqual(len(modified_paths), 3)
178
171
        tree_mod_paths = [self.wt.abspath(self.wt.id2path(f)) for f in
179
 
                          (b'ozzie', b'my_pretties', b'my_pretties2')]
 
172
                          ('ozzie', 'my_pretties', 'my_pretties2')]
180
173
        self.assertSubset(tree_mod_paths, modified_paths)
181
174
        # is it safe to finalize repeatedly?
182
175
        transform.finalize()
184
177
 
185
178
    def test_apply_informs_tree_of_observed_sha1(self):
186
179
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
187
 
        trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
 
180
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
188
181
                                  sha1=sha1)
189
182
        calls = []
190
183
        orig = self.wt._observed_sha1
191
 
 
192
184
        def _observed_sha1(*args):
193
185
            calls.append(args)
194
186
            orig(*args)
195
187
        self.wt._observed_sha1 = _observed_sha1
196
188
        trans.apply()
197
 
        self.assertEqual([('file1', trans._observed_sha1s[trans_id])],
 
189
        self.assertEqual([(None, 'file1', trans._observed_sha1s[trans_id])],
198
190
                         calls)
199
191
 
200
192
    def test_create_file_caches_sha1(self):
229
221
 
230
222
    def test_new_file_caches_sha1(self):
231
223
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
232
 
        trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
 
224
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
233
225
                                  sha1=sha1)
234
226
        st_val = osutils.lstat(trans._limbo_name(trans_id))
235
227
        o_sha1, o_st_val = trans._observed_sha1s[trans_id]
238
230
 
239
231
    def test_cancel_creation_removes_observed_sha1(self):
240
232
        trans, root, contents, sha1 = self.get_transform_for_sha1_test()
241
 
        trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
 
233
        trans_id = trans.new_file('file1', root, contents, file_id='file1-id',
242
234
                                  sha1=sha1)
243
235
        self.assertTrue(trans_id in trans._observed_sha1s)
244
236
        trans.cancel_creation(trans_id)
251
243
        # Roll back the clock, so that we know everything is being set to the
252
244
        # exact time
253
245
        transform._creation_mtime = creation_mtime = time.time() - 20.0
254
 
        transform.create_file([b'content-one'],
 
246
        transform.create_file('content-one',
255
247
                              transform.create_path('one', root))
256
 
        time.sleep(1)  # *ugly*
257
 
        transform.create_file([b'content-two'],
 
248
        time.sleep(1) # *ugly*
 
249
        transform.create_file('content-two',
258
250
                              transform.create_path('two', root))
259
251
        transform.apply()
260
252
        fo, st1 = self.wt.get_file_with_stat('one', filtered=False)
262
254
        fo, st2 = self.wt.get_file_with_stat('two', filtered=False)
263
255
        fo.close()
264
256
        # We only guarantee 2s resolution
265
 
        self.assertTrue(
266
 
            abs(creation_mtime - st1.st_mtime) < 2.0,
 
257
        self.assertTrue(abs(creation_mtime - st1.st_mtime) < 2.0,
267
258
            "%s != %s within 2 seconds" % (creation_mtime, st1.st_mtime))
268
259
        # But if we have more than that, all files should get the same result
269
260
        self.assertEqual(st1.st_mtime, st2.st_mtime)
270
261
 
271
262
    def test_change_root_id(self):
272
263
        transform, root = self.get_transform()
273
 
        self.assertNotEqual(b'new-root-id', self.wt.path2id(''))
 
264
        self.assertNotEqual(b'new-root-id', self.wt.get_root_id())
274
265
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
275
266
        transform.delete_contents(root)
276
267
        transform.unversion_file(root)
277
268
        transform.fixup_new_roots()
278
269
        transform.apply()
279
 
        self.assertEqual(b'new-root-id', self.wt.path2id(''))
 
270
        self.assertEqual(b'new-root-id', self.wt.get_root_id())
280
271
 
281
272
    def test_change_root_id_add_files(self):
282
273
        transform, root = self.get_transform()
283
 
        self.assertNotEqual(b'new-root-id', self.wt.path2id(''))
 
274
        self.assertNotEqual(b'new-root-id', self.wt.get_root_id())
284
275
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
285
 
        transform.new_file('file', new_trans_id, [b'new-contents\n'],
286
 
                           b'new-file-id')
 
276
        transform.new_file('file', new_trans_id, ['new-contents\n'],
 
277
                           'new-file-id')
287
278
        transform.delete_contents(root)
288
279
        transform.unversion_file(root)
289
280
        transform.fixup_new_roots()
290
281
        transform.apply()
291
 
        self.assertEqual(b'new-root-id', self.wt.path2id(''))
 
282
        self.assertEqual(b'new-root-id', self.wt.get_root_id())
292
283
        self.assertEqual(b'new-file-id', self.wt.path2id('file'))
293
 
        self.assertFileEqual(b'new-contents\n', self.wt.abspath('file'))
 
284
        self.assertFileEqual('new-contents\n', self.wt.abspath('file'))
294
285
 
295
286
    def test_add_two_roots(self):
296
287
        transform, root = self.get_transform()
297
 
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
298
 
        transform.new_directory('', ROOT_PARENT, b'alt-root-id')
 
288
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
 
289
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'alt-root-id')
299
290
        self.assertRaises(ValueError, transform.fixup_new_roots)
300
291
 
301
292
    def test_retain_existing_root(self):
314
305
 
315
306
    def test_add_unversioned_root(self):
316
307
        transform, root = self.get_transform()
317
 
        transform.new_directory('', ROOT_PARENT, None)
 
308
        new_trans_id = transform.new_directory('', ROOT_PARENT, None)
318
309
        transform.delete_contents(transform.root)
319
310
        transform.fixup_new_roots()
320
311
        self.assertNotIn(transform.root, transform._new_id)
321
312
 
322
313
    def test_remove_root_fixup(self):
323
314
        transform, root = self.get_transform()
324
 
        old_root_id = self.wt.path2id('')
 
315
        old_root_id = self.wt.get_root_id()
325
316
        self.assertNotEqual(b'new-root-id', old_root_id)
326
317
        transform.delete_contents(root)
327
318
        transform.unversion_file(root)
328
319
        transform.fixup_new_roots()
329
320
        transform.apply()
330
 
        self.assertEqual(old_root_id, self.wt.path2id(''))
 
321
        self.assertEqual(old_root_id, self.wt.get_root_id())
331
322
 
332
323
        transform, root = self.get_transform()
333
 
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
334
 
        transform.new_directory('', ROOT_PARENT, b'alt-root-id')
 
324
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
 
325
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'alt-root-id')
335
326
        self.assertRaises(ValueError, transform.fixup_new_roots)
336
327
 
337
328
    def test_fixup_new_roots_permits_empty_tree(self):
358
349
        old_root_id = transform.tree_file_id(root)
359
350
        transform.unversion_file(root)
360
351
        transform.apply()
361
 
        self.assertEqual(old_root_id, self.wt.path2id(''))
 
352
        self.assertEqual(old_root_id, self.wt.get_root_id())
362
353
 
363
354
    def test_hardlink(self):
364
355
        self.requireFeature(HardlinkFeature)
365
356
        transform, root = self.get_transform()
366
 
        transform.new_file('file1', root, [b'contents'])
 
357
        transform.new_file('file1', root, 'contents')
367
358
        transform.apply()
368
359
        target = self.make_branch_and_tree('target')
369
360
        target_transform = TreeTransform(target)
379
370
        transform, root = self.get_transform()
380
371
        self.wt.lock_tree_write()
381
372
        self.addCleanup(self.wt.unlock)
382
 
        transform.new_file('name', root, [b'contents'], b'my_pretties', True)
383
 
        oz = transform.new_directory('oz', root, b'oz-id')
384
 
        dorothy = transform.new_directory('dorothy', oz, b'dorothy-id')
385
 
        transform.new_file('toto', dorothy, [b'toto-contents'], b'toto-id',
386
 
                           False)
 
373
        trans_id = transform.new_file('name', root, 'contents',
 
374
                                      'my_pretties', True)
 
375
        oz = transform.new_directory('oz', root, 'oz-id')
 
376
        dorothy = transform.new_directory('dorothy', oz, 'dorothy-id')
 
377
        toto = transform.new_file('toto', dorothy, 'toto-contents',
 
378
                                  'toto-id', False)
387
379
 
388
380
        self.assertEqual(len(transform.find_conflicts()), 0)
389
381
        transform.apply()
390
382
        self.assertRaises(ReusingTransform, transform.find_conflicts)
391
 
        with open(self.wt.abspath('name'), 'r') as f:
392
 
            self.assertEqual('contents', f.read())
393
 
        self.assertEqual(self.wt.path2id('name'), b'my_pretties')
 
383
        self.assertEqual('contents', file(self.wt.abspath('name')).read())
 
384
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
394
385
        self.assertIs(self.wt.is_executable('name'), True)
395
 
        self.assertEqual(self.wt.path2id('oz'), b'oz-id')
396
 
        self.assertEqual(self.wt.path2id('oz/dorothy'), b'dorothy-id')
397
 
        self.assertEqual(self.wt.path2id('oz/dorothy/toto'), b'toto-id')
 
386
        self.assertEqual(self.wt.path2id('oz'), 'oz-id')
 
387
        self.assertEqual(self.wt.path2id('oz/dorothy'), 'dorothy-id')
 
388
        self.assertEqual(self.wt.path2id('oz/dorothy/toto'), 'toto-id')
398
389
 
399
 
        self.assertEqual(b'toto-contents',
 
390
        self.assertEqual('toto-contents',
400
391
                         self.wt.get_file('oz/dorothy/toto').read())
401
392
        self.assertIs(self.wt.is_executable('oz/dorothy/toto'), False)
402
393
 
403
394
    def test_tree_reference(self):
404
395
        transform, root = self.get_transform()
405
396
        tree = transform._tree
406
 
        trans_id = transform.new_directory('reference', root, b'subtree-id')
407
 
        transform.set_tree_reference(b'subtree-revision', trans_id)
 
397
        trans_id = transform.new_directory('reference', root, 'subtree-id')
 
398
        transform.set_tree_reference('subtree-revision', trans_id)
408
399
        transform.apply()
409
400
        tree.lock_read()
410
401
        self.addCleanup(tree.unlock)
411
 
        self.assertEqual(
412
 
            b'subtree-revision',
413
 
            tree.root_inventory.get_entry(b'subtree-id').reference_revision)
 
402
        self.assertEqual('subtree-revision',
 
403
                         tree.root_inventory.get_entry('subtree-id').reference_revision)
414
404
 
415
405
    def test_conflicts(self):
416
406
        transform, root = self.get_transform()
417
 
        trans_id = transform.new_file('name', root, [b'contents'],
418
 
                                      b'my_pretties')
 
407
        trans_id = transform.new_file('name', root, 'contents',
 
408
                                      'my_pretties')
419
409
        self.assertEqual(len(transform.find_conflicts()), 0)
420
 
        trans_id2 = transform.new_file('name', root, [b'Crontents'], b'toto')
 
410
        trans_id2 = transform.new_file('name', root, 'Crontents', 'toto')
421
411
        self.assertEqual(transform.find_conflicts(),
422
412
                         [('duplicate', trans_id, trans_id2, 'name')])
423
413
        self.assertRaises(MalformedTransform, transform.apply)
437
427
        self.assertEqual(transform.find_conflicts(),
438
428
                         [('unversioned parent', lion_id),
439
429
                          ('missing parent', lion_id)])
440
 
        transform.version_file(b"Courage", lion_id)
 
430
        transform.version_file("Courage", lion_id)
441
431
        self.assertEqual(transform.find_conflicts(),
442
432
                         [('missing parent', lion_id),
443
433
                          ('versioning no contents', lion_id)])
444
434
        transform.adjust_path('name2', root, trans_id2)
445
435
        self.assertEqual(transform.find_conflicts(),
446
436
                         [('versioning no contents', lion_id)])
447
 
        transform.create_file([b'Contents, okay?'], lion_id)
 
437
        transform.create_file('Contents, okay?', lion_id)
448
438
        transform.adjust_path('name2', trans_id2, trans_id2)
449
439
        self.assertEqual(transform.find_conflicts(),
450
440
                         [('parent loop', trans_id2),
454
444
        transform.set_executability(True, oz_id)
455
445
        self.assertEqual(transform.find_conflicts(),
456
446
                         [('unversioned executability', oz_id)])
457
 
        transform.version_file(b'oz-id', oz_id)
 
447
        transform.version_file('oz-id', oz_id)
458
448
        self.assertEqual(transform.find_conflicts(),
459
449
                         [('non-file executability', oz_id)])
460
450
        transform.set_executability(None, oz_id)
461
 
        tip_id = transform.new_file('tip', oz_id, [b'ozma'], b'tip-id')
 
451
        tip_id = transform.new_file('tip', oz_id, 'ozma', 'tip-id')
462
452
        transform.apply()
463
 
        self.assertEqual(self.wt.path2id('name'), b'my_pretties')
464
 
        with open(self.wt.abspath('name'), 'rb') as f:
465
 
            self.assertEqual(b'contents', f.read())
 
453
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
 
454
        self.assertEqual('contents', file(self.wt.abspath('name')).read())
466
455
        transform2, root = self.get_transform()
467
456
        oz_id = transform2.trans_id_tree_path('oz')
468
 
        newtip = transform2.new_file('tip', oz_id, [b'other'], b'tip-id')
 
457
        newtip = transform2.new_file('tip', oz_id, 'other', 'tip-id')
469
458
        result = transform2.find_conflicts()
470
459
        fp = FinalPaths(transform2)
471
460
        self.assertTrue('oz/tip' in transform2._tree_path_ids)
495
484
        tree.case_sensitive = True
496
485
        transform = TreeTransform(tree)
497
486
        self.addCleanup(transform.finalize)
498
 
        transform.new_file('file', transform.root, [b'content'])
499
 
        transform.new_file('FiLe', transform.root, [b'content'])
 
487
        transform.new_file('file', transform.root, 'content')
 
488
        transform.new_file('FiLe', transform.root, 'content')
500
489
        result = transform.find_conflicts()
501
490
        self.assertEqual([], result)
502
491
        transform.finalize()
505
494
        tree.case_sensitive = False
506
495
        transform = TreeTransform(tree)
507
496
        self.addCleanup(transform.finalize)
508
 
        transform.new_file('file', transform.root, [b'content'])
509
 
        transform.new_file('FiLe', transform.root, [b'content'])
 
497
        transform.new_file('file', transform.root, 'content')
 
498
        transform.new_file('FiLe', transform.root, 'content')
510
499
        result = transform.find_conflicts()
511
500
        self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
512
501
 
519
508
        tree.case_sensitive = True
520
509
        transform = TreeTransform(tree)
521
510
        self.addCleanup(transform.finalize)
522
 
        transform.new_file('file', transform.root, [b'content'])
 
511
        transform.new_file('file', transform.root, 'content')
523
512
        result = transform.find_conflicts()
524
513
        self.assertEqual([], result)
525
514
        transform.finalize()
528
517
        tree.case_sensitive = False
529
518
        transform = TreeTransform(tree)
530
519
        self.addCleanup(transform.finalize)
531
 
        transform.new_file('file', transform.root, [b'content'])
 
520
        transform.new_file('file', transform.root, 'content')
532
521
        result = transform.find_conflicts()
533
522
        self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
534
523
 
540
529
        tree.case_sensitive = False
541
530
        transform = TreeTransform(tree)
542
531
        self.addCleanup(transform.finalize)
543
 
        transform.new_file('file', transform.root, [b'content'])
544
 
        transform.new_file('FiLe', transform.root, [b'content'])
 
532
        transform.new_file('file', transform.root, 'content')
 
533
        transform.new_file('FiLe', transform.root, 'content')
545
534
        resolve_conflicts(transform)
546
535
        transform.apply()
547
536
        self.assertPathExists('tree/file')
555
544
        tree.case_sensitive = False
556
545
        transform = TreeTransform(tree)
557
546
        self.addCleanup(transform.finalize)
558
 
        transform.new_file('file', transform.root, [b'content'])
559
 
        transform.new_file('FiLe', transform.root, [b'content'])
 
547
        transform.new_file('file', transform.root, 'content')
 
548
        transform.new_file('FiLe', transform.root, 'content')
560
549
        resolve_conflicts(transform,
561
550
                          pass_func=lambda t, c: resolve_checkout(t, c, []))
562
551
        transform.apply()
568
557
        tree = self.make_branch_and_tree('tree')
569
558
        transform = TreeTransform(tree)
570
559
        self.addCleanup(transform.finalize)
571
 
        transform.new_file('file', transform.root, [b'content'])
572
 
        transform.new_file('FiLe', transform.root, [b'content'])
 
560
        transform.new_file('file', transform.root, 'content')
 
561
        transform.new_file('FiLe', transform.root, 'content')
573
562
        dir = transform.new_directory('dir', transform.root)
574
 
        transform.new_file('dirfile', dir, [b'content'])
575
 
        transform.new_file('dirFiLe', dir, [b'content'])
 
563
        transform.new_file('dirfile', dir, 'content')
 
564
        transform.new_file('dirFiLe', dir, 'content')
576
565
        resolve_conflicts(transform)
577
566
        transform.apply()
578
567
        self.assertPathExists('tree/file')
590
579
        transform = TreeTransform(tree)
591
580
        self.addCleanup(transform.finalize)
592
581
        dir = transform.new_directory('dir', transform.root)
593
 
        first = transform.new_file('file', dir, [b'content'])
594
 
        second = transform.new_file('FiLe', dir, [b'content'])
 
582
        first = transform.new_file('file', dir, 'content')
 
583
        second = transform.new_file('FiLe', dir, 'content')
595
584
        self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
596
585
        self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
597
586
 
609
598
 
610
599
    def test_add_del(self):
611
600
        start, root = self.get_transform()
612
 
        start.new_directory('a', root, b'a')
 
601
        start.new_directory('a', root, 'a')
613
602
        start.apply()
614
603
        transform, root = self.get_transform()
615
604
        transform.delete_versioned(transform.trans_id_tree_path('a'))
616
 
        transform.new_directory('a', root, b'a')
 
605
        transform.new_directory('a', root, 'a')
617
606
        transform.apply()
618
607
 
619
608
    def test_unversioning(self):
620
609
        create_tree, root = self.get_transform()
621
610
        parent_id = create_tree.new_directory('parent', root, b'parent-id')
622
 
        create_tree.new_file('child', parent_id, [b'child'], b'child-id')
 
611
        create_tree.new_file('child', parent_id, 'child', b'child-id')
623
612
        create_tree.apply()
624
613
        unversion = TreeTransform(self.wt)
625
614
        self.addCleanup(unversion.finalize)
635
624
        create_tree, root = self.get_transform()
636
625
        # prepare tree
637
626
        root = create_tree.root
638
 
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
639
 
        create_tree.new_file('name2', root, [b'hello2'], b'name2')
640
 
        ddir = create_tree.new_directory('dying_directory', root, b'ddir')
641
 
        create_tree.new_file('dying_file', ddir, [b'goodbye1'], b'dfile')
642
 
        create_tree.new_file('moving_file', ddir, [b'later1'], b'mfile')
643
 
        create_tree.new_file('moving_file2', root, [b'later2'], b'mfile2')
 
627
        create_tree.new_file('name1', root, 'hello1', 'name1')
 
628
        create_tree.new_file('name2', root, 'hello2', 'name2')
 
629
        ddir = create_tree.new_directory('dying_directory', root, 'ddir')
 
630
        create_tree.new_file('dying_file', ddir, 'goodbye1', 'dfile')
 
631
        create_tree.new_file('moving_file', ddir, 'later1', 'mfile')
 
632
        create_tree.new_file('moving_file2', root, 'later2', 'mfile2')
644
633
        create_tree.apply()
645
634
 
646
635
        mangle_tree, root = self.get_transform()
647
636
        root = mangle_tree.root
648
 
        # swap names
 
637
        #swap names
649
638
        name1 = mangle_tree.trans_id_tree_path('name1')
650
639
        name2 = mangle_tree.trans_id_tree_path('name2')
651
640
        mangle_tree.adjust_path('name2', root, name1)
652
641
        mangle_tree.adjust_path('name1', root, name2)
653
642
 
654
 
        # tests for deleting parent directories
 
643
        #tests for deleting parent directories
655
644
        ddir = mangle_tree.trans_id_tree_path('dying_directory')
656
645
        mangle_tree.delete_contents(ddir)
657
646
        dfile = mangle_tree.trans_id_tree_path('dying_directory/dying_file')
660
649
        mfile = mangle_tree.trans_id_tree_path('dying_directory/moving_file')
661
650
        mangle_tree.adjust_path('mfile', root, mfile)
662
651
 
663
 
        # tests for adding parent directories
664
 
        newdir = mangle_tree.new_directory('new_directory', root, b'newdir')
 
652
        #tests for adding parent directories
 
653
        newdir = mangle_tree.new_directory('new_directory', root, 'newdir')
665
654
        mfile2 = mangle_tree.trans_id_tree_path('moving_file2')
666
655
        mangle_tree.adjust_path('mfile2', newdir, mfile2)
667
 
        mangle_tree.new_file('newfile', newdir, [b'hello3'], b'dfile')
668
 
        self.assertEqual(mangle_tree.final_file_id(mfile2), b'mfile2')
 
656
        mangle_tree.new_file('newfile', newdir, 'hello3', 'dfile')
 
657
        self.assertEqual(mangle_tree.final_file_id(mfile2), 'mfile2')
669
658
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
670
 
        self.assertEqual(mangle_tree.final_file_id(mfile2), b'mfile2')
 
659
        self.assertEqual(mangle_tree.final_file_id(mfile2), 'mfile2')
671
660
        mangle_tree.apply()
672
 
        with open(self.wt.abspath('name1'), 'r') as f:
673
 
            self.assertEqual(f.read(), 'hello2')
674
 
        with open(self.wt.abspath('name2'), 'r') as f:
675
 
            self.assertEqual(f.read(), 'hello1')
 
661
        self.assertEqual(file(self.wt.abspath('name1')).read(), 'hello2')
 
662
        self.assertEqual(file(self.wt.abspath('name2')).read(), 'hello1')
676
663
        mfile2_path = self.wt.abspath(pathjoin('new_directory', 'mfile2'))
677
664
        self.assertEqual(mangle_tree.final_parent(mfile2), newdir)
678
 
        with open(mfile2_path, 'r') as f:
679
 
            self.assertEqual(f.read(), 'later2')
 
665
        self.assertEqual(file(mfile2_path).read(), 'later2')
680
666
        self.assertEqual(self.wt.id2path(b'mfile2'), 'new_directory/mfile2')
681
667
        self.assertEqual(self.wt.path2id('new_directory/mfile2'), b'mfile2')
682
668
        newfile_path = self.wt.abspath(pathjoin('new_directory', 'newfile'))
683
 
        with open(newfile_path, 'r') as f:
684
 
            self.assertEqual(f.read(), 'hello3')
 
669
        self.assertEqual(file(newfile_path).read(), 'hello3')
685
670
        self.assertEqual(self.wt.path2id('dying_directory'), b'ddir')
686
671
        self.assertIs(self.wt.path2id('dying_directory/dying_file'), None)
687
672
        mfile2_path = self.wt.abspath(pathjoin('new_directory', 'mfile2'))
688
673
 
689
674
    def test_both_rename(self):
690
675
        create_tree, root = self.get_transform()
691
 
        newdir = create_tree.new_directory('selftest', root, b'selftest-id')
692
 
        create_tree.new_file('blackbox.py', newdir, [
693
 
                             b'hello1'], b'blackbox-id')
 
676
        newdir = create_tree.new_directory('selftest', root, 'selftest-id')
 
677
        create_tree.new_file('blackbox.py', newdir, 'hello1', 'blackbox-id')
694
678
        create_tree.apply()
695
679
        mangle_tree, root = self.get_transform()
696
680
        selftest = mangle_tree.trans_id_tree_path('selftest')
702
686
 
703
687
    def test_both_rename2(self):
704
688
        create_tree, root = self.get_transform()
705
 
        breezy = create_tree.new_directory('breezy', root, b'breezy-id')
706
 
        tests = create_tree.new_directory('tests', breezy, b'tests-id')
707
 
        blackbox = create_tree.new_directory('blackbox', tests, b'blackbox-id')
708
 
        create_tree.new_file('test_too_much.py', blackbox, [b'hello1'],
709
 
                             b'test_too_much-id')
 
689
        breezy = create_tree.new_directory('breezy', root, 'breezy-id')
 
690
        tests = create_tree.new_directory('tests', breezy, 'tests-id')
 
691
        blackbox = create_tree.new_directory('blackbox', tests, 'blackbox-id')
 
692
        create_tree.new_file('test_too_much.py', blackbox, 'hello1',
 
693
                             'test_too_much-id')
710
694
        create_tree.apply()
711
695
        mangle_tree, root = self.get_transform()
712
696
        breezy = mangle_tree.trans_id_tree_path('breezy')
713
697
        tests = mangle_tree.trans_id_tree_path('breezy/tests')
714
 
        test_too_much = mangle_tree.trans_id_tree_path(
715
 
            'breezy/tests/blackbox/test_too_much.py')
 
698
        test_too_much = mangle_tree.trans_id_tree_path('breezy/tests/blackbox/test_too_much.py')
716
699
        mangle_tree.adjust_path('selftest', breezy, tests)
717
700
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
718
701
        mangle_tree.set_executability(True, test_too_much)
720
703
 
721
704
    def test_both_rename3(self):
722
705
        create_tree, root = self.get_transform()
723
 
        tests = create_tree.new_directory('tests', root, b'tests-id')
724
 
        create_tree.new_file('test_too_much.py', tests, [b'hello1'],
725
 
                             b'test_too_much-id')
 
706
        tests = create_tree.new_directory('tests', root, 'tests-id')
 
707
        create_tree.new_file('test_too_much.py', tests, 'hello1',
 
708
                             'test_too_much-id')
726
709
        create_tree.apply()
727
710
        mangle_tree, root = self.get_transform()
728
711
        tests = mangle_tree.trans_id_tree_path('tests')
729
 
        test_too_much = mangle_tree.trans_id_tree_path(
730
 
            'tests/test_too_much.py')
 
712
        test_too_much = mangle_tree.trans_id_tree_path('tests/test_too_much.py')
731
713
        mangle_tree.adjust_path('selftest', root, tests)
732
714
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
733
715
        mangle_tree.set_executability(True, test_too_much)
737
719
        create_tree, root = self.get_transform()
738
720
        # prepare tree
739
721
        root = create_tree.root
740
 
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
 
722
        create_tree.new_file('name1', root, 'hello1', 'name1')
741
723
        create_tree.apply()
742
724
        delete_contents, root = self.get_transform()
743
725
        file = delete_contents.trans_id_tree_path('name1')
745
727
        delete_contents.apply()
746
728
        move_id, root = self.get_transform()
747
729
        name1 = move_id.trans_id_tree_path('name1')
748
 
        newdir = move_id.new_directory('dir', root, b'newdir')
 
730
        newdir = move_id.new_directory('dir', root, 'newdir')
749
731
        move_id.adjust_path('name2', newdir, name1)
750
732
        move_id.apply()
751
733
 
753
735
        create_tree, root = self.get_transform()
754
736
        # prepare tree
755
737
        root = create_tree.root
756
 
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
 
738
        create_tree.new_file('name1', root, 'hello1', 'name1')
757
739
        create_tree.apply()
758
740
        delete_contents = TreeTransform(self.wt)
759
741
        self.addCleanup(delete_contents.finalize)
763
745
        delete_contents.finalize()
764
746
        replace = TreeTransform(self.wt)
765
747
        self.addCleanup(replace.finalize)
766
 
        name2 = replace.new_file('name2', root, [b'hello2'], b'name1')
 
748
        name2 = replace.new_file('name2', root, 'hello2', 'name1')
767
749
        conflicts = replace.find_conflicts()
768
750
        name1 = replace.trans_id_tree_path('name1')
769
751
        self.assertEqual(conflicts, [('duplicate id', name1, name2)])
773
755
    def _test_symlinks(self, link_name1, link_target1,
774
756
                       link_name2, link_target2):
775
757
 
776
 
        def ozpath(p):
777
 
            return 'oz/' + p
 
758
        def ozpath(p): return 'oz/' + p
778
759
 
779
760
        self.requireFeature(SymlinkFeature)
780
761
        transform, root = self.get_transform()
781
 
        oz_id = transform.new_directory('oz', root, b'oz-id')
782
 
        transform.new_symlink(link_name1, oz_id, link_target1, b'wizard-id')
 
762
        oz_id = transform.new_directory('oz', root, 'oz-id')
 
763
        wizard = transform.new_symlink(link_name1, oz_id, link_target1,
 
764
                                       'wizard-id')
783
765
        wiz_id = transform.create_path(link_name2, oz_id)
784
766
        transform.create_symlink(link_target2, wiz_id)
785
 
        transform.version_file(b'wiz-id2', wiz_id)
 
767
        transform.version_file('wiz-id2', wiz_id)
786
768
        transform.set_executability(True, wiz_id)
787
769
        self.assertEqual(transform.find_conflicts(),
788
770
                         [('non-file executability', wiz_id)])
789
771
        transform.set_executability(None, wiz_id)
790
772
        transform.apply()
791
 
        self.assertEqual(self.wt.path2id(ozpath(link_name1)), b'wizard-id')
 
773
        self.assertEqual(self.wt.path2id(ozpath(link_name1)), 'wizard-id')
792
774
        self.assertEqual('symlink',
793
775
                         file_kind(self.wt.abspath(ozpath(link_name1))))
794
776
        self.assertEqual(link_target2,
807
789
                            u'\N{Euro Sign}wizard2',
808
790
                            u'b\N{Euro Sign}hind_curtain')
809
791
 
810
 
    def test_unsupported_symlink_no_conflict(self):
 
792
    def test_unable_create_symlink(self):
811
793
        def tt_helper():
812
794
            wt = self.make_branch_and_tree('.')
813
 
            tt = TreeTransform(wt)
814
 
            self.addCleanup(tt.finalize)
815
 
            tt.new_symlink('foo', tt.root, 'bar')
816
 
            result = tt.find_conflicts()
817
 
            self.assertEqual([], result)
 
795
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
 
796
            try:
 
797
                tt.new_symlink('foo', tt.root, 'bar')
 
798
                tt.apply()
 
799
            finally:
 
800
                wt.unlock()
818
801
        os_symlink = getattr(os, 'symlink', None)
819
802
        os.symlink = None
820
803
        try:
821
 
            tt_helper()
 
804
            err = self.assertRaises(errors.UnableCreateSymlink, tt_helper)
 
805
            self.assertEqual(
 
806
                "Unable to create symlink 'foo' on this platform",
 
807
                str(err))
822
808
        finally:
823
809
            if os_symlink:
824
810
                os.symlink = os_symlink
825
811
 
826
812
    def get_conflicted(self):
827
813
        create, root = self.get_transform()
828
 
        create.new_file('dorothy', root, [b'dorothy'], b'dorothy-id')
829
 
        oz = create.new_directory('oz', root, b'oz-id')
830
 
        create.new_directory('emeraldcity', oz, b'emerald-id')
 
814
        create.new_file('dorothy', root, 'dorothy', 'dorothy-id')
 
815
        oz = create.new_directory('oz', root, 'oz-id')
 
816
        create.new_directory('emeraldcity', oz, 'emerald-id')
831
817
        create.apply()
832
818
        conflicts, root = self.get_transform()
833
819
        # set up duplicate entry, duplicate id
834
 
        new_dorothy = conflicts.new_file('dorothy', root, [b'dorothy'],
835
 
                                         b'dorothy-id')
 
820
        new_dorothy = conflicts.new_file('dorothy', root, 'dorothy',
 
821
                                         'dorothy-id')
836
822
        old_dorothy = conflicts.trans_id_tree_path('dorothy')
837
823
        oz = conflicts.trans_id_tree_path('oz')
838
824
        # set up DeletedParent parent conflict
839
825
        conflicts.delete_versioned(oz)
840
826
        emerald = conflicts.trans_id_tree_path('oz/emeraldcity')
841
827
        # set up MissingParent conflict
842
 
        munchkincity = conflicts.trans_id_file_id(b'munchkincity-id')
 
828
        munchkincity = conflicts.trans_id_file_id('munchkincity-id')
843
829
        conflicts.adjust_path('munchkincity', root, munchkincity)
844
 
        conflicts.new_directory('auntem', munchkincity, b'auntem-id')
 
830
        conflicts.new_directory('auntem', munchkincity, 'auntem-id')
845
831
        # set up parent loop
846
832
        conflicts.adjust_path('emeraldcity', emerald, emerald)
847
833
        return conflicts, emerald, oz, old_dorothy, new_dorothy
853
839
        self.assertEqual(conflicts.final_name(old_dorothy), 'dorothy.moved')
854
840
        self.assertIs(conflicts.final_file_id(old_dorothy), None)
855
841
        self.assertEqual(conflicts.final_name(new_dorothy), 'dorothy')
856
 
        self.assertEqual(conflicts.final_file_id(new_dorothy), b'dorothy-id')
 
842
        self.assertEqual(conflicts.final_file_id(new_dorothy), 'dorothy-id')
857
843
        self.assertEqual(conflicts.final_parent(emerald), oz)
858
844
        conflicts.apply()
859
845
 
862
848
        raw_conflicts = resolve_conflicts(tt)
863
849
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
864
850
        duplicate = DuplicateEntry('Moved existing file to', 'dorothy.moved',
865
 
                                   'dorothy', None, b'dorothy-id')
 
851
                                   'dorothy', None, 'dorothy-id')
866
852
        self.assertEqual(cooked_conflicts[0], duplicate)
867
853
        duplicate_id = DuplicateID('Unversioned existing file',
868
854
                                   'dorothy.moved', 'dorothy', None,
869
 
                                   b'dorothy-id')
 
855
                                   'dorothy-id')
870
856
        self.assertEqual(cooked_conflicts[1], duplicate_id)
871
857
        missing_parent = MissingParent('Created directory', 'munchkincity',
872
 
                                       b'munchkincity-id')
873
 
        deleted_parent = DeletingParent('Not deleting', 'oz', b'oz-id')
 
858
                                       'munchkincity-id')
 
859
        deleted_parent = DeletingParent('Not deleting', 'oz', 'oz-id')
874
860
        self.assertEqual(cooked_conflicts[2], missing_parent)
875
861
        unversioned_parent = UnversionedParent('Versioned directory',
876
862
                                               'munchkincity',
877
 
                                               b'munchkincity-id')
 
863
                                               'munchkincity-id')
878
864
        unversioned_parent2 = UnversionedParent('Versioned directory', 'oz',
879
 
                                                b'oz-id')
 
865
                                               'oz-id')
880
866
        self.assertEqual(cooked_conflicts[3], unversioned_parent)
881
 
        parent_loop = ParentLoop(
882
 
            'Cancelled move', 'oz/emeraldcity',
883
 
            'oz/emeraldcity', b'emerald-id', b'emerald-id')
 
867
        parent_loop = ParentLoop('Cancelled move', 'oz/emeraldcity',
 
868
                                 'oz/emeraldcity', 'emerald-id', 'emerald-id')
884
869
        self.assertEqual(cooked_conflicts[4], deleted_parent)
885
870
        self.assertEqual(cooked_conflicts[5], unversioned_parent2)
886
871
        self.assertEqual(cooked_conflicts[6], parent_loop)
892
877
        raw_conflicts = resolve_conflicts(tt)
893
878
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
894
879
        tt.finalize()
895
 
        conflicts_s = [text_type(c) for c in cooked_conflicts]
 
880
        conflicts_s = [unicode(c) for c in cooked_conflicts]
896
881
        self.assertEqual(len(cooked_conflicts), len(conflicts_s))
897
882
        self.assertEqual(conflicts_s[0], 'Conflict adding file dorothy.  '
898
883
                                         'Moved existing file to '
905
890
        self.assertEqual(conflicts_s[3], 'Conflict because munchkincity is not'
906
891
                                         ' versioned, but has versioned'
907
892
                                         ' children.  Versioned directory.')
908
 
        self.assertEqualDiff(
909
 
            conflicts_s[4], "Conflict: can't delete oz because it"
910
 
                            " is not empty.  Not deleting.")
 
893
        self.assertEqualDiff(conflicts_s[4], "Conflict: can't delete oz because it"
 
894
                                         " is not empty.  Not deleting.")
911
895
        self.assertEqual(conflicts_s[5], 'Conflict because oz is not'
912
896
                                         ' versioned, but has versioned'
913
897
                                         ' children.  Versioned directory.')
916
900
 
917
901
    def prepare_wrong_parent_kind(self):
918
902
        tt, root = self.get_transform()
919
 
        tt.new_file('parent', root, [b'contents'], b'parent-id')
 
903
        tt.new_file('parent', root, 'contents', b'parent-id')
920
904
        tt.apply()
921
905
        tt, root = self.get_transform()
922
 
        parent_id = tt.trans_id_file_id(b'parent-id')
923
 
        tt.new_file('child,', parent_id, [b'contents2'], b'file-id')
 
906
        parent_id = tt.trans_id_file_id('parent-id')
 
907
        tt.new_file('child,', parent_id, 'contents2', b'file-id')
924
908
        return tt
925
909
 
926
910
    def test_find_conflicts_wrong_parent_kind(self):
931
915
        tt = self.prepare_wrong_parent_kind()
932
916
        raw_conflicts = resolve_conflicts(tt)
933
917
        self.assertEqual({('non-directory parent', 'Created directory',
934
 
                           'new-3')}, raw_conflicts)
 
918
                         'new-3')}, raw_conflicts)
935
919
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
936
920
        self.assertEqual([NonDirectoryParent('Created directory', 'parent.new',
937
 
                                             b'parent-id')], cooked_conflicts)
 
921
        b'parent-id')], cooked_conflicts)
938
922
        tt.apply()
939
923
        self.assertFalse(self.wt.is_versioned('parent'))
940
 
        self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
 
924
        self.assertEqual('parent-id', self.wt.path2id('parent.new'))
941
925
 
942
926
    def test_resolve_conflicts_wrong_new_parent_kind(self):
943
927
        tt, root = self.get_transform()
944
928
        parent_id = tt.new_directory('parent', root, b'parent-id')
945
 
        tt.new_file('child,', parent_id, [b'contents2'], b'file-id')
 
929
        tt.new_file('child,', parent_id, 'contents2', b'file-id')
946
930
        tt.apply()
947
931
        tt, root = self.get_transform()
948
 
        parent_id = tt.trans_id_file_id(b'parent-id')
 
932
        parent_id = tt.trans_id_file_id('parent-id')
949
933
        tt.delete_contents(parent_id)
950
 
        tt.create_file([b'contents'], parent_id)
 
934
        tt.create_file('contents', parent_id)
951
935
        raw_conflicts = resolve_conflicts(tt)
952
936
        self.assertEqual({('non-directory parent', 'Created directory',
953
 
                           'new-3')}, raw_conflicts)
 
937
                         'new-3')}, raw_conflicts)
954
938
        tt.apply()
955
939
        self.assertFalse(self.wt.is_versioned('parent'))
956
 
        self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
 
940
        self.assertEqual('parent-id', self.wt.path2id('parent.new'))
957
941
 
958
942
    def test_resolve_conflicts_wrong_parent_kind_unversioned(self):
959
943
        tt, root = self.get_transform()
960
944
        parent_id = tt.new_directory('parent', root)
961
 
        tt.new_file('child,', parent_id, [b'contents2'])
 
945
        tt.new_file('child,', parent_id, 'contents2')
962
946
        tt.apply()
963
947
        tt, root = self.get_transform()
964
948
        parent_id = tt.trans_id_tree_path('parent')
965
949
        tt.delete_contents(parent_id)
966
 
        tt.create_file([b'contents'], parent_id)
 
950
        tt.create_file('contents', parent_id)
967
951
        resolve_conflicts(tt)
968
952
        tt.apply()
969
953
        self.assertFalse(self.wt.is_versioned('parent'))
973
957
        wt = self.make_branch_and_tree('.')
974
958
        tt = TreeTransform(wt)
975
959
        self.addCleanup(tt.finalize)
976
 
        parent = tt.trans_id_file_id(b'parent-id')
977
 
        tt.new_file('file', parent, [b'Contents'])
 
960
        parent = tt.trans_id_file_id('parent-id')
 
961
        tt.new_file('file', parent, 'Contents')
978
962
        raw_conflicts = resolve_conflicts(tt)
979
963
        # Since the directory doesn't exist it's seen as 'missing'.  So
980
964
        # 'resolve_conflicts' create a conflict asking for it to be created.
986
970
 
987
971
    def test_moving_versioned_directories(self):
988
972
        create, root = self.get_transform()
989
 
        kansas = create.new_directory('kansas', root, b'kansas-id')
990
 
        create.new_directory('house', kansas, b'house-id')
991
 
        create.new_directory('oz', root, b'oz-id')
 
973
        kansas = create.new_directory('kansas', root, 'kansas-id')
 
974
        create.new_directory('house', kansas, 'house-id')
 
975
        create.new_directory('oz', root, 'oz-id')
992
976
        create.apply()
993
977
        cyclone, root = self.get_transform()
994
978
        oz = cyclone.trans_id_tree_path('oz')
998
982
 
999
983
    def test_moving_root(self):
1000
984
        create, root = self.get_transform()
1001
 
        fun = create.new_directory('fun', root, b'fun-id')
1002
 
        create.new_directory('sun', root, b'sun-id')
1003
 
        create.new_directory('moon', root, b'moon')
 
985
        fun = create.new_directory('fun', root, 'fun-id')
 
986
        create.new_directory('sun', root, 'sun-id')
 
987
        create.new_directory('moon', root, 'moon')
1004
988
        create.apply()
1005
989
        transform, root = self.get_transform()
1006
990
        transform.adjust_root_path('oldroot', fun)
1007
991
        new_root = transform.trans_id_tree_path('')
1008
 
        transform.version_file(b'new-root', new_root)
 
992
        transform.version_file('new-root', new_root)
1009
993
        transform.apply()
1010
994
 
1011
995
    def test_renames(self):
1012
996
        create, root = self.get_transform()
1013
 
        old = create.new_directory('old-parent', root, b'old-id')
1014
 
        intermediate = create.new_directory('intermediate', old, b'im-id')
1015
 
        myfile = create.new_file('myfile', intermediate, [b'myfile-text'],
1016
 
                                 b'myfile-id')
 
997
        old = create.new_directory('old-parent', root, 'old-id')
 
998
        intermediate = create.new_directory('intermediate', old, 'im-id')
 
999
        myfile = create.new_file('myfile', intermediate, 'myfile-text',
 
1000
                                 'myfile-id')
1017
1001
        create.apply()
1018
1002
        rename, root = self.get_transform()
1019
 
        old = rename.trans_id_file_id(b'old-id')
 
1003
        old = rename.trans_id_file_id('old-id')
1020
1004
        rename.adjust_path('new', root, old)
1021
 
        myfile = rename.trans_id_file_id(b'myfile-id')
 
1005
        myfile = rename.trans_id_file_id('myfile-id')
1022
1006
        rename.set_executability(True, myfile)
1023
1007
        rename.apply()
1024
1008
 
1026
1010
        self.requireFeature(features.not_running_as_root)
1027
1011
        # see https://bugs.launchpad.net/bzr/+bug/491763
1028
1012
        create, root_id = self.get_transform()
1029
 
        create.new_directory('first-dir', root_id, b'first-id')
1030
 
        create.new_file('myfile', root_id, [b'myfile-text'], b'myfile-id')
 
1013
        first_dir = create.new_directory('first-dir', root_id, 'first-id')
 
1014
        myfile = create.new_file('myfile', root_id, 'myfile-text',
 
1015
                                 'myfile-id')
1031
1016
        create.apply()
1032
1017
        if os.name == "posix" and sys.platform != "cygwin":
1033
1018
            # posix filesystems fail on renaming if the readonly bit is set
1034
1019
            osutils.make_readonly(self.wt.abspath('first-dir'))
1035
1020
        elif os.name == "nt":
1036
1021
            # windows filesystems fail on renaming open files
1037
 
            self.addCleanup(open(self.wt.abspath('myfile')).close)
 
1022
            self.addCleanup(file(self.wt.abspath('myfile')).close)
1038
1023
        else:
1039
1024
            self.skipTest("Can't force a permissions error on rename")
1040
1025
        # now transform to rename
1041
1026
        rename_transform, root_id = self.get_transform()
1042
 
        file_trans_id = rename_transform.trans_id_file_id(b'myfile-id')
1043
 
        dir_id = rename_transform.trans_id_file_id(b'first-id')
 
1027
        file_trans_id = rename_transform.trans_id_file_id('myfile-id')
 
1028
        dir_id = rename_transform.trans_id_file_id('first-id')
1044
1029
        rename_transform.adjust_path('newname', dir_id, file_trans_id)
1045
1030
        e = self.assertRaises(errors.TransformRenameFailed,
1046
 
                              rename_transform.apply)
1047
 
        # On nix looks like:
 
1031
            rename_transform.apply)
 
1032
        # On nix looks like: 
1048
1033
        # "Failed to rename .../work/.bzr/checkout/limbo/new-1
1049
1034
        # to .../first-dir/newname: [Errno 13] Permission denied"
1050
1035
        # On windows looks like:
1051
 
        # "Failed to rename .../work/myfile to
 
1036
        # "Failed to rename .../work/myfile to 
1052
1037
        # .../work/.bzr/checkout/limbo/new-1: [Errno 13] Permission denied"
1053
1038
        # This test isn't concerned with exactly what the error looks like,
1054
1039
        # and the strerror will vary across OS and locales, but the assert
1064
1049
 
1065
1050
        - create file and set executability simultaneously
1066
1051
        - create file and set executability afterward
1067
 
        - unsetting the executability of a file whose executability has not
1068
 
          been
 
1052
        - unsetting the executability of a file whose executability has not been
1069
1053
        declared should throw an exception (this may happen when a
1070
1054
        merge attempts to create a file with a duplicate ID)
1071
1055
        """
1073
1057
        wt = transform._tree
1074
1058
        wt.lock_read()
1075
1059
        self.addCleanup(wt.unlock)
1076
 
        transform.new_file('set_on_creation', root, [b'Set on creation'],
1077
 
                           b'soc', True)
 
1060
        transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
 
1061
                           True)
1078
1062
        sac = transform.new_file('set_after_creation', root,
1079
 
                                 [b'Set after creation'], b'sac')
 
1063
                                 'Set after creation', 'sac')
1080
1064
        transform.set_executability(True, sac)
1081
 
        uws = transform.new_file('unset_without_set', root, [b'Unset badly'],
1082
 
                                 b'uws')
 
1065
        uws = transform.new_file('unset_without_set', root, 'Unset badly',
 
1066
                                 'uws')
1083
1067
        self.assertRaises(KeyError, transform.set_executability, None, uws)
1084
1068
        transform.apply()
1085
1069
        self.assertTrue(wt.is_executable('set_on_creation'))
1090
1074
        if sys.platform == 'win32':
1091
1075
            raise TestSkipped('chmod has no effect on win32')
1092
1076
        transform, root = self.get_transform()
1093
 
        transform.new_file('file1', root, [b'contents'], b'file1-id', True)
 
1077
        transform.new_file('file1', root, 'contents', 'file1-id', True)
1094
1078
        transform.apply()
1095
1079
        self.wt.lock_write()
1096
1080
        self.addCleanup(self.wt.unlock)
1098
1082
        transform, root = self.get_transform()
1099
1083
        file1_id = transform.trans_id_tree_path('file1')
1100
1084
        transform.delete_contents(file1_id)
1101
 
        transform.create_file([b'contents2'], file1_id)
 
1085
        transform.create_file('contents2', file1_id)
1102
1086
        transform.apply()
1103
1087
        self.assertTrue(self.wt.is_executable('file1'))
1104
1088
 
1109
1093
 
1110
1094
        stat_paths = []
1111
1095
        real_stat = os.stat
1112
 
 
1113
1096
        def instrumented_stat(path):
1114
1097
            stat_paths.append(path)
1115
1098
            return real_stat(path)
1116
1099
 
1117
1100
        transform, root = self.get_transform()
1118
1101
 
1119
 
        bar1_id = transform.new_file('bar', root, [b'bar contents 1\n'],
1120
 
                                     file_id=b'bar-id-1', executable=False)
 
1102
        bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
 
1103
                                     file_id='bar-id-1', executable=False)
1121
1104
        transform.apply()
1122
1105
 
1123
1106
        transform, root = self.get_transform()
1125
1108
        bar2_id = transform.trans_id_tree_path('bar2')
1126
1109
        try:
1127
1110
            os.stat = instrumented_stat
1128
 
            transform.create_file([b'bar2 contents\n'],
1129
 
                                  bar2_id, mode_id=bar1_id)
 
1111
            transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
1130
1112
        finally:
1131
1113
            os.stat = real_stat
1132
1114
            transform.finalize()
1137
1119
    def test_iter_changes(self):
1138
1120
        self.wt.set_root_id(b'eert_toor')
1139
1121
        transform, root = self.get_transform()
1140
 
        transform.new_file('old', root, [b'blah'], b'id-1', True)
 
1122
        transform.new_file('old', root, 'blah', 'id-1', True)
1141
1123
        transform.apply()
1142
1124
        transform, root = self.get_transform()
1143
1125
        try:
1144
1126
            self.assertEqual([], list(transform.iter_changes()))
1145
1127
            old = transform.trans_id_tree_path('old')
1146
1128
            transform.unversion_file(old)
1147
 
            self.assertEqual([(b'id-1', ('old', None), False, (True, False),
1148
 
                               (b'eert_toor', b'eert_toor'),
1149
 
                               ('old', 'old'), ('file', 'file'),
1150
 
                               (True, True), False)],
1151
 
                             list(transform.iter_changes()))
1152
 
            transform.new_directory('new', root, b'id-1')
1153
 
            self.assertEqual([(b'id-1', ('old', 'new'), True, (True, True),
1154
 
                               (b'eert_toor', b'eert_toor'), ('old', 'new'),
1155
 
                               ('file', 'directory'),
1156
 
                               (True, False), False)],
1157
 
                             list(transform.iter_changes()))
 
1129
            self.assertEqual([('id-1', ('old', None), False, (True, False),
 
1130
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1131
                (True, True))], list(transform.iter_changes()))
 
1132
            transform.new_directory('new', root, 'id-1')
 
1133
            self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
 
1134
                ('eert_toor', 'eert_toor'), ('old', 'new'),
 
1135
                ('file', 'directory'),
 
1136
                (True, False))], list(transform.iter_changes()))
1158
1137
        finally:
1159
1138
            transform.finalize()
1160
1139
 
1161
1140
    def test_iter_changes_new(self):
1162
1141
        self.wt.set_root_id(b'eert_toor')
1163
1142
        transform, root = self.get_transform()
1164
 
        transform.new_file('old', root, [b'blah'])
 
1143
        transform.new_file('old', root, 'blah')
1165
1144
        transform.apply()
1166
1145
        transform, root = self.get_transform()
1167
1146
        try:
1168
1147
            old = transform.trans_id_tree_path('old')
1169
 
            transform.version_file(b'id-1', old)
1170
 
            self.assertEqual([(b'id-1', (None, 'old'), False, (False, True),
1171
 
                               (b'eert_toor', b'eert_toor'),
1172
 
                               ('old', 'old'), ('file', 'file'),
1173
 
                               (False, False), False)],
1174
 
                             list(transform.iter_changes()))
 
1148
            transform.version_file('id-1', old)
 
1149
            self.assertEqual([('id-1', (None, 'old'), False, (False, True),
 
1150
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1151
                (False, False))], list(transform.iter_changes()))
1175
1152
        finally:
1176
1153
            transform.finalize()
1177
1154
 
1178
1155
    def test_iter_changes_modifications(self):
1179
1156
        self.wt.set_root_id(b'eert_toor')
1180
1157
        transform, root = self.get_transform()
1181
 
        transform.new_file('old', root, [b'blah'], b'id-1')
1182
 
        transform.new_file('new', root, [b'blah'])
1183
 
        transform.new_directory('subdir', root, b'subdir-id')
 
1158
        transform.new_file('old', root, 'blah', 'id-1')
 
1159
        transform.new_file('new', root, 'blah')
 
1160
        transform.new_directory('subdir', root, 'subdir-id')
1184
1161
        transform.apply()
1185
1162
        transform, root = self.get_transform()
1186
1163
        try:
1189
1166
            new = transform.trans_id_tree_path('new')
1190
1167
            self.assertEqual([], list(transform.iter_changes()))
1191
1168
 
1192
 
            # content deletion
 
1169
            #content deletion
1193
1170
            transform.delete_contents(old)
1194
 
            self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1195
 
                               (b'eert_toor', b'eert_toor'),
1196
 
                               ('old', 'old'), ('file', None),
1197
 
                               (False, False), False)],
1198
 
                             list(transform.iter_changes()))
 
1171
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
 
1172
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
 
1173
                (False, False))], list(transform.iter_changes()))
1199
1174
 
1200
 
            # content change
1201
 
            transform.create_file([b'blah'], old)
1202
 
            self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1203
 
                               (b'eert_toor', b'eert_toor'),
1204
 
                               ('old', 'old'), ('file', 'file'),
1205
 
                               (False, False), False)],
1206
 
                             list(transform.iter_changes()))
 
1175
            #content change
 
1176
            transform.create_file('blah', old)
 
1177
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
 
1178
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1179
                (False, False))], list(transform.iter_changes()))
1207
1180
            transform.cancel_deletion(old)
1208
 
            self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1209
 
                               (b'eert_toor', b'eert_toor'),
1210
 
                               ('old', 'old'), ('file', 'file'),
1211
 
                               (False, False), False)],
1212
 
                             list(transform.iter_changes()))
 
1181
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
 
1182
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1183
                (False, False))], list(transform.iter_changes()))
1213
1184
            transform.cancel_creation(old)
1214
1185
 
1215
1186
            # move file_id to a different file
1216
1187
            self.assertEqual([], list(transform.iter_changes()))
1217
1188
            transform.unversion_file(old)
1218
 
            transform.version_file(b'id-1', new)
 
1189
            transform.version_file('id-1', new)
1219
1190
            transform.adjust_path('old', root, new)
1220
 
            self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1221
 
                               (b'eert_toor', b'eert_toor'),
1222
 
                               ('old', 'old'), ('file', 'file'),
1223
 
                               (False, False), False)],
1224
 
                             list(transform.iter_changes()))
 
1191
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
 
1192
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1193
                (False, False))], list(transform.iter_changes()))
1225
1194
            transform.cancel_versioning(new)
1226
1195
            transform._removed_id = set()
1227
1196
 
1228
 
            # execute bit
 
1197
            #execute bit
1229
1198
            self.assertEqual([], list(transform.iter_changes()))
1230
1199
            transform.set_executability(True, old)
1231
 
            self.assertEqual([(b'id-1', ('old', 'old'), False, (True, True),
1232
 
                               (b'eert_toor', b'eert_toor'),
1233
 
                               ('old', 'old'), ('file', 'file'),
1234
 
                               (False, True), False)],
1235
 
                             list(transform.iter_changes()))
 
1200
            self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
 
1201
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1202
                (False, True))], list(transform.iter_changes()))
1236
1203
            transform.set_executability(None, old)
1237
1204
 
1238
1205
            # filename
1239
1206
            self.assertEqual([], list(transform.iter_changes()))
1240
1207
            transform.adjust_path('new', root, old)
1241
1208
            transform._new_parent = {}
1242
 
            self.assertEqual([(b'id-1', ('old', 'new'), False, (True, True),
1243
 
                               (b'eert_toor', b'eert_toor'),
1244
 
                               ('old', 'new'), ('file', 'file'),
1245
 
                               (False, False), False)],
1246
 
                             list(transform.iter_changes()))
 
1209
            self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
 
1210
                ('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
 
1211
                (False, False))], list(transform.iter_changes()))
1247
1212
            transform._new_name = {}
1248
1213
 
1249
1214
            # parent directory
1250
1215
            self.assertEqual([], list(transform.iter_changes()))
1251
1216
            transform.adjust_path('new', subdir, old)
1252
1217
            transform._new_name = {}
1253
 
            self.assertEqual([(b'id-1', ('old', 'subdir/old'), False,
1254
 
                               (True, True), (b'eert_toor',
1255
 
                                              b'subdir-id'), ('old', 'old'),
1256
 
                               ('file', 'file'), (False, False), False)],
1257
 
                             list(transform.iter_changes()))
 
1218
            self.assertEqual([('id-1', ('old', 'subdir/old'), False,
 
1219
                (True, True), ('eert_toor', 'subdir-id'), ('old', 'old'),
 
1220
                ('file', 'file'), (False, False))],
 
1221
                list(transform.iter_changes()))
1258
1222
            transform._new_path = {}
1259
1223
 
1260
1224
        finally:
1268
1232
        # obviously can't bleed into file2's change output.  But for now, it
1269
1233
        # works.
1270
1234
        transform, root = self.get_transform()
1271
 
        transform.new_file('file1', root, [b'blah'], b'id-1')
1272
 
        transform.new_file('file2', root, [b'blah'], b'id-2')
 
1235
        transform.new_file('file1', root, 'blah', 'id-1')
 
1236
        transform.new_file('file2', root, 'blah', 'id-2')
1273
1237
        transform.apply()
1274
1238
        transform, root = self.get_transform()
1275
1239
        try:
1276
 
            transform.delete_contents(transform.trans_id_file_id(b'id-1'))
 
1240
            transform.delete_contents(transform.trans_id_file_id('id-1'))
1277
1241
            transform.set_executability(True,
1278
 
                                        transform.trans_id_file_id(b'id-2'))
1279
 
            self.assertEqual(
1280
 
                [(b'id-1', (u'file1', u'file1'), True, (True, True),
1281
 
                 (b'eert_toor', b'eert_toor'), ('file1', u'file1'),
1282
 
                 ('file', None), (False, False), False),
1283
 
                 (b'id-2', (u'file2', u'file2'), False, (True, True),
1284
 
                 (b'eert_toor', b'eert_toor'), ('file2', u'file2'),
1285
 
                 ('file', 'file'), (False, True), False)],
 
1242
            transform.trans_id_file_id('id-2'))
 
1243
            self.assertEqual([('id-1', (u'file1', u'file1'), True, (True, True),
 
1244
                ('eert_toor', 'eert_toor'), ('file1', u'file1'),
 
1245
                ('file', None), (False, False)),
 
1246
                ('id-2', (u'file2', u'file2'), False, (True, True),
 
1247
                ('eert_toor', 'eert_toor'), ('file2', u'file2'),
 
1248
                ('file', 'file'), (False, True))],
1286
1249
                list(transform.iter_changes()))
1287
1250
        finally:
1288
1251
            transform.finalize()
1292
1255
        self.wt.set_root_id(b'toor_eert')
1293
1256
        # Need two steps because versioning a non-existant file is a conflict.
1294
1257
        transform, root = self.get_transform()
1295
 
        transform.new_directory('floater', root, b'floater-id')
 
1258
        transform.new_directory('floater', root, 'floater-id')
1296
1259
        transform.apply()
1297
1260
        transform, root = self.get_transform()
1298
1261
        transform.delete_contents(transform.trans_id_tree_path('floater'))
1301
1264
        floater = transform.trans_id_tree_path('floater')
1302
1265
        try:
1303
1266
            transform.adjust_path('flitter', root, floater)
1304
 
            self.assertEqual([(b'floater-id', ('floater', 'flitter'), False,
1305
 
                               (True, True),
1306
 
                               (b'toor_eert', b'toor_eert'),
1307
 
                               ('floater', 'flitter'),
1308
 
                               (None, None), (False, False), False)],
1309
 
                             list(transform.iter_changes()))
 
1267
            self.assertEqual([('floater-id', ('floater', 'flitter'), False,
 
1268
            (True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
 
1269
            (None, None), (False, False))], list(transform.iter_changes()))
1310
1270
        finally:
1311
1271
            transform.finalize()
1312
1272
 
1314
1274
        """Ensure that no-ops are not treated as modifications"""
1315
1275
        self.wt.set_root_id(b'eert_toor')
1316
1276
        transform, root = self.get_transform()
1317
 
        transform.new_file('old', root, [b'blah'], b'id-1')
1318
 
        transform.new_directory('subdir', root, b'subdir-id')
 
1277
        transform.new_file('old', root, 'blah', 'id-1')
 
1278
        transform.new_directory('subdir', root, 'subdir-id')
1319
1279
        transform.apply()
1320
1280
        transform, root = self.get_transform()
1321
1281
        try:
1326
1286
            transform.create_directory(subdir)
1327
1287
            transform.set_executability(False, old)
1328
1288
            transform.unversion_file(old)
1329
 
            transform.version_file(b'id-1', old)
 
1289
            transform.version_file('id-1', old)
1330
1290
            transform.adjust_path('old', root, old)
1331
1291
            self.assertEqual([], list(transform.iter_changes()))
1332
1292
        finally:
1334
1294
 
1335
1295
    def test_rename_count(self):
1336
1296
        transform, root = self.get_transform()
1337
 
        transform.new_file('name1', root, [b'contents'])
 
1297
        transform.new_file('name1', root, 'contents')
1338
1298
        self.assertEqual(transform.rename_count, 0)
1339
1299
        transform.apply()
1340
1300
        self.assertEqual(transform.rename_count, 1)
1357
1317
        """
1358
1318
        transform, root = self.get_transform()
1359
1319
        parent1 = transform.new_directory('parent1', root)
1360
 
        child1 = transform.new_file('child1', parent1, [b'contents'])
 
1320
        child1 = transform.new_file('child1', parent1, 'contents')
1361
1321
        parent2 = transform.new_directory('parent2', root)
1362
1322
        transform.adjust_path('child1', parent2, child1)
1363
1323
        transform.apply()
1376
1336
        """
1377
1337
        transform, root = self.get_transform()
1378
1338
        parent1 = transform.new_directory('parent1', root)
1379
 
        child1 = transform.new_file('child1', parent1, [b'contents'])
1380
 
        child2 = transform.new_file('child2', parent1, [b'contents'])
 
1339
        child1 = transform.new_file('child1', parent1, 'contents')
 
1340
        child2 = transform.new_file('child2', parent1, 'contents')
1381
1341
        try:
1382
1342
            transform.cancel_creation(parent1)
1383
1343
        except OSError:
1403
1363
        """Make sure adjust_path keeps track of limbo children properly"""
1404
1364
        transform, root = self.get_transform()
1405
1365
        parent1 = transform.new_directory('parent1', root)
1406
 
        child1 = transform.new_file('child1', parent1, [b'contents'])
 
1366
        child1 = transform.new_file('child1', parent1, 'contents')
1407
1367
        parent2 = transform.new_directory('parent2', root)
1408
1368
        transform.adjust_path('child1', parent2, child1)
1409
1369
        transform.cancel_creation(child1)
1418
1378
    def test_noname_contents(self):
1419
1379
        """TreeTransform should permit deferring naming files."""
1420
1380
        transform, root = self.get_transform()
1421
 
        parent = transform.trans_id_file_id(b'parent-id')
 
1381
        parent = transform.trans_id_file_id('parent-id')
1422
1382
        try:
1423
1383
            transform.create_directory(parent)
1424
1384
        except KeyError:
1428
1388
    def test_noname_contents_nested(self):
1429
1389
        """TreeTransform should permit deferring naming files."""
1430
1390
        transform, root = self.get_transform()
1431
 
        parent = transform.trans_id_file_id(b'parent-id')
 
1391
        parent = transform.trans_id_file_id('parent-id')
1432
1392
        try:
1433
1393
            transform.create_directory(parent)
1434
1394
        except KeyError:
1435
1395
            self.fail("Can't handle contents with no name")
1436
 
        transform.new_directory('child', parent)
 
1396
        child = transform.new_directory('child', parent)
1437
1397
        transform.adjust_path('parent', root, parent)
1438
1398
        transform.apply()
1439
1399
        self.assertPathExists(self.wt.abspath('parent/child'))
1443
1403
        """Avoid reusing the same limbo name for different files"""
1444
1404
        transform, root = self.get_transform()
1445
1405
        parent = transform.new_directory('parent', root)
1446
 
        transform.new_directory('child', parent)
 
1406
        child1 = transform.new_directory('child', parent)
1447
1407
        try:
1448
1408
            child2 = transform.new_directory('child', parent)
1449
1409
        except OSError:
1463
1423
        parent = transform.new_directory('parent', root)
1464
1424
        child1 = transform.new_directory('child', parent)
1465
1425
        transform.adjust_path('child1', parent, child1)
1466
 
        transform.new_directory('child', parent)
 
1426
        child2 = transform.new_directory('child', parent)
1467
1427
        transform.apply()
1468
1428
        # limbo/new-1 => parent
1469
1429
        self.assertEqual(1, transform.rename_count)
1475
1435
        child1 = transform.new_directory('child1', parent2)
1476
1436
        transform.cancel_creation(parent2)
1477
1437
        transform.create_directory(parent2)
1478
 
        transform.new_directory('child1', parent2)
 
1438
        child2 = transform.new_directory('child1', parent2)
1479
1439
        transform.adjust_path('child2', parent2, child1)
1480
1440
        transform.apply()
1481
1441
        # limbo/new-1 => parent2, limbo/new-2 => parent2/child1
1485
1445
        """Finalize must be done in child-to-parent order"""
1486
1446
        transform, root = self.get_transform()
1487
1447
        parent = transform.new_directory('parent', root)
1488
 
        transform.new_directory('child', parent)
 
1448
        child = transform.new_directory('child', parent)
1489
1449
        try:
1490
1450
            transform.finalize()
1491
1451
        except OSError:
1505
1465
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
1506
1466
            try:
1507
1467
                foo = tt.new_directory('foo', tt.root)
1508
 
                tt.new_file('bar', foo, [b'foobar'])
 
1468
                tt.new_file('bar', foo, 'foobar')
1509
1469
                baz = tt.new_directory('baz', tt.root)
1510
 
                tt.new_file('qux', baz, [b'quux'])
 
1470
                tt.new_file('qux', baz, 'quux')
1511
1471
                # Ask for a rename 'foo' -> 'baz'
1512
1472
                tt.adjust_path('baz', tt.root, foo)
1513
1473
                # Lie to tt that we've already resolved all conflicts.
1514
1474
                tt.apply(no_conflicts=True)
1515
 
            except BaseException:
 
1475
            except:
1516
1476
                wt.unlock()
1517
1477
                raise
1518
1478
        # The rename will fail because the target directory is not empty (but
1532
1492
                tt.new_directory('baz', foo_2)
1533
1493
                # Lie to tt that we've already resolved all conflicts.
1534
1494
                tt.apply(no_conflicts=True)
1535
 
            except BaseException:
 
1495
            except:
1536
1496
                wt.unlock()
1537
1497
                raise
1538
1498
        err = self.assertRaises(errors.FileExists, tt_helper)
1550
1510
                tt.new_directory('baz', foo_2)
1551
1511
                # Lie to tt that we've already resolved all conflicts.
1552
1512
                tt.apply(no_conflicts=True)
1553
 
            except BaseException:
 
1513
            except:
1554
1514
                tt.finalize()
1555
1515
                raise
1556
1516
        err = self.assertRaises(errors.FileExists, tt_helper)
1567
1527
        tt.delete_contents(foo_trans_id)
1568
1528
        tt.create_directory(foo_trans_id)
1569
1529
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1570
 
        tt.create_file([b"aa\n"], bar_trans_id)
1571
 
        tt.version_file(b"bar-1", bar_trans_id)
 
1530
        tt.create_file(["aa\n"], bar_trans_id)
 
1531
        tt.version_file("bar-1", bar_trans_id)
1572
1532
        tt.apply()
1573
1533
        self.assertPathExists("foo/bar")
1574
1534
        wt.lock_read()
1597
1557
        self.addCleanup(wt.unlock)
1598
1558
        self.assertEqual(wt.kind("foo"), "symlink")
1599
1559
 
1600
 
    def test_file_to_symlink_unsupported(self):
1601
 
        wt = self.make_branch_and_tree('.')
1602
 
        self.build_tree(['foo'])
1603
 
        wt.add(['foo'])
1604
 
        wt.commit("one")
1605
 
        self.overrideAttr(osutils, 'supports_symlinks', lambda p: False)
1606
 
        tt = TreeTransform(wt)
1607
 
        self.addCleanup(tt.finalize)
1608
 
        foo_trans_id = tt.trans_id_tree_path("foo")
1609
 
        tt.delete_contents(foo_trans_id)
1610
 
        log = BytesIO()
1611
 
        trace.push_log_file(log)
1612
 
        tt.create_symlink("bar", foo_trans_id)
1613
 
        tt.apply()
1614
 
        self.assertContainsRe(
1615
 
            log.getvalue(),
1616
 
            b'Unable to create symlink "foo" on this filesystem')
1617
 
 
1618
1560
    def test_dir_to_file(self):
1619
1561
        wt = self.make_branch_and_tree('.')
1620
1562
        self.build_tree(['foo/', 'foo/bar'])
1626
1568
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1627
1569
        tt.delete_contents(foo_trans_id)
1628
1570
        tt.delete_versioned(bar_trans_id)
1629
 
        tt.create_file([b"aa\n"], foo_trans_id)
 
1571
        tt.create_file(["aa\n"], foo_trans_id)
1630
1572
        tt.apply()
1631
1573
        self.assertPathExists("foo")
1632
1574
        wt.lock_read()
1656
1598
 
1657
1599
    def test_no_final_path(self):
1658
1600
        transform, root = self.get_transform()
1659
 
        trans_id = transform.trans_id_file_id(b'foo')
1660
 
        transform.create_file([b'bar'], trans_id)
 
1601
        trans_id = transform.trans_id_file_id('foo')
 
1602
        transform.create_file('bar', trans_id)
1661
1603
        transform.cancel_creation(trans_id)
1662
1604
        transform.apply()
1663
1605
 
1668
1610
        tree2 = self.make_branch_and_tree('tree2')
1669
1611
        tt = TreeTransform(tree2)
1670
1612
        foo_trans_id = tt.create_path('foo', tt.root)
1671
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo')
 
1613
        create_from_tree(tt, foo_trans_id, tree1, 'foo', file_id=b'foo-id')
1672
1614
        bar_trans_id = tt.create_path('bar', tt.root)
1673
 
        create_from_tree(tt, bar_trans_id, tree1, 'bar')
 
1615
        create_from_tree(tt, bar_trans_id, tree1, 'bar', file_id='bbar-id')
1674
1616
        tt.apply()
1675
1617
        self.assertEqual('directory', osutils.file_kind('tree2/foo'))
1676
 
        self.assertFileEqual(b'baz', 'tree2/bar')
 
1618
        self.assertFileEqual('baz', 'tree2/bar')
1677
1619
 
1678
1620
    def test_create_from_tree_bytes(self):
1679
1621
        """Provided lines are used instead of tree content."""
1680
1622
        tree1 = self.make_branch_and_tree('tree1')
1681
 
        self.build_tree_contents([('tree1/foo', b'bar'), ])
 
1623
        self.build_tree_contents([('tree1/foo', 'bar'),])
1682
1624
        tree1.add('foo', b'foo-id')
1683
1625
        tree2 = self.make_branch_and_tree('tree2')
1684
1626
        tt = TreeTransform(tree2)
1685
1627
        foo_trans_id = tt.create_path('foo', tt.root)
1686
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo', chunks=[b'qux'])
 
1628
        create_from_tree(tt, foo_trans_id, tree1, 'foo', file_id=b'foo-id',
 
1629
                         bytes='qux')
1687
1630
        tt.apply()
1688
 
        self.assertFileEqual(b'qux', 'tree2/foo')
 
1631
        self.assertFileEqual('qux', 'tree2/foo')
1689
1632
 
1690
1633
    def test_create_from_tree_symlink(self):
1691
1634
        self.requireFeature(SymlinkFeature)
1694
1637
        tree1.add('foo', b'foo-id')
1695
1638
        tt = TreeTransform(self.make_branch_and_tree('tree2'))
1696
1639
        foo_trans_id = tt.create_path('foo', tt.root)
1697
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo')
 
1640
        create_from_tree(tt, foo_trans_id, tree1, 'foo', file_id=b'foo-id')
1698
1641
        tt.apply()
1699
1642
        self.assertEqual('bar', os.readlink('tree2/foo'))
1700
1643
 
1712
1655
 
1713
1656
 
1714
1657
def conflict_text(tree, merge):
1715
 
    template = b'%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
1716
 
    return template % (b'<' * 7, tree, b'=' * 7, merge, b'>' * 7)
 
1658
    template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
 
1659
    return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
1717
1660
 
1718
1661
 
1719
1662
class TestInventoryAltered(tests.TestCaseWithTransport):
1743
1686
        tree.add('foo', b'foo-id')
1744
1687
        with TransformPreview(tree) as tt:
1745
1688
            tt.unversion_file(tt.root)
1746
 
            tt.version_file(tree.path2id(''), tt.root)
1747
 
            tt.trans_id_tree_path('foo')
 
1689
            tt.version_file(tree.get_root_id(), tt.root)
 
1690
            foo_trans_id = tt.trans_id_tree_path('foo')
1748
1691
            self.assertEqual([], tt._inventory_altered())
1749
1692
 
1750
1693
 
1753
1696
    def test_text_merge(self):
1754
1697
        root_id = generate_ids.gen_root_id()
1755
1698
        base = TransformGroup("base", root_id)
1756
 
        base.tt.new_file('a', base.root, [b'a\nb\nc\nd\be\n'], b'a')
1757
 
        base.tt.new_file('b', base.root, [b'b1'], b'b')
1758
 
        base.tt.new_file('c', base.root, [b'c'], b'c')
1759
 
        base.tt.new_file('d', base.root, [b'd'], b'd')
1760
 
        base.tt.new_file('e', base.root, [b'e'], b'e')
1761
 
        base.tt.new_file('f', base.root, [b'f'], b'f')
1762
 
        base.tt.new_directory('g', base.root, b'g')
1763
 
        base.tt.new_directory('h', base.root, b'h')
 
1699
        base.tt.new_file('a', base.root, 'a\nb\nc\nd\be\n', 'a')
 
1700
        base.tt.new_file('b', base.root, 'b1', 'b')
 
1701
        base.tt.new_file('c', base.root, 'c', 'c')
 
1702
        base.tt.new_file('d', base.root, 'd', 'd')
 
1703
        base.tt.new_file('e', base.root, 'e', 'e')
 
1704
        base.tt.new_file('f', base.root, 'f', 'f')
 
1705
        base.tt.new_directory('g', base.root, 'g')
 
1706
        base.tt.new_directory('h', base.root, 'h')
1764
1707
        base.tt.apply()
1765
1708
        other = TransformGroup("other", root_id)
1766
 
        other.tt.new_file('a', other.root, [b'y\nb\nc\nd\be\n'], b'a')
1767
 
        other.tt.new_file('b', other.root, [b'b2'], b'b')
1768
 
        other.tt.new_file('c', other.root, [b'c2'], b'c')
1769
 
        other.tt.new_file('d', other.root, [b'd'], b'd')
1770
 
        other.tt.new_file('e', other.root, [b'e2'], b'e')
1771
 
        other.tt.new_file('f', other.root, [b'f'], b'f')
1772
 
        other.tt.new_file('g', other.root, [b'g'], b'g')
1773
 
        other.tt.new_file('h', other.root, [b'h\ni\nj\nk\n'], b'h')
1774
 
        other.tt.new_file('i', other.root, [b'h\ni\nj\nk\n'], b'i')
 
1709
        other.tt.new_file('a', other.root, 'y\nb\nc\nd\be\n', 'a')
 
1710
        other.tt.new_file('b', other.root, 'b2', 'b')
 
1711
        other.tt.new_file('c', other.root, 'c2', 'c')
 
1712
        other.tt.new_file('d', other.root, 'd', 'd')
 
1713
        other.tt.new_file('e', other.root, 'e2', 'e')
 
1714
        other.tt.new_file('f', other.root, 'f', 'f')
 
1715
        other.tt.new_file('g', other.root, 'g', 'g')
 
1716
        other.tt.new_file('h', other.root, 'h\ni\nj\nk\n', 'h')
 
1717
        other.tt.new_file('i', other.root, 'h\ni\nj\nk\n', 'i')
1775
1718
        other.tt.apply()
1776
1719
        this = TransformGroup("this", root_id)
1777
 
        this.tt.new_file('a', this.root, [b'a\nb\nc\nd\bz\n'], b'a')
1778
 
        this.tt.new_file('b', this.root, [b'b'], b'b')
1779
 
        this.tt.new_file('c', this.root, [b'c'], b'c')
1780
 
        this.tt.new_file('d', this.root, [b'd2'], b'd')
1781
 
        this.tt.new_file('e', this.root, [b'e2'], b'e')
1782
 
        this.tt.new_file('f', this.root, [b'f'], b'f')
1783
 
        this.tt.new_file('g', this.root, [b'g'], b'g')
1784
 
        this.tt.new_file('h', this.root, [b'1\n2\n3\n4\n'], b'h')
1785
 
        this.tt.new_file('i', this.root, [b'1\n2\n3\n4\n'], b'i')
 
1720
        this.tt.new_file('a', this.root, 'a\nb\nc\nd\bz\n', 'a')
 
1721
        this.tt.new_file('b', this.root, 'b', 'b')
 
1722
        this.tt.new_file('c', this.root, 'c', 'c')
 
1723
        this.tt.new_file('d', this.root, 'd2', 'd')
 
1724
        this.tt.new_file('e', this.root, 'e2', 'e')
 
1725
        this.tt.new_file('f', this.root, 'f', 'f')
 
1726
        this.tt.new_file('g', this.root, 'g', 'g')
 
1727
        this.tt.new_file('h', this.root, '1\n2\n3\n4\n', 'h')
 
1728
        this.tt.new_file('i', this.root, '1\n2\n3\n4\n', 'i')
1786
1729
        this.tt.apply()
1787
1730
        Merge3Merger(this.wt, this.wt, base.wt, other.wt)
1788
1731
 
1789
1732
        # textual merge
1790
 
        with this.wt.get_file(this.wt.id2path(b'a')) as f:
1791
 
            self.assertEqual(f.read(), b'y\nb\nc\nd\bz\n')
 
1733
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'a')).read(), 'y\nb\nc\nd\bz\n')
1792
1734
        # three-way text conflict
1793
 
        with this.wt.get_file(this.wt.id2path(b'b')) as f:
1794
 
            self.assertEqual(f.read(), conflict_text(b'b', b'b2'))
 
1735
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'b')).read(),
 
1736
                         conflict_text('b', 'b2'))
1795
1737
        # OTHER wins
1796
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'c')).read(), b'c2')
 
1738
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'c')).read(), 'c2')
1797
1739
        # THIS wins
1798
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'd')).read(), b'd2')
 
1740
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'd')).read(), 'd2')
1799
1741
        # Ambigious clean merge
1800
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'e')).read(), b'e2')
 
1742
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'e')).read(), 'e2')
1801
1743
        # No change
1802
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'f')).read(), b'f')
 
1744
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'f')).read(), 'f')
1803
1745
        # Correct correct results when THIS == OTHER
1804
 
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'g')).read(), b'g')
 
1746
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'g')).read(), 'g')
1805
1747
        # Text conflict when THIS & OTHER are text and BASE is dir
1806
1748
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'h')).read(),
1807
 
                         conflict_text(b'1\n2\n3\n4\n', b'h\ni\nj\nk\n'))
 
1749
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
1808
1750
        self.assertEqual(this.wt.get_file('h.THIS').read(),
1809
 
                         b'1\n2\n3\n4\n')
 
1751
                         '1\n2\n3\n4\n')
1810
1752
        self.assertEqual(this.wt.get_file('h.OTHER').read(),
1811
 
                         b'h\ni\nj\nk\n')
 
1753
                         'h\ni\nj\nk\n')
1812
1754
        self.assertEqual(file_kind(this.wt.abspath('h.BASE')), 'directory')
1813
1755
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'i')).read(),
1814
 
                         conflict_text(b'1\n2\n3\n4\n', b'h\ni\nj\nk\n'))
 
1756
                         conflict_text('1\n2\n3\n4\n', 'h\ni\nj\nk\n'))
1815
1757
        self.assertEqual(this.wt.get_file('i.THIS').read(),
1816
 
                         b'1\n2\n3\n4\n')
 
1758
                         '1\n2\n3\n4\n')
1817
1759
        self.assertEqual(this.wt.get_file('i.OTHER').read(),
1818
 
                         b'h\ni\nj\nk\n')
 
1760
                         'h\ni\nj\nk\n')
1819
1761
        self.assertEqual(os.path.exists(this.wt.abspath('i.BASE')), False)
1820
1762
        modified = ['a', 'b', 'c', 'h', 'i']
1821
1763
        merge_modified = this.wt.merge_modified()
1822
1764
        self.assertSubset(merge_modified, modified)
1823
1765
        self.assertEqual(len(merge_modified), len(modified))
1824
 
        with open(this.wt.abspath(this.wt.id2path(b'a')), 'wb') as f:
1825
 
            f.write(b'booga')
 
1766
        with file(this.wt.abspath(this.wt.id2path('a')), 'wb') as f: f.write('booga')
1826
1767
        modified.pop(0)
1827
1768
        merge_modified = this.wt.merge_modified()
1828
1769
        self.assertSubset(merge_modified, modified)
1837
1778
        this = TransformGroup("THIS", root_id)
1838
1779
        other = TransformGroup("OTHER", root_id)
1839
1780
        for tg in this, base, other:
1840
 
            tg.tt.new_directory('a', tg.root, b'a')
1841
 
            tg.tt.new_symlink('b', tg.root, 'b', b'b')
1842
 
            tg.tt.new_file('c', tg.root, [b'c'], b'c')
1843
 
            tg.tt.new_symlink('d', tg.root, tg.name, b'd')
 
1781
            tg.tt.new_directory('a', tg.root, 'a')
 
1782
            tg.tt.new_symlink('b', tg.root, 'b', 'b')
 
1783
            tg.tt.new_file('c', tg.root, 'c', 'c')
 
1784
            tg.tt.new_symlink('d', tg.root, tg.name, 'd')
1844
1785
        targets = ((base, 'base-e', 'base-f', None, None),
1845
1786
                   (this, 'other-e', 'this-f', 'other-g', 'this-h'),
1846
1787
                   (other, 'other-e', None, 'other-g', 'other-h'))
1848
1789
            for link, target in (('e', e_target), ('f', f_target),
1849
1790
                                 ('g', g_target), ('h', h_target)):
1850
1791
                if target is not None:
1851
 
                    tg.tt.new_symlink(link, tg.root, target,
1852
 
                                      link.encode('ascii'))
 
1792
                    tg.tt.new_symlink(link, tg.root, target, link)
1853
1793
 
1854
1794
        for tg in this, base, other:
1855
1795
            tg.tt.apply()
1858
1798
        self.assertIs(os.path.islink(this.wt.abspath('b')), True)
1859
1799
        self.assertIs(os.path.isfile(this.wt.abspath('c')), True)
1860
1800
        for suffix in ('THIS', 'BASE', 'OTHER'):
1861
 
            self.assertEqual(os.readlink(
1862
 
                this.wt.abspath('d.' + suffix)), suffix)
 
1801
            self.assertEqual(os.readlink(this.wt.abspath('d.'+suffix)), suffix)
1863
1802
        self.assertIs(os.path.lexists(this.wt.abspath('d')), False)
1864
1803
        self.assertEqual(this.wt.id2path(b'd'), 'd.OTHER')
1865
1804
        self.assertEqual(this.wt.id2path(b'f'), 'f.THIS')
1879
1818
        base = TransformGroup("BASE", root_id)
1880
1819
        this = TransformGroup("THIS", root_id)
1881
1820
        other = TransformGroup("OTHER", root_id)
1882
 
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, b'a')
1883
 
                                   for t in [base, this, other]]
1884
 
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, b'b')
1885
 
                                   for t in [base, this, other]]
1886
 
        base.tt.new_directory('c', base_a, b'c')
1887
 
        this.tt.new_directory('c1', this_a, b'c')
1888
 
        other.tt.new_directory('c', other_b, b'c')
1889
 
 
1890
 
        base.tt.new_directory('d', base_a, b'd')
1891
 
        this.tt.new_directory('d1', this_b, b'd')
1892
 
        other.tt.new_directory('d', other_a, b'd')
1893
 
 
1894
 
        base.tt.new_directory('e', base_a, b'e')
1895
 
        this.tt.new_directory('e', this_a, b'e')
1896
 
        other.tt.new_directory('e1', other_b, b'e')
1897
 
 
1898
 
        base.tt.new_directory('f', base_a, b'f')
1899
 
        this.tt.new_directory('f1', this_b, b'f')
1900
 
        other.tt.new_directory('f1', other_b, b'f')
 
1821
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a')
 
1822
                                   for t in [base, this, other]]
 
1823
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b')
 
1824
                                   for t in [base, this, other]]
 
1825
        base.tt.new_directory('c', base_a, 'c')
 
1826
        this.tt.new_directory('c1', this_a, 'c')
 
1827
        other.tt.new_directory('c', other_b, 'c')
 
1828
 
 
1829
        base.tt.new_directory('d', base_a, 'd')
 
1830
        this.tt.new_directory('d1', this_b, 'd')
 
1831
        other.tt.new_directory('d', other_a, 'd')
 
1832
 
 
1833
        base.tt.new_directory('e', base_a, 'e')
 
1834
        this.tt.new_directory('e', this_a, 'e')
 
1835
        other.tt.new_directory('e1', other_b, 'e')
 
1836
 
 
1837
        base.tt.new_directory('f', base_a, 'f')
 
1838
        this.tt.new_directory('f1', this_b, 'f')
 
1839
        other.tt.new_directory('f1', other_b, 'f')
1901
1840
 
1902
1841
        for tg in [this, base, other]:
1903
1842
            tg.tt.apply()
1912
1851
        base = TransformGroup("BASE", root_id)
1913
1852
        this = TransformGroup("THIS", root_id)
1914
1853
        other = TransformGroup("OTHER", root_id)
1915
 
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, b'a')
1916
 
                                   for t in [base, this, other]]
1917
 
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, b'b')
1918
 
                                   for t in [base, this, other]]
1919
 
 
1920
 
        base.tt.new_file('g', base_a, [b'g'], b'g')
1921
 
        other.tt.new_file('g1', other_b, [b'g1'], b'g')
1922
 
 
1923
 
        base.tt.new_file('h', base_a, [b'h'], b'h')
1924
 
        this.tt.new_file('h1', this_b, [b'h1'], b'h')
1925
 
 
1926
 
        base.tt.new_file('i', base.root, [b'i'], b'i')
1927
 
        other.tt.new_directory('i1', this_b, b'i')
 
1854
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a')
 
1855
                                   for t in [base, this, other]]
 
1856
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b')
 
1857
                                   for t in [base, this, other]]
 
1858
 
 
1859
        base.tt.new_file('g', base_a, 'g', 'g')
 
1860
        other.tt.new_file('g1', other_b, 'g1', 'g')
 
1861
 
 
1862
        base.tt.new_file('h', base_a, 'h', 'h')
 
1863
        this.tt.new_file('h1', this_b, 'h1', 'h')
 
1864
 
 
1865
        base.tt.new_file('i', base.root, 'i', 'i')
 
1866
        other.tt.new_directory('i1', this_b, 'i')
1928
1867
 
1929
1868
        for tg in [this, base, other]:
1930
1869
            tg.tt.apply()
1946
1885
        os.mkdir('a')
1947
1886
        a = ControlDir.create_standalone_workingtree('a')
1948
1887
        os.mkdir('a/foo')
1949
 
        with open('a/foo/bar', 'wb') as f:
1950
 
            f.write(b'contents')
 
1888
        with file('a/foo/bar', 'wb') as f: f.write('contents')
1951
1889
        os.symlink('a/foo/bar', 'a/foo/baz')
1952
1890
        a.add(['foo', 'foo/bar', 'foo/baz'])
1953
1891
        a.commit('initial commit')
1957
1895
        self.addCleanup(basis.unlock)
1958
1896
        build_tree(basis, b)
1959
1897
        self.assertIs(os.path.isdir('b/foo'), True)
1960
 
        with open('b/foo/bar', 'rb') as f:
1961
 
            self.assertEqual(f.read(), b"contents")
 
1898
        self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
1962
1899
        self.assertEqual(os.readlink('b/foo/baz'), 'a/foo/bar')
1963
1900
 
1964
1901
    def test_build_with_references(self):
1965
1902
        tree = self.make_branch_and_tree('source',
1966
 
                                         format='development-subtree')
 
1903
            format='development-subtree')
1967
1904
        subtree = self.make_branch_and_tree('source/subtree',
1968
 
                                            format='development-subtree')
 
1905
            format='development-subtree')
1969
1906
        tree.add_reference(subtree)
1970
1907
        tree.commit('a revision')
1971
1908
        tree.branch.create_checkout('target')
1977
1914
        source = self.make_branch_and_tree('source')
1978
1915
        target = self.make_branch_and_tree('target')
1979
1916
        self.build_tree(['source/file', 'target/file'])
1980
 
        source.add('file', b'new-file')
 
1917
        source.add('file', 'new-file')
1981
1918
        source.commit('added file')
1982
1919
        build_tree(source.basis_tree(), target)
1983
 
        self.assertEqual(
1984
 
            [DuplicateEntry('Moved existing file to', 'file.moved',
1985
 
                            'file', None, 'new-file')],
1986
 
            target.conflicts())
 
1920
        self.assertEqual([DuplicateEntry('Moved existing file to',
 
1921
                          'file.moved', 'file', None, 'new-file')],
 
1922
                         target.conflicts())
1987
1923
        target2 = self.make_branch_and_tree('target2')
1988
 
        with open('target2/file', 'wb') as target_file, \
1989
 
                open('source/file', 'rb') as source_file:
1990
 
            target_file.write(source_file.read())
 
1924
        target_file = file('target2/file', 'wb')
 
1925
        try:
 
1926
            source_file = file('source/file', 'rb')
 
1927
            try:
 
1928
                target_file.write(source_file.read())
 
1929
            finally:
 
1930
                source_file.close()
 
1931
        finally:
 
1932
            target_file.close()
1991
1933
        build_tree(source.basis_tree(), target2)
1992
1934
        self.assertEqual([], target2.conflicts())
1993
1935
 
1996
1938
        self.requireFeature(SymlinkFeature)
1997
1939
        source = self.make_branch_and_tree('source')
1998
1940
        os.symlink('foo', 'source/symlink')
1999
 
        source.add('symlink', b'new-symlink')
 
1941
        source.add('symlink', 'new-symlink')
2000
1942
        source.commit('added file')
2001
1943
        target = self.make_branch_and_tree('target')
2002
1944
        os.symlink('bar', 'target/symlink')
2003
1945
        build_tree(source.basis_tree(), target)
2004
 
        self.assertEqual(
2005
 
            [DuplicateEntry('Moved existing file to', 'symlink.moved',
2006
 
                            'symlink', None, 'new-symlink')],
 
1946
        self.assertEqual([DuplicateEntry('Moved existing file to',
 
1947
            'symlink.moved', 'symlink', None, 'new-symlink')],
2007
1948
            target.conflicts())
2008
1949
        target = self.make_branch_and_tree('target2')
2009
1950
        os.symlink('foo', 'target2/symlink')
2015
1956
        source = self.make_branch_and_tree('source')
2016
1957
        target = self.make_branch_and_tree('target')
2017
1958
        self.build_tree(['source/dir1/', 'source/dir1/file', 'target/dir1/'])
2018
 
        source.add(['dir1', 'dir1/file'], [b'new-dir1', b'new-file'])
 
1959
        source.add(['dir1', 'dir1/file'], ['new-dir1', 'new-file'])
2019
1960
        source.commit('added file')
2020
1961
        build_tree(source.basis_tree(), target)
2021
1962
        self.assertEqual([], target.conflicts())
2037
1978
        self.assertPathDoesNotExist('target3/dir1/file')
2038
1979
        self.assertPathExists('target3/dir1/file2')
2039
1980
        self.assertPathExists('target3/dir1.diverted/file')
2040
 
        self.assertEqual(
2041
 
            [DuplicateEntry('Diverted to', 'dir1.diverted',
2042
 
                            'dir1', 'new-dir1', None)],
 
1981
        self.assertEqual([DuplicateEntry('Diverted to',
 
1982
            'dir1.diverted', 'dir1', 'new-dir1', None)],
2043
1983
            target.conflicts())
2044
1984
 
2045
1985
        target = self.make_branch_and_tree('target4')
2049
1989
        self.assertPathExists('target4/dir1/file')
2050
1990
        self.assertEqual('directory', file_kind('target4/dir1/file'))
2051
1991
        self.assertPathExists('target4/dir1/file.diverted')
2052
 
        self.assertEqual(
2053
 
            [DuplicateEntry('Diverted to', 'dir1/file.diverted',
2054
 
                            'dir1/file', 'new-file', None)],
 
1992
        self.assertEqual([DuplicateEntry('Diverted to',
 
1993
            'dir1/file.diverted', 'dir1/file', 'new-file', None)],
2055
1994
            target.conflicts())
2056
1995
 
2057
1996
    def test_mixed_conflict_handling(self):
2059
1998
        source = self.make_branch_and_tree('source')
2060
1999
        target = self.make_branch_and_tree('target')
2061
2000
        self.build_tree(['source/name', 'target/name/'])
2062
 
        source.add('name', b'new-name')
 
2001
        source.add('name', 'new-name')
2063
2002
        source.commit('added file')
2064
2003
        build_tree(source.basis_tree(), target)
2065
 
        self.assertEqual(
2066
 
            [DuplicateEntry('Moved existing file to',
2067
 
                            'name.moved', 'name', None, 'new-name')],
2068
 
            target.conflicts())
 
2004
        self.assertEqual([DuplicateEntry('Moved existing file to',
 
2005
            'name.moved', 'name', None, 'new-name')], target.conflicts())
2069
2006
 
2070
2007
    def test_raises_in_populated(self):
2071
2008
        source = self.make_branch_and_tree('source')
2076
2013
        self.build_tree(['target/name'])
2077
2014
        target.add('name')
2078
2015
        self.assertRaises(errors.WorkingTreeAlreadyPopulated,
2079
 
                          build_tree, source.basis_tree(), target)
 
2016
            build_tree, source.basis_tree(), target)
2080
2017
 
2081
2018
    def test_build_tree_rename_count(self):
2082
2019
        source = self.make_branch_and_tree('source')
2111
2048
        self.build_tree_contents([('source/file2', b'C')])
2112
2049
        calls = []
2113
2050
        real_source_get_file = source.get_file
2114
 
 
2115
 
        def get_file(path):
2116
 
            calls.append(path)
2117
 
            return real_source_get_file(path)
 
2051
        def get_file(path, file_id=None):
 
2052
            calls.append(file_id)
 
2053
            return real_source_get_file(path, file_id)
2118
2054
        source.get_file = get_file
2119
2055
        target = self.make_branch_and_tree('target')
2120
2056
        revision_tree = source.basis_tree()
2121
2057
        revision_tree.lock_read()
2122
2058
        self.addCleanup(revision_tree.unlock)
2123
2059
        build_tree(revision_tree, target, source)
2124
 
        self.assertEqual(['file1'], calls)
 
2060
        self.assertEqual(['file1-id'], calls)
2125
2061
        target.lock_read()
2126
2062
        self.addCleanup(target.unlock)
2127
2063
        self.assertEqual([], list(target.iter_changes(revision_tree)))
2128
2064
 
2129
2065
    def test_build_tree_accelerator_tree_observes_sha1(self):
2130
2066
        source = self.create_ab_tree()
2131
 
        sha1 = osutils.sha_string(b'A')
 
2067
        sha1 = osutils.sha_string('A')
2132
2068
        target = self.make_branch_and_tree('target')
2133
2069
        target.lock_write()
2134
2070
        self.addCleanup(target.unlock)
2135
2071
        state = target.current_dirstate()
2136
2072
        state._cutoff_time = time.time() + 60
2137
2073
        build_tree(source.basis_tree(), target, source)
2138
 
        entry = state._get_entry(0, path_utf8=b'file1')
 
2074
        entry = state._get_entry(0, path_utf8='file1')
2139
2075
        self.assertEqual(sha1, entry[1][0][1])
2140
2076
 
2141
2077
    def test_build_tree_accelerator_tree_missing_file(self):
2164
2100
        os.symlink('file2', 'source/file1')
2165
2101
        calls = []
2166
2102
        real_source_get_file = source.get_file
2167
 
 
2168
 
        def get_file(path):
2169
 
            calls.append(path)
2170
 
            return real_source_get_file(path)
 
2103
        def get_file(path, file_id=None):
 
2104
            calls.append(file_id)
 
2105
            return real_source_get_file(path, file_id)
2171
2106
        source.get_file = get_file
2172
2107
        target = self.make_branch_and_tree('target')
2173
2108
        revision_tree = source.basis_tree()
2245
2180
        # below, but that looks a bit... hard to read even if it's exactly
2246
2181
        # the same thing.
2247
2182
        original_registry = filters._reset_registry()
2248
 
 
2249
2183
        def restore_registry():
2250
2184
            filters._reset_registry(original_registry)
2251
2185
        self.addCleanup(restore_registry)
2252
 
 
2253
2186
        def rot13(chunks, context=None):
2254
 
            return [
2255
 
                codecs.encode(chunk.decode('ascii'), 'rot13').encode('ascii')
2256
 
                for chunk in chunks]
 
2187
            return [''.join(chunks).encode('rot13')]
2257
2188
        rot13filter = filters.ContentFilter(rot13, rot13)
2258
2189
        filters.filter_stacks_registry.register(
2259
2190
            'rot13', {'yes': [rot13filter]}.get)
2260
2191
        os.mkdir(self.test_home_dir + '/.bazaar')
2261
2192
        rules_filename = self.test_home_dir + '/.bazaar/rules'
2262
 
        with open(rules_filename, 'wb') as f:
2263
 
            f.write(b'[name %s]\nrot13=yes\n' % (pattern,))
2264
 
 
 
2193
        f = open(rules_filename, 'wb')
 
2194
        f.write('[name %s]\nrot13=yes\n' % (pattern,))
 
2195
        f.close()
2265
2196
        def uninstall_rules():
2266
2197
            os.remove(rules_filename)
2267
2198
            rules.reset_rules()
2274
2205
        if it can).
2275
2206
        """
2276
2207
        self.requireFeature(HardlinkFeature)
2277
 
        self.install_rot13_content_filter(b'file1')
 
2208
        self.install_rot13_content_filter('file1')
2278
2209
        source = self.create_ab_tree()
2279
2210
        target = self.make_branch_and_tree('target')
2280
2211
        revision_tree = source.basis_tree()
2293
2224
 
2294
2225
    def test_case_insensitive_build_tree_inventory(self):
2295
2226
        if (features.CaseInsensitiveFilesystemFeature.available()
2296
 
                or features.CaseInsCasePresFilenameFeature.available()):
 
2227
            or features.CaseInsCasePresFilenameFeature.available()):
2297
2228
            raise tests.UnavailableFeature('Fully case sensitive filesystem')
2298
2229
        source = self.make_branch_and_tree('source')
2299
2230
        self.build_tree(['source/file', 'source/FILE'])
2326
2257
        # entry[1] is the state information, entry[1][0] is the state of the
2327
2258
        # working tree, entry[1][0][1] is the sha value for the current working
2328
2259
        # tree
2329
 
        entry1 = state._get_entry(0, path_utf8=b'file1')
 
2260
        entry1 = state._get_entry(0, path_utf8='file1')
2330
2261
        self.assertEqual(entry1_sha, entry1[1][0][1])
2331
2262
        # The 'size' field must also be set.
2332
2263
        self.assertEqual(25, entry1[1][0][2])
2333
2264
        entry1_state = entry1[1][0]
2334
 
        entry2 = state._get_entry(0, path_utf8=b'dir/file2')
 
2265
        entry2 = state._get_entry(0, path_utf8='dir/file2')
2335
2266
        self.assertEqual(entry2_sha, entry2[1][0][1])
2336
2267
        self.assertEqual(29, entry2[1][0][2])
2337
2268
        entry2_state = entry2[1][0]
2338
2269
        # Now, make sure that we don't have to re-read the content. The
2339
2270
        # packed_stat should match exactly.
2340
 
        self.assertEqual(entry1_sha, target.get_file_sha1('file1'))
2341
 
        self.assertEqual(entry2_sha, target.get_file_sha1('dir/file2'))
 
2271
        self.assertEqual(entry1_sha, target.get_file_sha1('file1', b'file1-id'))
 
2272
        self.assertEqual(entry2_sha,
 
2273
                         target.get_file_sha1('dir/file2', b'file2-id'))
2342
2274
        self.assertEqual(entry1_state, entry1[1][0])
2343
2275
        self.assertEqual(entry2_state, entry2[1][0])
2344
2276
 
2377
2309
 
2378
2310
    def test_merge_parents(self):
2379
2311
        branch, tt = self.get_branch_and_transform()
2380
 
        tt.commit(branch, 'my message', [b'rev1b', b'rev1c'])
2381
 
        self.assertEqual([b'rev1b', b'rev1c'],
 
2312
        rev = tt.commit(branch, 'my message', ['rev1b', 'rev1c'])
 
2313
        self.assertEqual(['rev1b', 'rev1c'],
2382
2314
                         branch.basis_tree().get_parent_ids()[1:])
2383
2315
 
2384
2316
    def test_first_commit(self):
2387
2319
        self.addCleanup(branch.unlock)
2388
2320
        tt = TransformPreview(branch.basis_tree())
2389
2321
        self.addCleanup(tt.finalize)
2390
 
        tt.new_directory('', ROOT_PARENT, b'TREE_ROOT')
2391
 
        tt.commit(branch, 'my message')
 
2322
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
 
2323
        rev = tt.commit(branch, 'my message')
2392
2324
        self.assertEqual([], branch.basis_tree().get_parent_ids())
2393
2325
        self.assertNotEqual(_mod_revision.NULL_REVISION,
2394
2326
                            branch.last_revision())
2400
2332
        tt = TransformPreview(branch.basis_tree())
2401
2333
        self.addCleanup(tt.finalize)
2402
2334
        e = self.assertRaises(ValueError, tt.commit, branch,
2403
 
                              'my message', [b'rev1b-id'])
 
2335
                          'my message', ['rev1b-id'])
2404
2336
        self.assertEqual('Cannot supply merge parents for first commit.',
2405
2337
                         str(e))
2406
2338
        self.assertEqual(_mod_revision.NULL_REVISION, branch.last_revision())
2407
2339
 
2408
2340
    def test_add_files(self):
2409
2341
        branch, tt = self.get_branch_and_transform()
2410
 
        tt.new_file('file', tt.root, [b'contents'], b'file-id')
2411
 
        trans_id = tt.new_directory('dir', tt.root, b'dir-id')
 
2342
        tt.new_file('file', tt.root, 'contents', b'file-id')
 
2343
        trans_id = tt.new_directory('dir', tt.root, 'dir-id')
2412
2344
        if SymlinkFeature.available():
2413
 
            tt.new_symlink('symlink', trans_id, 'target', b'symlink-id')
2414
 
        tt.commit(branch, 'message')
 
2345
            tt.new_symlink('symlink', trans_id, 'target', 'symlink-id')
 
2346
        rev = tt.commit(branch, 'message')
2415
2347
        tree = branch.basis_tree()
2416
2348
        self.assertEqual('file', tree.id2path(b'file-id'))
2417
 
        self.assertEqual(b'contents', tree.get_file_text('file'))
 
2349
        self.assertEqual('contents', tree.get_file_text('file', b'file-id'))
2418
2350
        self.assertEqual('dir', tree.id2path(b'dir-id'))
2419
2351
        if SymlinkFeature.available():
2420
2352
            self.assertEqual('dir/symlink', tree.id2path(b'symlink-id'))
2422
2354
 
2423
2355
    def test_add_unversioned(self):
2424
2356
        branch, tt = self.get_branch_and_transform()
2425
 
        tt.new_file('file', tt.root, [b'contents'])
 
2357
        tt.new_file('file', tt.root, 'contents')
2426
2358
        self.assertRaises(errors.StrictCommitFailed, tt.commit, branch,
2427
2359
                          'message', strict=True)
2428
2360
 
2429
2361
    def test_modify_strict(self):
2430
2362
        branch, tt = self.get_branch_and_transform()
2431
 
        tt.new_file('file', tt.root, [b'contents'], b'file-id')
 
2363
        tt.new_file('file', tt.root, 'contents', b'file-id')
2432
2364
        tt.commit(branch, 'message', strict=True)
2433
2365
        tt = TransformPreview(branch.basis_tree())
2434
2366
        self.addCleanup(tt.finalize)
2435
 
        trans_id = tt.trans_id_file_id(b'file-id')
 
2367
        trans_id = tt.trans_id_file_id('file-id')
2436
2368
        tt.delete_contents(trans_id)
2437
 
        tt.create_file([b'contents'], trans_id)
 
2369
        tt.create_file('contents', trans_id)
2438
2370
        tt.commit(branch, 'message', strict=True)
2439
2371
 
2440
2372
    def test_commit_malformed(self):
2443
2375
        In this case, we are adding a file without adding its parent.
2444
2376
        """
2445
2377
        branch, tt = self.get_branch_and_transform()
2446
 
        parent_id = tt.trans_id_file_id(b'parent-id')
2447
 
        tt.new_file('file', parent_id, [b'contents'], b'file-id')
 
2378
        parent_id = tt.trans_id_file_id('parent-id')
 
2379
        tt.new_file('file', parent_id, 'contents', b'file-id')
2448
2380
        self.assertRaises(errors.MalformedTransform, tt.commit, branch,
2449
2381
                          'message')
2450
2382
 
2452
2384
        branch, tt = self.get_branch_and_transform()
2453
2385
        rev_id = tt.commit(branch, 'message', timestamp=1, timezone=43201,
2454
2386
                           committer='me <me@example.com>',
2455
 
                           revprops={u'foo': 'bar'}, revision_id=b'revid-1',
 
2387
                           revprops={'foo': 'bar'}, revision_id='revid-1',
2456
2388
                           authors=['Author1 <author1@example.com>',
2457
 
                                    'Author2 <author2@example.com>',
2458
 
                                    ])
2459
 
        self.assertEqual(b'revid-1', rev_id)
 
2389
                              'Author2 <author2@example.com>',
 
2390
                               ])
 
2391
        self.assertEqual('revid-1', rev_id)
2460
2392
        revision = branch.repository.get_revision(rev_id)
2461
2393
        self.assertEqual(1, revision.timestamp)
2462
2394
        self.assertEqual(43201, revision.timezone)
2525
2457
        mover.rename('c/e', 'c/d')
2526
2458
        try:
2527
2459
            mover.rename('a', 'c')
2528
 
        except errors.FileExists:
 
2460
        except errors.FileExists as e:
2529
2461
            mover.rollback()
2530
2462
        self.assertPathExists('a')
2531
2463
        self.assertPathExists('c/d')
2546
2478
 
2547
2479
        def rename(self, source, target):
2548
2480
            if (self.bad_source is not None and
2549
 
                    source.endswith(self.bad_source)):
 
2481
                source.endswith(self.bad_source)):
2550
2482
                raise Bogus
2551
2483
            elif (self.bad_target is not None and
2552
 
                  target.endswith(self.bad_target)):
 
2484
                target.endswith(self.bad_target)):
2553
2485
                raise Bogus
2554
2486
            else:
2555
2487
                _FileMover.rename(self, source, target)
2610
2542
        new_globals = dict(func.__globals__)
2611
2543
        new_globals.update(globals)
2612
2544
        new_func = types.FunctionType(func.__code__, new_globals,
2613
 
                                      func.__name__, func.__defaults__)
2614
 
        if PY3:
2615
 
            setattr(instance, method_name,
2616
 
                    types.MethodType(new_func, instance))
2617
 
        else:
2618
 
            setattr(instance, method_name,
2619
 
                    types.MethodType(new_func, instance, instance.__class__))
 
2545
            func.__name__, func.__defaults__)
 
2546
        setattr(instance, method_name,
 
2547
            types.MethodType(new_func, instance, instance.__class__))
2620
2548
        self.addCleanup(delattr, instance, method_name)
2621
2549
 
2622
2550
    @staticmethod
2648
2576
 
2649
2577
    def test_root_create_file_open_raises_before_creation(self):
2650
2578
        tt, trans_id = self.create_transform_and_root_trans_id()
2651
 
        self._override_globals_in_method(
2652
 
            tt, "create_file", {"open": self._fake_open_raises_before})
2653
 
        self.assertRaises(RuntimeError, tt.create_file,
2654
 
                          [b"contents"], trans_id)
 
2579
        self._override_globals_in_method(tt, "create_file",
 
2580
            {"open": self._fake_open_raises_before})
 
2581
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2655
2582
        path = tt._limbo_name(trans_id)
2656
2583
        self.assertPathDoesNotExist(path)
2657
2584
        tt.finalize()
2659
2586
 
2660
2587
    def test_root_create_file_open_raises_after_creation(self):
2661
2588
        tt, trans_id = self.create_transform_and_root_trans_id()
2662
 
        self._override_globals_in_method(
2663
 
            tt, "create_file", {"open": self._fake_open_raises_after})
2664
 
        self.assertRaises(RuntimeError, tt.create_file,
2665
 
                          [b"contents"], trans_id)
 
2589
        self._override_globals_in_method(tt, "create_file",
 
2590
            {"open": self._fake_open_raises_after})
 
2591
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2666
2592
        path = tt._limbo_name(trans_id)
2667
2593
        self.assertPathExists(path)
2668
2594
        tt.finalize()
2671
2597
 
2672
2598
    def test_subdir_create_file_open_raises_before_creation(self):
2673
2599
        tt, trans_id = self.create_transform_and_subdir_trans_id()
2674
 
        self._override_globals_in_method(
2675
 
            tt, "create_file", {"open": self._fake_open_raises_before})
2676
 
        self.assertRaises(RuntimeError, tt.create_file,
2677
 
                          [b"contents"], trans_id)
 
2600
        self._override_globals_in_method(tt, "create_file",
 
2601
            {"open": self._fake_open_raises_before})
 
2602
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2678
2603
        path = tt._limbo_name(trans_id)
2679
2604
        self.assertPathDoesNotExist(path)
2680
2605
        tt.finalize()
2682
2607
 
2683
2608
    def test_subdir_create_file_open_raises_after_creation(self):
2684
2609
        tt, trans_id = self.create_transform_and_subdir_trans_id()
2685
 
        self._override_globals_in_method(
2686
 
            tt, "create_file", {"open": self._fake_open_raises_after})
2687
 
        self.assertRaises(RuntimeError, tt.create_file,
2688
 
                          [b"contents"], trans_id)
 
2610
        self._override_globals_in_method(tt, "create_file",
 
2611
            {"open": self._fake_open_raises_after})
 
2612
        self.assertRaises(RuntimeError, tt.create_file, ["contents"], trans_id)
2689
2613
        path = tt._limbo_name(trans_id)
2690
2614
        self.assertPathExists(path)
2691
2615
        tt.finalize()
2695
2619
    def test_rename_in_limbo_rename_raises_after_rename(self):
2696
2620
        tt, trans_id = self.create_transform_and_root_trans_id()
2697
2621
        parent1 = tt.new_directory('parent1', tt.root)
2698
 
        child1 = tt.new_file('child1', parent1, [b'contents'])
 
2622
        child1 = tt.new_file('child1', parent1, 'contents')
2699
2623
        parent2 = tt.new_directory('parent2', tt.root)
2700
2624
 
2701
2625
        class FakeOSModule(object):
2703
2627
                os.rename(old, new)
2704
2628
                raise RuntimeError
2705
2629
        self._override_globals_in_method(tt, "_rename_in_limbo",
2706
 
                                         {"os": FakeOSModule()})
 
2630
            {"os": FakeOSModule()})
2707
2631
        self.assertRaises(
2708
2632
            RuntimeError, tt.adjust_path, "child1", parent2, child1)
2709
2633
        path = osutils.pathjoin(tt._limbo_name(parent2), "child1")
2715
2639
    def test_rename_in_limbo_rename_raises_before_rename(self):
2716
2640
        tt, trans_id = self.create_transform_and_root_trans_id()
2717
2641
        parent1 = tt.new_directory('parent1', tt.root)
2718
 
        child1 = tt.new_file('child1', parent1, [b'contents'])
 
2642
        child1 = tt.new_file('child1', parent1, 'contents')
2719
2643
        parent2 = tt.new_directory('parent2', tt.root)
2720
2644
 
2721
2645
        class FakeOSModule(object):
2722
2646
            def rename(self, old, new):
2723
2647
                raise RuntimeError
2724
2648
        self._override_globals_in_method(tt, "_rename_in_limbo",
2725
 
                                         {"os": FakeOSModule()})
 
2649
            {"os": FakeOSModule()})
2726
2650
        self.assertRaises(
2727
2651
            RuntimeError, tt.adjust_path, "child1", parent2, child1)
2728
2652
        path = osutils.pathjoin(tt._limbo_name(parent1), "child1")
2736
2660
 
2737
2661
    def make_tt_with_versioned_dir(self):
2738
2662
        wt = self.make_branch_and_tree('.')
2739
 
        self.build_tree(['dir/', ])
 
2663
        self.build_tree(['dir/',])
2740
2664
        wt.add(['dir'], [b'dir-id'])
2741
2665
        wt.commit('Create dir')
2742
2666
        tt = TreeTransform(wt)
2746
2670
    def test_resolve_create_parent_for_versioned_file(self):
2747
2671
        wt, tt = self.make_tt_with_versioned_dir()
2748
2672
        dir_tid = tt.trans_id_tree_path('dir')
2749
 
        tt.new_file('file', dir_tid, [b'Contents'], file_id=b'file-id')
 
2673
        file_tid = tt.new_file('file', dir_tid, 'Contents', file_id=b'file-id')
2750
2674
        tt.delete_contents(dir_tid)
2751
2675
        tt.unversion_file(dir_tid)
2752
2676
        conflicts = resolve_conflicts(tt)
2757
2681
    def test_non_versioned_file_create_conflict(self):
2758
2682
        wt, tt = self.make_tt_with_versioned_dir()
2759
2683
        dir_tid = tt.trans_id_tree_path('dir')
2760
 
        tt.new_file('file', dir_tid, [b'Contents'])
 
2684
        tt.new_file('file', dir_tid, 'Contents')
2761
2685
        tt.delete_contents(dir_tid)
2762
2686
        tt.unversion_file(dir_tid)
2763
2687
        conflicts = resolve_conflicts(tt)
2767
2691
                         conflicts.pop())
2768
2692
 
2769
2693
 
2770
 
A_ENTRY = (b'a-id', ('a', 'a'), True, (True, True),
2771
 
           (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2772
 
           (False, False), False)
2773
 
ROOT_ENTRY = (b'TREE_ROOT', ('', ''), False, (True, True), (None, None),
2774
 
              ('', ''), ('directory', 'directory'), (False, False), False)
 
2694
A_ENTRY = ('a-id', ('a', 'a'), True, (True, True),
 
2695
                  ('TREE_ROOT', 'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
 
2696
                  (False, False))
 
2697
ROOT_ENTRY = ('TREE_ROOT', ('', ''), False, (True, True), (None, None),
 
2698
              ('', ''), ('directory', 'directory'), (False, False))
2775
2699
 
2776
2700
 
2777
2701
class TestTransformPreview(tests.TestCaseWithTransport):
2782
2706
        tree.set_root_id(b'TREE_ROOT')
2783
2707
        tree.add('a', b'a-id')
2784
2708
        tree.commit('rev1', rev_id=b'rev1')
2785
 
        return tree.branch.repository.revision_tree(b'rev1')
 
2709
        return tree.branch.repository.revision_tree('rev1')
2786
2710
 
2787
2711
    def get_empty_preview(self):
2788
2712
        repository = self.make_repository('repo')
2806
2730
        revision_tree = self.create_tree()
2807
2731
        preview = TransformPreview(revision_tree)
2808
2732
        self.addCleanup(preview.finalize)
2809
 
        preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
 
2733
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2810
2734
        preview_tree = preview.get_preview_tree()
2811
2735
        self.assertEqual(preview_tree.kind('file2'), 'file')
2812
 
        with preview_tree.get_file('file2') as f:
2813
 
            self.assertEqual(f.read(), b'content B\n')
 
2736
        self.assertEqual(
 
2737
            preview_tree.get_file('file2', 'file2-id').read(), 'content B\n')
2814
2738
 
2815
2739
    def test_diff_preview_tree(self):
2816
2740
        revision_tree = self.create_tree()
2817
2741
        preview = TransformPreview(revision_tree)
2818
2742
        self.addCleanup(preview.finalize)
2819
 
        preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
 
2743
        preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
2820
2744
        preview_tree = preview.get_preview_tree()
2821
2745
        out = BytesIO()
2822
2746
        show_diff_trees(revision_tree, preview_tree, out)
2823
2747
        lines = out.getvalue().splitlines()
2824
 
        self.assertEqual(lines[0], b"=== added file 'file2'")
 
2748
        self.assertEqual(lines[0], "=== added file 'file2'")
2825
2749
        # 3 lines of diff administrivia
2826
 
        self.assertEqual(lines[4], b"+content B")
2827
 
 
2828
 
    def test_unsupported_symlink_diff(self):
2829
 
        self.requireFeature(SymlinkFeature)
2830
 
        tree = self.make_branch_and_tree('.')
2831
 
        self.build_tree_contents([('a', 'content 1')])
2832
 
        tree.set_root_id(b'TREE_ROOT')
2833
 
        tree.add('a', b'a-id')
2834
 
        os.symlink('a', 'foo')
2835
 
        tree.add('foo', b'foo-id')
2836
 
        tree.commit('rev1', rev_id=b'rev1')
2837
 
        revision_tree = tree.branch.repository.revision_tree(b'rev1')
2838
 
        preview = TransformPreview(revision_tree)
2839
 
        self.addCleanup(preview.finalize)
2840
 
        preview.delete_versioned(preview.trans_id_tree_path('foo'))
2841
 
        preview_tree = preview.get_preview_tree()
2842
 
        out = BytesIO()
2843
 
        log = BytesIO()
2844
 
        trace.push_log_file(log)
2845
 
        os_symlink = getattr(os, 'symlink', None)
2846
 
        os.symlink = None
2847
 
        try:
2848
 
            show_diff_trees(revision_tree, preview_tree, out)
2849
 
            lines = out.getvalue().splitlines()
2850
 
        finally:
2851
 
            os.symlink = os_symlink
2852
 
        self.assertContainsRe(
2853
 
            log.getvalue(),
2854
 
            b'Ignoring "foo" as symlinks are not supported on this filesystem')
 
2750
        self.assertEqual(lines[4], "+content B")
2855
2751
 
2856
2752
    def test_transform_conflicts(self):
2857
2753
        revision_tree = self.create_tree()
2858
2754
        preview = TransformPreview(revision_tree)
2859
2755
        self.addCleanup(preview.finalize)
2860
 
        preview.new_file('a', preview.root, [b'content 2'])
 
2756
        preview.new_file('a', preview.root, 'content 2')
2861
2757
        resolve_conflicts(preview)
2862
 
        trans_id = preview.trans_id_file_id(b'a-id')
 
2758
        trans_id = preview.trans_id_file_id('a-id')
2863
2759
        self.assertEqual('a.moved', preview.final_name(trans_id))
2864
2760
 
2865
2761
    def get_tree_and_preview_tree(self):
2866
2762
        revision_tree = self.create_tree()
2867
2763
        preview = TransformPreview(revision_tree)
2868
2764
        self.addCleanup(preview.finalize)
2869
 
        a_trans_id = preview.trans_id_file_id(b'a-id')
 
2765
        a_trans_id = preview.trans_id_file_id('a-id')
2870
2766
        preview.delete_contents(a_trans_id)
2871
 
        preview.create_file([b'b content'], a_trans_id)
 
2767
        preview.create_file('b content', a_trans_id)
2872
2768
        preview_tree = preview.get_preview_tree()
2873
2769
        return revision_tree, preview_tree
2874
2770
 
2875
2771
    def test_iter_changes(self):
2876
2772
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2877
 
        root = revision_tree.path2id('')
2878
 
        self.assertEqual([(b'a-id', ('a', 'a'), True, (True, True),
2879
 
                           (root, root), ('a', 'a'), ('file', 'file'),
2880
 
                           (False, False), False)],
2881
 
                         list(preview_tree.iter_changes(revision_tree)))
 
2773
        root = revision_tree.get_root_id()
 
2774
        self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
 
2775
                          (root, root), ('a', 'a'), ('file', 'file'),
 
2776
                          (False, False))],
 
2777
                          list(preview_tree.iter_changes(revision_tree)))
2882
2778
 
2883
2779
    def test_include_unchanged_succeeds(self):
2884
2780
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2885
2781
        changes = preview_tree.iter_changes(revision_tree,
2886
2782
                                            include_unchanged=True)
 
2783
        root = revision_tree.get_root_id()
 
2784
 
2887
2785
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
2888
2786
 
2889
2787
    def test_specific_files(self):
2918
2816
        revision_tree = self.create_tree()
2919
2817
        preview = TransformPreview(revision_tree)
2920
2818
        self.addCleanup(preview.finalize)
2921
 
        preview.new_file('file', preview.root, [b'contents'], b'file-id')
2922
 
        preview.new_directory('directory', preview.root, b'dir-id')
 
2819
        preview.new_file('file', preview.root, 'contents', b'file-id')
 
2820
        preview.new_directory('directory', preview.root, 'dir-id')
2923
2821
        preview_tree = preview.get_preview_tree()
2924
2822
        self.assertEqual('file', preview_tree.kind('file'))
2925
2823
        self.assertEqual('directory', preview_tree.kind('directory'))
2926
2824
 
2927
2825
    def test_get_file_mtime(self):
2928
2826
        preview = self.get_empty_preview()
2929
 
        file_trans_id = preview.new_file('file', preview.root, [b'contents'],
 
2827
        file_trans_id = preview.new_file('file', preview.root, 'contents',
2930
2828
                                         b'file-id')
2931
2829
        limbo_path = preview._limbo_name(file_trans_id)
2932
2830
        preview_tree = preview.get_preview_tree()
2933
2831
        self.assertEqual(os.stat(limbo_path).st_mtime,
2934
 
                         preview_tree.get_file_mtime('file'))
 
2832
                         preview_tree.get_file_mtime('file', b'file-id'))
2935
2833
 
2936
2834
    def test_get_file_mtime_renamed(self):
2937
2835
        work_tree = self.make_branch_and_tree('tree')
2942
2840
        file_trans_id = preview.trans_id_tree_path('file')
2943
2841
        preview.adjust_path('renamed', preview.root, file_trans_id)
2944
2842
        preview_tree = preview.get_preview_tree()
2945
 
        preview_mtime = preview_tree.get_file_mtime('renamed')
2946
 
        work_mtime = work_tree.get_file_mtime('file')
 
2843
        preview_mtime = preview_tree.get_file_mtime('renamed', b'file-id')
 
2844
        work_mtime = work_tree.get_file_mtime('file', b'file-id')
2947
2845
 
2948
2846
    def test_get_file_size(self):
2949
2847
        work_tree = self.make_branch_and_tree('tree')
2951
2849
        work_tree.add('old', b'old-id')
2952
2850
        preview = TransformPreview(work_tree)
2953
2851
        self.addCleanup(preview.finalize)
2954
 
        preview.new_file('name', preview.root, [b'contents'], b'new-id',
2955
 
                         'executable')
 
2852
        new_id = preview.new_file('name', preview.root, 'contents', b'new-id',
 
2853
                                  'executable')
2956
2854
        tree = preview.get_preview_tree()
2957
2855
        self.assertEqual(len('old'), tree.get_file_size('old'))
2958
2856
        self.assertEqual(len('contents'), tree.get_file_size('name'))
2959
2857
 
2960
2858
    def test_get_file(self):
2961
2859
        preview = self.get_empty_preview()
2962
 
        preview.new_file('file', preview.root, [b'contents'], b'file-id')
 
2860
        preview.new_file('file', preview.root, 'contents', b'file-id')
2963
2861
        preview_tree = preview.get_preview_tree()
2964
 
        with preview_tree.get_file('file') as tree_file:
2965
 
            self.assertEqual(b'contents', tree_file.read())
 
2862
        tree_file = preview_tree.get_file('file')
 
2863
        try:
 
2864
            self.assertEqual('contents', tree_file.read())
 
2865
        finally:
 
2866
            tree_file.close()
2966
2867
 
2967
2868
    def test_get_symlink_target(self):
2968
2869
        self.requireFeature(SymlinkFeature)
2969
2870
        preview = self.get_empty_preview()
2970
 
        preview.new_symlink('symlink', preview.root, 'target', b'symlink-id')
 
2871
        preview.new_symlink('symlink', preview.root, 'target', 'symlink-id')
2971
2872
        preview_tree = preview.get_preview_tree()
2972
2873
        self.assertEqual('target',
2973
2874
                         preview_tree.get_symlink_target('symlink'))
2983
2884
        preview.unversion_file(c_trans_id)
2984
2885
        preview.version_file(b'c-id', c_trans_id)
2985
2886
        preview_tree = preview.get_preview_tree()
2986
 
        self.assertEqual({b'a-id', b'c-id', tree.path2id('')},
 
2887
        self.assertEqual({b'a-id', b'c-id', tree.get_root_id()},
2987
2888
                         preview_tree.all_file_ids())
2988
2889
 
2989
2890
    def test_path2id_deleted_unchanged(self):
3004
2905
        preview = TransformPreview(tree)
3005
2906
        self.addCleanup(preview.finalize)
3006
2907
        preview.new_file('new', preview.trans_id_file_id(b'unchanged-id'),
3007
 
                         [b'contents'], b'new-id')
 
2908
            'contents', 'new-id')
3008
2909
        preview_tree = preview.get_preview_tree()
3009
2910
        self.assertEqual(b'new-id', preview_tree.path2id('unchanged/new'))
3010
2911
 
3049
2950
    def test_iter_entries_by_dir_new(self):
3050
2951
        tree = self.make_branch_and_tree('tree')
3051
2952
        tt = TreeTransform(tree)
3052
 
        tt.new_file('new', tt.root, [b'contents'], b'new-id')
 
2953
        tt.new_file('new', tt.root, 'contents', b'new-id')
3053
2954
        self.assertMatchingIterEntries(tt)
3054
2955
 
3055
2956
    def test_iter_entries_by_dir_deleted(self):
3109
3010
 
3110
3011
    def test_file_content_summary_executable(self):
3111
3012
        preview = self.get_empty_preview()
3112
 
        path_id = preview.new_file('path', preview.root, [
3113
 
                                   b'contents'], b'path-id')
 
3013
        path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
3114
3014
        preview.set_executability(True, path_id)
3115
3015
        summary = preview.get_preview_tree().path_content_summary('path')
3116
3016
        self.assertEqual(4, len(summary))
3135
3035
 
3136
3036
    def test_file_content_summary_non_exec(self):
3137
3037
        preview = self.get_empty_preview()
3138
 
        preview.new_file('path', preview.root, [b'contents'], b'path-id')
 
3038
        preview.new_file('path', preview.root, 'contents', 'path-id')
3139
3039
        summary = preview.get_preview_tree().path_content_summary('path')
3140
3040
        self.assertEqual(4, len(summary))
3141
3041
        self.assertEqual('file', summary[0])
3148
3048
 
3149
3049
    def test_dir_content_summary(self):
3150
3050
        preview = self.get_empty_preview()
3151
 
        preview.new_directory('path', preview.root, b'path-id')
 
3051
        preview.new_directory('path', preview.root, 'path-id')
3152
3052
        summary = preview.get_preview_tree().path_content_summary('path')
3153
3053
        self.assertEqual(('directory', None, None, None), summary)
3154
3054
 
3155
3055
    def test_tree_content_summary(self):
3156
3056
        preview = self.get_empty_preview()
3157
 
        path = preview.new_directory('path', preview.root, b'path-id')
3158
 
        preview.set_tree_reference(b'rev-1', path)
 
3057
        path = preview.new_directory('path', preview.root, 'path-id')
 
3058
        preview.set_tree_reference('rev-1', path)
3159
3059
        summary = preview.get_preview_tree().path_content_summary('path')
3160
3060
        self.assertEqual(4, len(summary))
3161
3061
        self.assertEqual('tree-reference', summary[0])
3170
3070
        self.addCleanup(preview.finalize)
3171
3071
        file_trans_id = preview.trans_id_file_id(b'file-id')
3172
3072
        preview.delete_contents(file_trans_id)
3173
 
        preview.create_file([b'a\nb\nc\n'], file_trans_id)
 
3073
        preview.create_file('a\nb\nc\n', file_trans_id)
3174
3074
        preview_tree = preview.get_preview_tree()
3175
3075
        expected = [
3176
 
            (b'one', b'a\n'),
3177
 
            (b'me:', b'b\n'),
3178
 
            (b'me:', b'c\n'),
 
3076
            ('one', 'a\n'),
 
3077
            ('me:', 'b\n'),
 
3078
            ('me:', 'c\n'),
3179
3079
        ]
3180
 
        annotation = preview_tree.annotate_iter(
3181
 
            'file', default_revision=b'me:')
 
3080
        annotation = preview_tree.annotate_iter('file', default_revision=b'me:')
3182
3081
        self.assertEqual(expected, annotation)
3183
3082
 
3184
3083
    def test_annotate_missing(self):
3185
3084
        preview = self.get_empty_preview()
3186
 
        preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
 
3085
        preview.new_file('file', preview.root, 'a\nb\nc\n', b'file-id')
3187
3086
        preview_tree = preview.get_preview_tree()
3188
3087
        expected = [
3189
 
            (b'me:', b'a\n'),
3190
 
            (b'me:', b'b\n'),
3191
 
            (b'me:', b'c\n'),
3192
 
            ]
3193
 
        annotation = preview_tree.annotate_iter(
3194
 
            'file', default_revision=b'me:')
 
3088
            ('me:', 'a\n'),
 
3089
            ('me:', 'b\n'),
 
3090
            ('me:', 'c\n'),
 
3091
         ]
 
3092
        annotation = preview_tree.annotate_iter('file', default_revision=b'me:')
3195
3093
        self.assertEqual(expected, annotation)
3196
3094
 
3197
3095
    def test_annotate_rename(self):
3205
3103
        preview.adjust_path('newname', preview.root, file_trans_id)
3206
3104
        preview_tree = preview.get_preview_tree()
3207
3105
        expected = [
3208
 
            (b'one', b'a\n'),
 
3106
            ('one', 'a\n'),
3209
3107
        ]
3210
 
        annotation = preview_tree.annotate_iter(
3211
 
            'file', default_revision=b'me:')
 
3108
        annotation = preview_tree.annotate_iter('file', default_revision=b'me:')
3212
3109
        self.assertEqual(expected, annotation)
3213
3110
 
3214
3111
    def test_annotate_deleted(self):
3222
3119
        file_trans_id = preview.trans_id_file_id(b'file-id')
3223
3120
        preview.delete_contents(file_trans_id)
3224
3121
        preview_tree = preview.get_preview_tree()
3225
 
        annotation = preview_tree.annotate_iter(
3226
 
            'file', default_revision=b'me:')
 
3122
        annotation = preview_tree.annotate_iter('file', default_revision=b'me:')
3227
3123
        self.assertIs(None, annotation)
3228
3124
 
3229
3125
    def test_stored_kind(self):
3230
3126
        preview = self.get_empty_preview()
3231
 
        preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
 
3127
        preview.new_file('file', preview.root, 'a\nb\nc\n', b'file-id')
3232
3128
        preview_tree = preview.get_preview_tree()
3233
3129
        self.assertEqual('file', preview_tree.stored_kind('file'))
3234
3130
 
3235
3131
    def test_is_executable(self):
3236
3132
        preview = self.get_empty_preview()
3237
 
        preview.new_file('file', preview.root, [b'a\nb\nc\n'], b'file-id')
 
3133
        preview.new_file('file', preview.root, 'a\nb\nc\n', b'file-id')
3238
3134
        preview.set_executability(True, preview.trans_id_file_id(b'file-id'))
3239
3135
        preview_tree = preview.get_preview_tree()
3240
3136
        self.assertEqual(True, preview_tree.is_executable('file'))
3255
3151
        self.addCleanup(preview.finalize)
3256
3152
        trans_id = preview.trans_id_file_id(b'file-id')
3257
3153
        preview.delete_contents(trans_id)
3258
 
        preview.create_file([b'b\nc\nd\ne\n'], trans_id)
 
3154
        preview.create_file('b\nc\nd\ne\n', trans_id)
3259
3155
        self.build_tree_contents([('wtb/file', b'a\nc\nd\nf\n')])
3260
3156
        tree_a = preview.get_preview_tree()
3261
3157
        tree_a.set_parent_ids([base_id])
3262
3158
        self.assertEqual([
3263
 
            ('killed-a', b'a\n'),
3264
 
            ('killed-b', b'b\n'),
3265
 
            ('unchanged', b'c\n'),
3266
 
            ('unchanged', b'd\n'),
3267
 
            ('new-a', b'e\n'),
3268
 
            ('new-b', b'f\n'),
3269
 
        ], list(tree_a.plan_file_merge('file', tree_b)))
 
3159
            ('killed-a', 'a\n'),
 
3160
            ('killed-b', 'b\n'),
 
3161
            ('unchanged', 'c\n'),
 
3162
            ('unchanged', 'd\n'),
 
3163
            ('new-a', 'e\n'),
 
3164
            ('new-b', 'f\n'),
 
3165
        ], list(tree_a.plan_file_merge(b'file-id', tree_b)))
3270
3166
 
3271
3167
    def test_plan_file_merge_revision_tree(self):
3272
3168
        work_a = self.make_branch_and_tree('wta')
3278
3174
        self.addCleanup(preview.finalize)
3279
3175
        trans_id = preview.trans_id_file_id(b'file-id')
3280
3176
        preview.delete_contents(trans_id)
3281
 
        preview.create_file([b'b\nc\nd\ne\n'], trans_id)
 
3177
        preview.create_file('b\nc\nd\ne\n', trans_id)
3282
3178
        self.build_tree_contents([('wtb/file', b'a\nc\nd\nf\n')])
3283
3179
        tree_a = preview.get_preview_tree()
3284
3180
        tree_a.set_parent_ids([base_id])
3285
3181
        self.assertEqual([
3286
 
            ('killed-a', b'a\n'),
3287
 
            ('killed-b', b'b\n'),
3288
 
            ('unchanged', b'c\n'),
3289
 
            ('unchanged', b'd\n'),
3290
 
            ('new-a', b'e\n'),
3291
 
            ('new-b', b'f\n'),
3292
 
        ], list(tree_a.plan_file_merge('file', tree_b)))
 
3182
            ('killed-a', 'a\n'),
 
3183
            ('killed-b', 'b\n'),
 
3184
            ('unchanged', 'c\n'),
 
3185
            ('unchanged', 'd\n'),
 
3186
            ('new-a', 'e\n'),
 
3187
            ('new-b', 'f\n'),
 
3188
        ], list(tree_a.plan_file_merge(b'file-id', tree_b)))
3293
3189
 
3294
3190
    def test_walkdirs(self):
3295
3191
        preview = self.get_empty_preview()
3296
 
        preview.new_directory('', ROOT_PARENT, b'tree-root')
 
3192
        root = preview.new_directory('', ROOT_PARENT, 'tree-root')
3297
3193
        # FIXME: new_directory should mark root.
3298
3194
        preview.fixup_new_roots()
3299
3195
        preview_tree = preview.get_preview_tree()
3300
 
        preview.new_file('a', preview.root, [b'contents'], b'a-id')
 
3196
        file_trans_id = preview.new_file('a', preview.root, 'contents',
 
3197
                                         b'a-id')
3301
3198
        expected = [(('', b'tree-root'),
3302
 
                     [('a', 'a', 'file', None, b'a-id', 'file')])]
 
3199
                    [('a', 'a', 'file', None, b'a-id', 'file')])]
3303
3200
        self.assertEqual(expected, list(preview_tree.walkdirs()))
3304
3201
 
3305
3202
    def test_extras(self):
3309
3206
        work_tree.add(['removed-file', 'not-removed-file'])
3310
3207
        preview = TransformPreview(work_tree)
3311
3208
        self.addCleanup(preview.finalize)
3312
 
        preview.new_file('new-file', preview.root, [b'contents'])
3313
 
        preview.new_file('new-versioned-file', preview.root, [b'contents'],
 
3209
        preview.new_file('new-file', preview.root, 'contents')
 
3210
        preview.new_file('new-versioned-file', preview.root, 'contents',
3314
3211
                         b'new-versioned-id')
3315
3212
        tree = preview.get_preview_tree()
3316
3213
        preview.unversion_file(preview.trans_id_tree_path('removed-file'))
3333
3230
        self.addCleanup(preview.finalize)
3334
3231
        file_trans_id = preview.trans_id_file_id(b'file-id')
3335
3232
        preview.delete_contents(file_trans_id)
3336
 
        preview.create_file([b'a\nb\n'], file_trans_id)
 
3233
        preview.create_file('a\nb\n', file_trans_id)
3337
3234
        preview_tree = preview.get_preview_tree()
3338
3235
        merger = Merger.from_revision_ids(preview_tree,
3339
3236
                                          child_tree.branch.last_revision(),
3344
3241
        self.addCleanup(tt.finalize)
3345
3242
        final_tree = tt.get_preview_tree()
3346
3243
        self.assertEqual(
3347
 
            b'a\nb\nc\n',
3348
 
            final_tree.get_file_text(final_tree.id2path(b'file-id')))
 
3244
                'a\nb\nc\n',
 
3245
                final_tree.get_file_text(final_tree.id2path(b'file-id')))
3349
3246
 
3350
3247
    def test_merge_preview_into_workingtree(self):
3351
3248
        tree = self.make_branch_and_tree('tree')
3352
3249
        tree.set_root_id(b'TREE_ROOT')
3353
3250
        tt = TransformPreview(tree)
3354
3251
        self.addCleanup(tt.finalize)
3355
 
        tt.new_file('name', tt.root, [b'content'], b'file-id')
 
3252
        tt.new_file('name', tt.root, 'content', b'file-id')
3356
3253
        tree2 = self.make_branch_and_tree('tree2')
3357
3254
        tree2.set_root_id(b'TREE_ROOT')
3358
3255
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
3369
3266
        self.addCleanup(tt.finalize)
3370
3267
        trans_id = tt.trans_id_file_id(b'foo-id')
3371
3268
        tt.delete_contents(trans_id)
3372
 
        tt.create_file([b'baz'], trans_id)
 
3269
        tt.create_file('baz', trans_id)
3373
3270
        tree2 = tree.controldir.sprout('tree2').open_workingtree()
3374
3271
        self.build_tree_contents([('tree2/foo', b'qux')])
3375
3272
        merger = Merger.from_uncommitted(tree2, tt.get_preview_tree(),
3383
3280
        tt = TransformPreview(wt)
3384
3281
        removed_id = tt.trans_id_tree_path('removed')
3385
3282
        tt.delete_contents(removed_id)
3386
 
        tt.new_file('new', tt.root, [b'contents'])
 
3283
        tt.new_file('new', tt.root, 'contents')
3387
3284
        modified_id = tt.trans_id_tree_path('modified')
3388
3285
        tt.delete_contents(modified_id)
3389
 
        tt.create_file([b'modified-contents'], modified_id)
 
3286
        tt.create_file('modified-contents', modified_id)
3390
3287
        self.addCleanup(tt.finalize)
3391
3288
        tree = tt.get_preview_tree()
3392
3289
        self.assertTrue(tree.has_filename('unmodified'))
3399
3296
        tree = self.make_branch_and_tree('tree')
3400
3297
        preview = TransformPreview(tree)
3401
3298
        self.addCleanup(preview.finalize)
3402
 
        preview.new_file('foo', preview.root, [b'bar'], b'baz-id')
 
3299
        preview.new_file('foo', preview.root, 'bar', 'baz-id')
3403
3300
        preview_tree = preview.get_preview_tree()
 
3301
        self.assertEqual(False, preview_tree.is_executable('tree/foo', 'baz-id'))
3404
3302
        self.assertEqual(False, preview_tree.is_executable('tree/foo'))
3405
3303
 
3406
3304
    def test_commit_preview_tree(self):
3409
3307
        tree.branch.lock_write()
3410
3308
        self.addCleanup(tree.branch.unlock)
3411
3309
        tt = TransformPreview(tree)
3412
 
        tt.new_file('file', tt.root, [b'contents'], b'file_id')
 
3310
        tt.new_file('file', tt.root, 'contents', 'file_id')
3413
3311
        self.addCleanup(tt.finalize)
3414
3312
        preview = tt.get_preview_tree()
3415
3313
        preview.set_parent_ids([rev_id])
3418
3316
        builder.finish_inventory()
3419
3317
        rev2_id = builder.commit('rev2')
3420
3318
        rev2_tree = tree.branch.repository.revision_tree(rev2_id)
3421
 
        self.assertEqual(b'contents', rev2_tree.get_file_text('file'))
 
3319
        self.assertEqual('contents', rev2_tree.get_file_text('file'))
3422
3320
 
3423
3321
    def test_ascii_limbo_paths(self):
3424
3322
        self.requireFeature(features.UnicodeFilenameFeature)
3427
3325
        tt = TransformPreview(tree)
3428
3326
        self.addCleanup(tt.finalize)
3429
3327
        foo_id = tt.new_directory('', ROOT_PARENT)
3430
 
        bar_id = tt.new_file(u'\u1234bar', foo_id, [b'contents'])
 
3328
        bar_id = tt.new_file(u'\u1234bar', foo_id, 'contents')
3431
3329
        limbo_path = tt._limbo_name(bar_id)
3432
 
        self.assertEqual(limbo_path, limbo_path)
 
3330
        self.assertEqual(limbo_path.encode('ascii', 'replace'), limbo_path)
3433
3331
 
3434
3332
 
3435
3333
class FakeSerializer(object):
3460
3358
    @staticmethod
3461
3359
    def default_attribs():
3462
3360
        return {
3463
 
            b'_id_number': 1,
3464
 
            b'_new_name': {},
3465
 
            b'_new_parent': {},
3466
 
            b'_new_executability': {},
3467
 
            b'_new_id': {},
3468
 
            b'_tree_path_ids': {b'': b'new-0'},
3469
 
            b'_removed_id': [],
3470
 
            b'_removed_contents': [],
3471
 
            b'_non_present_ids': {},
 
3361
            '_id_number': 1,
 
3362
            '_new_name': {},
 
3363
            '_new_parent': {},
 
3364
            '_new_executability': {},
 
3365
            '_new_id': {},
 
3366
            '_tree_path_ids': {'': 'new-0'},
 
3367
            '_removed_id': [],
 
3368
            '_removed_contents': [],
 
3369
            '_non_present_ids': {},
3472
3370
            }
3473
3371
 
3474
3372
    def make_records(self, attribs, contents):
3475
3373
        records = [
3476
 
            ((((b'attribs'),),), bencode.bencode(attribs))]
 
3374
            (((('attribs'),),), bencode.bencode(attribs))]
3477
3375
        records.extend([(((n, k),), c) for n, k, c in contents])
3478
3376
        return records
3479
3377
 
3480
3378
    def creation_records(self):
3481
3379
        attribs = self.default_attribs()
3482
 
        attribs[b'_id_number'] = 3
3483
 
        attribs[b'_new_name'] = {
3484
 
            b'new-1': u'foo\u1234'.encode('utf-8'), b'new-2': b'qux'}
3485
 
        attribs[b'_new_id'] = {b'new-1': b'baz', b'new-2': b'quxx'}
3486
 
        attribs[b'_new_parent'] = {b'new-1': b'new-0', b'new-2': b'new-0'}
3487
 
        attribs[b'_new_executability'] = {b'new-1': 1}
 
3380
        attribs['_id_number'] = 3
 
3381
        attribs['_new_name'] = {
 
3382
            'new-1': u'foo\u1234'.encode('utf-8'), 'new-2': 'qux'}
 
3383
        attribs['_new_id'] = {'new-1': 'baz', 'new-2': 'quxx'}
 
3384
        attribs['_new_parent'] = {'new-1': 'new-0', 'new-2': 'new-0'}
 
3385
        attribs['_new_executability'] = {'new-1': 1}
3488
3386
        contents = [
3489
 
            (b'new-1', b'file', b'i 1\nbar\n'),
3490
 
            (b'new-2', b'directory', b''),
 
3387
            ('new-1', 'file', 'i 1\nbar\n'),
 
3388
            ('new-2', 'directory', ''),
3491
3389
            ]
3492
3390
        return self.make_records(attribs, contents)
3493
3391
 
3494
3392
    def test_serialize_creation(self):
3495
3393
        tt = self.get_preview()
3496
 
        tt.new_file(u'foo\u1234', tt.root, [b'bar'], b'baz', True)
3497
 
        tt.new_directory('qux', tt.root, b'quxx')
 
3394
        tt.new_file(u'foo\u1234', tt.root, 'bar', 'baz', True)
 
3395
        tt.new_directory('qux', tt.root, 'quxx')
3498
3396
        self.assertSerializesTo(self.creation_records(), tt)
3499
3397
 
3500
3398
    def test_deserialize_creation(self):
3503
3401
        self.assertEqual(3, tt._id_number)
3504
3402
        self.assertEqual({'new-1': u'foo\u1234',
3505
3403
                          'new-2': 'qux'}, tt._new_name)
3506
 
        self.assertEqual({'new-1': b'baz', 'new-2': b'quxx'}, tt._new_id)
 
3404
        self.assertEqual({'new-1': 'baz', 'new-2': 'quxx'}, tt._new_id)
3507
3405
        self.assertEqual({'new-1': tt.root, 'new-2': tt.root}, tt._new_parent)
3508
 
        self.assertEqual({b'baz': 'new-1', b'quxx': 'new-2'}, tt._r_new_id)
 
3406
        self.assertEqual({'baz': 'new-1', 'quxx': 'new-2'}, tt._r_new_id)
3509
3407
        self.assertEqual({'new-1': True}, tt._new_executability)
3510
3408
        self.assertEqual({'new-1': 'file',
3511
3409
                          'new-2': 'directory'}, tt._new_contents)
3514
3412
            foo_content = foo_limbo.read()
3515
3413
        finally:
3516
3414
            foo_limbo.close()
3517
 
        self.assertEqual(b'bar', foo_content)
 
3415
        self.assertEqual('bar', foo_content)
3518
3416
 
3519
3417
    def symlink_creation_records(self):
3520
3418
        attribs = self.default_attribs()
3521
 
        attribs[b'_id_number'] = 2
3522
 
        attribs[b'_new_name'] = {b'new-1': u'foo\u1234'.encode('utf-8')}
3523
 
        attribs[b'_new_parent'] = {b'new-1': b'new-0'}
3524
 
        contents = [(b'new-1', b'symlink', u'bar\u1234'.encode('utf-8'))]
 
3419
        attribs['_id_number'] = 2
 
3420
        attribs['_new_name'] = {'new-1': u'foo\u1234'.encode('utf-8')}
 
3421
        attribs['_new_parent'] = {'new-1': 'new-0'}
 
3422
        contents = [('new-1', 'symlink', u'bar\u1234'.encode('utf-8'))]
3525
3423
        return self.make_records(attribs, contents)
3526
3424
 
3527
3425
    def test_serialize_symlink_creation(self):
3546
3444
 
3547
3445
    def destruction_records(self):
3548
3446
        attribs = self.default_attribs()
3549
 
        attribs[b'_id_number'] = 3
3550
 
        attribs[b'_removed_id'] = [b'new-1']
3551
 
        attribs[b'_removed_contents'] = [b'new-2']
3552
 
        attribs[b'_tree_path_ids'] = {
3553
 
            b'': b'new-0',
3554
 
            u'foo\u1234'.encode('utf-8'): b'new-1',
3555
 
            b'bar': b'new-2',
 
3447
        attribs['_id_number'] = 3
 
3448
        attribs['_removed_id'] = ['new-1']
 
3449
        attribs['_removed_contents'] = ['new-2']
 
3450
        attribs['_tree_path_ids'] = {
 
3451
            '': 'new-0',
 
3452
            u'foo\u1234'.encode('utf-8'): 'new-1',
 
3453
            'bar': 'new-2',
3556
3454
            }
3557
3455
        return self.make_records(attribs, [])
3558
3456
 
3578
3476
 
3579
3477
    def missing_records(self):
3580
3478
        attribs = self.default_attribs()
3581
 
        attribs[b'_id_number'] = 2
3582
 
        attribs[b'_non_present_ids'] = {
3583
 
            b'boo': b'new-1', }
 
3479
        attribs['_id_number'] = 2
 
3480
        attribs['_non_present_ids'] = {
 
3481
            'boo': 'new-1',}
3584
3482
        return self.make_records(attribs, [])
3585
3483
 
3586
3484
    def test_serialize_missing(self):
3587
3485
        tt = self.get_preview()
3588
 
        tt.trans_id_file_id(b'boo')
 
3486
        boo_trans_id = tt.trans_id_file_id('boo')
3589
3487
        self.assertSerializesTo(self.missing_records(), tt)
3590
3488
 
3591
3489
    def test_deserialize_missing(self):
3592
3490
        tt = self.get_preview()
3593
3491
        tt.deserialize(iter(self.missing_records()))
3594
 
        self.assertEqual({b'boo': 'new-1'}, tt._non_present_ids)
 
3492
        self.assertEqual({'boo': 'new-1'}, tt._non_present_ids)
3595
3493
 
3596
3494
    def make_modification_preview(self):
3597
3495
        LINES_ONE = b'aa\nbb\ncc\ndd\n'
3599
3497
        tree = self.make_branch_and_tree('tree')
3600
3498
        self.build_tree_contents([('tree/file', LINES_ONE)])
3601
3499
        tree.add('file', b'file-id')
3602
 
        return self.get_preview(tree), [LINES_TWO]
 
3500
        return self.get_preview(tree), LINES_TWO
3603
3501
 
3604
3502
    def modification_records(self):
3605
3503
        attribs = self.default_attribs()
3606
 
        attribs[b'_id_number'] = 2
3607
 
        attribs[b'_tree_path_ids'] = {
3608
 
            b'file': b'new-1',
3609
 
            b'': b'new-0', }
3610
 
        attribs[b'_removed_contents'] = [b'new-1']
3611
 
        contents = [(b'new-1', b'file',
3612
 
                     b'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
 
3504
        attribs['_id_number'] = 2
 
3505
        attribs['_tree_path_ids'] = {
 
3506
            'file': 'new-1',
 
3507
            '': 'new-0',}
 
3508
        attribs['_removed_contents'] = ['new-1']
 
3509
        contents = [('new-1', 'file',
 
3510
                     'i 1\nz\n\nc 0 1 1 1\ni 1\nx\n\nc 0 3 3 1\n')]
3613
3511
        return self.make_records(attribs, contents)
3614
3512
 
3615
3513
    def test_serialize_modification(self):
3616
3514
        tt, LINES = self.make_modification_preview()
3617
 
        trans_id = tt.trans_id_file_id(b'file-id')
 
3515
        trans_id = tt.trans_id_file_id('file-id')
3618
3516
        tt.delete_contents(trans_id)
3619
3517
        tt.create_file(LINES, trans_id)
3620
3518
        self.assertSerializesTo(self.modification_records(), tt)
3622
3520
    def test_deserialize_modification(self):
3623
3521
        tt, LINES = self.make_modification_preview()
3624
3522
        tt.deserialize(iter(self.modification_records()))
3625
 
        self.assertFileEqual(b''.join(LINES), tt._limbo_name('new-1'))
 
3523
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3626
3524
 
3627
3525
    def make_kind_change_preview(self):
3628
 
        LINES = b'a\nb\nc\nd\n'
 
3526
        LINES = 'a\nb\nc\nd\n'
3629
3527
        tree = self.make_branch_and_tree('tree')
3630
3528
        self.build_tree(['tree/foo/'])
3631
3529
        tree.add('foo', b'foo-id')
3632
 
        return self.get_preview(tree), [LINES]
 
3530
        return self.get_preview(tree), LINES
3633
3531
 
3634
3532
    def kind_change_records(self):
3635
3533
        attribs = self.default_attribs()
3636
 
        attribs[b'_id_number'] = 2
3637
 
        attribs[b'_tree_path_ids'] = {
3638
 
            b'foo': b'new-1',
3639
 
            b'': b'new-0', }
3640
 
        attribs[b'_removed_contents'] = [b'new-1']
3641
 
        contents = [(b'new-1', b'file',
3642
 
                     b'i 4\na\nb\nc\nd\n\n')]
 
3534
        attribs['_id_number'] = 2
 
3535
        attribs['_tree_path_ids'] = {
 
3536
            'foo': 'new-1',
 
3537
            '': 'new-0',}
 
3538
        attribs['_removed_contents'] = ['new-1']
 
3539
        contents = [('new-1', 'file',
 
3540
                     'i 4\na\nb\nc\nd\n\n')]
3643
3541
        return self.make_records(attribs, contents)
3644
3542
 
3645
3543
    def test_serialize_kind_change(self):
3652
3550
    def test_deserialize_kind_change(self):
3653
3551
        tt, LINES = self.make_kind_change_preview()
3654
3552
        tt.deserialize(iter(self.kind_change_records()))
3655
 
        self.assertFileEqual(b''.join(LINES), tt._limbo_name('new-1'))
 
3553
        self.assertFileEqual(LINES, tt._limbo_name('new-1'))
3656
3554
 
3657
3555
    def make_add_contents_preview(self):
3658
 
        LINES = b'a\nb\nc\nd\n'
 
3556
        LINES = 'a\nb\nc\nd\n'
3659
3557
        tree = self.make_branch_and_tree('tree')
3660
3558
        self.build_tree(['tree/foo'])
3661
3559
        tree.add('foo')
3664
3562
 
3665
3563
    def add_contents_records(self):
3666
3564
        attribs = self.default_attribs()
3667
 
        attribs[b'_id_number'] = 2
3668
 
        attribs[b'_tree_path_ids'] = {
3669
 
            b'foo': b'new-1',
3670
 
            b'': b'new-0', }
3671
 
        contents = [(b'new-1', b'file',
3672
 
                     b'i 4\na\nb\nc\nd\n\n')]
 
3565
        attribs['_id_number'] = 2
 
3566
        attribs['_tree_path_ids'] = {
 
3567
            'foo': 'new-1',
 
3568
            '': 'new-0',}
 
3569
        contents = [('new-1', 'file',
 
3570
                     'i 4\na\nb\nc\nd\n\n')]
3673
3571
        return self.make_records(attribs, contents)
3674
3572
 
3675
3573
    def test_serialize_add_contents(self):
3676
3574
        tt, LINES = self.make_add_contents_preview()
3677
3575
        trans_id = tt.trans_id_tree_path('foo')
3678
 
        tt.create_file([LINES], trans_id)
 
3576
        tt.create_file(LINES, trans_id)
3679
3577
        self.assertSerializesTo(self.add_contents_records(), tt)
3680
3578
 
3681
3579
    def test_deserialize_add_contents(self):
3685
3583
 
3686
3584
    def test_get_parents_lines(self):
3687
3585
        LINES_ONE = b'aa\nbb\ncc\ndd\n'
 
3586
        LINES_TWO = b'z\nbb\nx\ndd\n'
3688
3587
        tree = self.make_branch_and_tree('tree')
3689
3588
        self.build_tree_contents([('tree/file', LINES_ONE)])
3690
3589
        tree.add('file', b'file-id')
3691
3590
        tt = self.get_preview(tree)
3692
3591
        trans_id = tt.trans_id_tree_path('file')
3693
 
        self.assertEqual(([b'aa\n', b'bb\n', b'cc\n', b'dd\n'],),
3694
 
                         tt._get_parents_lines(trans_id))
 
3592
        self.assertEqual((['aa\n', 'bb\n', 'cc\n', 'dd\n'],),
 
3593
            tt._get_parents_lines(trans_id))
3695
3594
 
3696
3595
    def test_get_parents_texts(self):
3697
3596
        LINES_ONE = b'aa\nbb\ncc\ndd\n'
 
3597
        LINES_TWO = b'z\nbb\nx\ndd\n'
3698
3598
        tree = self.make_branch_and_tree('tree')
3699
3599
        self.build_tree_contents([('tree/file', LINES_ONE)])
3700
3600
        tree.add('file', b'file-id')
3701
3601
        tt = self.get_preview(tree)
3702
3602
        trans_id = tt.trans_id_tree_path('file')
3703
3603
        self.assertEqual((LINES_ONE,),
3704
 
                         tt._get_parents_texts(trans_id))
 
3604
            tt._get_parents_texts(trans_id))
3705
3605
 
3706
3606
 
3707
3607
class TestOrphan(tests.TestCaseWithTransport):
3714
3614
 
3715
3615
    def _set_orphan_policy(self, wt, policy):
3716
3616
        wt.branch.get_config_stack().set('transform.orphan_policy',
3717
 
                                         policy)
 
3617
                                               policy)
3718
3618
 
3719
3619
    def _prepare_orphan(self, wt):
3720
3620
        self.build_tree(['dir/', 'dir/file', 'dir/foo'])
3741
3641
        self._set_orphan_policy(wt, 'move')
3742
3642
        tt, orphan_tid = self._prepare_orphan(wt)
3743
3643
        warnings = []
3744
 
 
3745
3644
        def warning(*args):
3746
3645
            warnings.append(args[0] % args[1:])
3747
3646
        self.overrideAttr(trace, 'warning', warning)
3748
3647
        remaining_conflicts = resolve_conflicts(tt)
3749
3648
        self.assertEqual(['dir/foo has been orphaned in brz-orphans'],
3750
 
                         warnings)
 
3649
                          warnings)
3751
3650
        # Yeah for resolved conflicts !
3752
3651
        self.assertLength(0, remaining_conflicts)
3753
3652
        # We have a new orphan
3754
3653
        self.assertEqual('foo.~1~', tt.final_name(orphan_tid))
3755
3654
        self.assertEqual('brz-orphans',
3756
 
                         tt.final_name(tt.final_parent(orphan_tid)))
 
3655
                          tt.final_name(tt.final_parent(orphan_tid)))
3757
3656
 
3758
3657
    def test_never_orphan(self):
3759
3658
        wt = self.make_branch_and_tree('.')
3784
3683
        self._set_orphan_policy(wt, 'donttouchmypreciouuus')
3785
3684
        tt, orphan_tid = self._prepare_orphan(wt)
3786
3685
        warnings = []
3787
 
 
3788
3686
        def warning(*args):
3789
3687
            warnings.append(args[0] % args[1:])
3790
3688
        self.overrideAttr(trace, 'warning', warning)
3811
3709
 
3812
3710
    def test_pre_commit_hooks(self):
3813
3711
        calls = []
3814
 
 
3815
3712
        def record_pre_transform(tree, tt):
3816
3713
            calls.append((tree, tt))
3817
 
        MutableTree.hooks.install_named_hook(
3818
 
            'pre_transform', record_pre_transform, "Pre transform")
 
3714
        MutableTree.hooks.install_named_hook('pre_transform',
 
3715
            record_pre_transform, "Pre transform")
3819
3716
        transform, root = self.get_transform()
3820
3717
        old_root_id = transform.tree_file_id(root)
3821
3718
        transform.apply()
3822
 
        self.assertEqual(old_root_id, self.wt.path2id(''))
 
3719
        self.assertEqual(old_root_id, self.wt.get_root_id())
3823
3720
        self.assertEqual([(self.wt, transform)], calls)
3824
3721
 
3825
3722
    def test_post_commit_hooks(self):
3826
3723
        calls = []
3827
 
 
3828
3724
        def record_post_transform(tree, tt):
3829
3725
            calls.append((tree, tt))
3830
 
        MutableTree.hooks.install_named_hook(
3831
 
            'post_transform', record_post_transform, "Post transform")
 
3726
        MutableTree.hooks.install_named_hook('post_transform',
 
3727
            record_post_transform, "Post transform")
3832
3728
        transform, root = self.get_transform()
3833
3729
        old_root_id = transform.tree_file_id(root)
3834
3730
        transform.apply()
3835
 
        self.assertEqual(old_root_id, self.wt.path2id(''))
 
3731
        self.assertEqual(old_root_id, self.wt.get_root_id())
3836
3732
        self.assertEqual([(self.wt, transform)], calls)
3837
3733
 
3838
3734