/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

Merge test-run support.

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
64
    text_type,
70
65
    )
71
66
from . import (
147
142
        self.assertEqual(imaginary_id, imaginary_id2)
148
143
        self.assertEqual(root, transform.get_tree_parent(imaginary_id))
149
144
        self.assertEqual('directory', transform.final_kind(root))
150
 
        self.assertEqual(self.wt.path2id(''), transform.final_file_id(root))
 
145
        self.assertEqual(self.wt.get_root_id(), transform.final_file_id(root))
151
146
        trans_id = transform.create_path('name', root)
152
147
        self.assertIs(transform.final_file_id(trans_id), None)
153
148
        self.assertIs(None, transform.final_kind(trans_id))
188
183
                                  sha1=sha1)
189
184
        calls = []
190
185
        orig = self.wt._observed_sha1
191
 
 
192
186
        def _observed_sha1(*args):
193
187
            calls.append(args)
194
188
            orig(*args)
195
189
        self.wt._observed_sha1 = _observed_sha1
196
190
        trans.apply()
197
 
        self.assertEqual([('file1', trans._observed_sha1s[trans_id])],
 
191
        self.assertEqual([(None, 'file1', trans._observed_sha1s[trans_id])],
198
192
                         calls)
199
193
 
200
194
    def test_create_file_caches_sha1(self):
253
247
        transform._creation_mtime = creation_mtime = time.time() - 20.0
254
248
        transform.create_file([b'content-one'],
255
249
                              transform.create_path('one', root))
256
 
        time.sleep(1)  # *ugly*
 
250
        time.sleep(1) # *ugly*
257
251
        transform.create_file([b'content-two'],
258
252
                              transform.create_path('two', root))
259
253
        transform.apply()
262
256
        fo, st2 = self.wt.get_file_with_stat('two', filtered=False)
263
257
        fo.close()
264
258
        # We only guarantee 2s resolution
265
 
        self.assertTrue(
266
 
            abs(creation_mtime - st1.st_mtime) < 2.0,
 
259
        self.assertTrue(abs(creation_mtime - st1.st_mtime) < 2.0,
267
260
            "%s != %s within 2 seconds" % (creation_mtime, st1.st_mtime))
268
261
        # But if we have more than that, all files should get the same result
269
262
        self.assertEqual(st1.st_mtime, st2.st_mtime)
270
263
 
271
264
    def test_change_root_id(self):
272
265
        transform, root = self.get_transform()
273
 
        self.assertNotEqual(b'new-root-id', self.wt.path2id(''))
 
266
        self.assertNotEqual(b'new-root-id', self.wt.get_root_id())
274
267
        transform.new_directory('', ROOT_PARENT, b'new-root-id')
275
268
        transform.delete_contents(root)
276
269
        transform.unversion_file(root)
277
270
        transform.fixup_new_roots()
278
271
        transform.apply()
279
 
        self.assertEqual(b'new-root-id', self.wt.path2id(''))
 
272
        self.assertEqual(b'new-root-id', self.wt.get_root_id())
280
273
 
281
274
    def test_change_root_id_add_files(self):
282
275
        transform, root = self.get_transform()
283
 
        self.assertNotEqual(b'new-root-id', self.wt.path2id(''))
 
276
        self.assertNotEqual(b'new-root-id', self.wt.get_root_id())
284
277
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
285
278
        transform.new_file('file', new_trans_id, [b'new-contents\n'],
286
279
                           b'new-file-id')
288
281
        transform.unversion_file(root)
289
282
        transform.fixup_new_roots()
290
283
        transform.apply()
291
 
        self.assertEqual(b'new-root-id', self.wt.path2id(''))
 
284
        self.assertEqual(b'new-root-id', self.wt.get_root_id())
292
285
        self.assertEqual(b'new-file-id', self.wt.path2id('file'))
293
286
        self.assertFileEqual(b'new-contents\n', self.wt.abspath('file'))
294
287
 
295
288
    def test_add_two_roots(self):
296
289
        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')
 
290
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
 
291
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'alt-root-id')
299
292
        self.assertRaises(ValueError, transform.fixup_new_roots)
300
293
 
301
294
    def test_retain_existing_root(self):
314
307
 
315
308
    def test_add_unversioned_root(self):
316
309
        transform, root = self.get_transform()
317
 
        transform.new_directory('', ROOT_PARENT, None)
 
310
        new_trans_id = transform.new_directory('', ROOT_PARENT, None)
318
311
        transform.delete_contents(transform.root)
319
312
        transform.fixup_new_roots()
320
313
        self.assertNotIn(transform.root, transform._new_id)
321
314
 
322
315
    def test_remove_root_fixup(self):
323
316
        transform, root = self.get_transform()
324
 
        old_root_id = self.wt.path2id('')
 
317
        old_root_id = self.wt.get_root_id()
325
318
        self.assertNotEqual(b'new-root-id', old_root_id)
326
319
        transform.delete_contents(root)
327
320
        transform.unversion_file(root)
328
321
        transform.fixup_new_roots()
329
322
        transform.apply()
330
 
        self.assertEqual(old_root_id, self.wt.path2id(''))
 
323
        self.assertEqual(old_root_id, self.wt.get_root_id())
331
324
 
332
325
        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')
 
326
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
 
327
        new_trans_id = transform.new_directory('', ROOT_PARENT, b'alt-root-id')
335
328
        self.assertRaises(ValueError, transform.fixup_new_roots)
336
329
 
337
330
    def test_fixup_new_roots_permits_empty_tree(self):
358
351
        old_root_id = transform.tree_file_id(root)
359
352
        transform.unversion_file(root)
360
353
        transform.apply()
361
 
        self.assertEqual(old_root_id, self.wt.path2id(''))
 
354
        self.assertEqual(old_root_id, self.wt.get_root_id())
362
355
 
363
356
    def test_hardlink(self):
364
357
        self.requireFeature(HardlinkFeature)
379
372
        transform, root = self.get_transform()
380
373
        self.wt.lock_tree_write()
381
374
        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')
 
375
        trans_id = transform.new_file('name', root, [b'contents'],
 
376
                                      b'my_pretties', True)
 
377
        oz = transform.new_directory('oz', root, 'oz-id')
384
378
        dorothy = transform.new_directory('dorothy', oz, b'dorothy-id')
385
 
        transform.new_file('toto', dorothy, [b'toto-contents'], b'toto-id',
386
 
                           False)
 
379
        toto = transform.new_file('toto', dorothy, [b'toto-contents'],
 
380
                                  b'toto-id', False)
387
381
 
388
382
        self.assertEqual(len(transform.find_conflicts()), 0)
389
383
        transform.apply()
390
384
        self.assertRaises(ReusingTransform, transform.find_conflicts)
391
385
        with open(self.wt.abspath('name'), 'r') as f:
392
386
            self.assertEqual('contents', f.read())
393
 
        self.assertEqual(self.wt.path2id('name'), b'my_pretties')
 
387
        self.assertEqual(self.wt.path2id('name'), 'my_pretties')
394
388
        self.assertIs(self.wt.is_executable('name'), True)
395
389
        self.assertEqual(self.wt.path2id('oz'), b'oz-id')
396
390
        self.assertEqual(self.wt.path2id('oz/dorothy'), b'dorothy-id')
403
397
    def test_tree_reference(self):
404
398
        transform, root = self.get_transform()
405
399
        tree = transform._tree
406
 
        trans_id = transform.new_directory('reference', root, b'subtree-id')
407
 
        transform.set_tree_reference(b'subtree-revision', trans_id)
 
400
        trans_id = transform.new_directory('reference', root, 'subtree-id')
 
401
        transform.set_tree_reference('subtree-revision', trans_id)
408
402
        transform.apply()
409
403
        tree.lock_read()
410
404
        self.addCleanup(tree.unlock)
411
 
        self.assertEqual(
412
 
            b'subtree-revision',
413
 
            tree.root_inventory.get_entry(b'subtree-id').reference_revision)
 
405
        self.assertEqual('subtree-revision',
 
406
                         tree.root_inventory.get_entry('subtree-id').reference_revision)
414
407
 
415
408
    def test_conflicts(self):
416
409
        transform, root = self.get_transform()
437
430
        self.assertEqual(transform.find_conflicts(),
438
431
                         [('unversioned parent', lion_id),
439
432
                          ('missing parent', lion_id)])
440
 
        transform.version_file(b"Courage", lion_id)
 
433
        transform.version_file("Courage", lion_id)
441
434
        self.assertEqual(transform.find_conflicts(),
442
435
                         [('missing parent', lion_id),
443
436
                          ('versioning no contents', lion_id)])
461
454
        tip_id = transform.new_file('tip', oz_id, [b'ozma'], b'tip-id')
462
455
        transform.apply()
463
456
        self.assertEqual(self.wt.path2id('name'), b'my_pretties')
464
 
        with open(self.wt.abspath('name'), 'rb') as f:
 
457
        with open(self.wt.abspath('name'), 'r') as f:
465
458
            self.assertEqual(b'contents', f.read())
466
459
        transform2, root = self.get_transform()
467
460
        oz_id = transform2.trans_id_tree_path('oz')
609
602
 
610
603
    def test_add_del(self):
611
604
        start, root = self.get_transform()
612
 
        start.new_directory('a', root, b'a')
 
605
        start.new_directory('a', root, 'a')
613
606
        start.apply()
614
607
        transform, root = self.get_transform()
615
608
        transform.delete_versioned(transform.trans_id_tree_path('a'))
616
 
        transform.new_directory('a', root, b'a')
 
609
        transform.new_directory('a', root, 'a')
617
610
        transform.apply()
618
611
 
619
612
    def test_unversioning(self):
645
638
 
646
639
        mangle_tree, root = self.get_transform()
647
640
        root = mangle_tree.root
648
 
        # swap names
 
641
        #swap names
649
642
        name1 = mangle_tree.trans_id_tree_path('name1')
650
643
        name2 = mangle_tree.trans_id_tree_path('name2')
651
644
        mangle_tree.adjust_path('name2', root, name1)
652
645
        mangle_tree.adjust_path('name1', root, name2)
653
646
 
654
 
        # tests for deleting parent directories
 
647
        #tests for deleting parent directories
655
648
        ddir = mangle_tree.trans_id_tree_path('dying_directory')
656
649
        mangle_tree.delete_contents(ddir)
657
650
        dfile = mangle_tree.trans_id_tree_path('dying_directory/dying_file')
660
653
        mfile = mangle_tree.trans_id_tree_path('dying_directory/moving_file')
661
654
        mangle_tree.adjust_path('mfile', root, mfile)
662
655
 
663
 
        # tests for adding parent directories
664
 
        newdir = mangle_tree.new_directory('new_directory', root, b'newdir')
 
656
        #tests for adding parent directories
 
657
        newdir = mangle_tree.new_directory('new_directory', root, 'newdir')
665
658
        mfile2 = mangle_tree.trans_id_tree_path('moving_file2')
666
659
        mangle_tree.adjust_path('mfile2', newdir, mfile2)
667
660
        mangle_tree.new_file('newfile', newdir, [b'hello3'], b'dfile')
689
682
    def test_both_rename(self):
690
683
        create_tree, root = self.get_transform()
691
684
        newdir = create_tree.new_directory('selftest', root, b'selftest-id')
692
 
        create_tree.new_file('blackbox.py', newdir, [
693
 
                             b'hello1'], b'blackbox-id')
 
685
        create_tree.new_file('blackbox.py', newdir, [b'hello1'], b'blackbox-id')
694
686
        create_tree.apply()
695
687
        mangle_tree, root = self.get_transform()
696
688
        selftest = mangle_tree.trans_id_tree_path('selftest')
702
694
 
703
695
    def test_both_rename2(self):
704
696
        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')
 
697
        breezy = create_tree.new_directory('breezy', root, 'breezy-id')
 
698
        tests = create_tree.new_directory('tests', breezy, 'tests-id')
 
699
        blackbox = create_tree.new_directory('blackbox', tests, 'blackbox-id')
708
700
        create_tree.new_file('test_too_much.py', blackbox, [b'hello1'],
709
701
                             b'test_too_much-id')
710
702
        create_tree.apply()
711
703
        mangle_tree, root = self.get_transform()
712
704
        breezy = mangle_tree.trans_id_tree_path('breezy')
713
705
        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')
 
706
        test_too_much = mangle_tree.trans_id_tree_path('breezy/tests/blackbox/test_too_much.py')
716
707
        mangle_tree.adjust_path('selftest', breezy, tests)
717
708
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
718
709
        mangle_tree.set_executability(True, test_too_much)
726
717
        create_tree.apply()
727
718
        mangle_tree, root = self.get_transform()
728
719
        tests = mangle_tree.trans_id_tree_path('tests')
729
 
        test_too_much = mangle_tree.trans_id_tree_path(
730
 
            'tests/test_too_much.py')
 
720
        test_too_much = mangle_tree.trans_id_tree_path('tests/test_too_much.py')
731
721
        mangle_tree.adjust_path('selftest', root, tests)
732
722
        mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
733
723
        mangle_tree.set_executability(True, test_too_much)
740
730
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
741
731
        create_tree.apply()
742
732
        delete_contents, root = self.get_transform()
743
 
        file = delete_contents.trans_id_tree_path('name1')
 
733
        file = delete_contents.trans_id_tree_path(b'name1')
744
734
        delete_contents.delete_contents(file)
745
735
        delete_contents.apply()
746
736
        move_id, root = self.get_transform()
747
737
        name1 = move_id.trans_id_tree_path('name1')
748
 
        newdir = move_id.new_directory('dir', root, b'newdir')
 
738
        newdir = move_id.new_directory('dir', root, 'newdir')
749
739
        move_id.adjust_path('name2', newdir, name1)
750
740
        move_id.apply()
751
741
 
753
743
        create_tree, root = self.get_transform()
754
744
        # prepare tree
755
745
        root = create_tree.root
756
 
        create_tree.new_file('name1', root, [b'hello1'], b'name1')
 
746
        create_tree.new_file('name1', root, [b'hello1'], 'name1')
757
747
        create_tree.apply()
758
748
        delete_contents = TreeTransform(self.wt)
759
749
        self.addCleanup(delete_contents.finalize)
763
753
        delete_contents.finalize()
764
754
        replace = TreeTransform(self.wt)
765
755
        self.addCleanup(replace.finalize)
766
 
        name2 = replace.new_file('name2', root, [b'hello2'], b'name1')
 
756
        name2 = replace.new_file('name2', root, [b'hello2'], 'name1')
767
757
        conflicts = replace.find_conflicts()
768
758
        name1 = replace.trans_id_tree_path('name1')
769
759
        self.assertEqual(conflicts, [('duplicate id', name1, name2)])
773
763
    def _test_symlinks(self, link_name1, link_target1,
774
764
                       link_name2, link_target2):
775
765
 
776
 
        def ozpath(p):
777
 
            return 'oz/' + p
 
766
        def ozpath(p): return 'oz/' + p
778
767
 
779
768
        self.requireFeature(SymlinkFeature)
780
769
        transform, root = self.get_transform()
781
770
        oz_id = transform.new_directory('oz', root, b'oz-id')
782
 
        transform.new_symlink(link_name1, oz_id, link_target1, b'wizard-id')
 
771
        wizard = transform.new_symlink(link_name1, oz_id, link_target1,
 
772
                                       b'wizard-id')
783
773
        wiz_id = transform.create_path(link_name2, oz_id)
784
774
        transform.create_symlink(link_target2, wiz_id)
785
775
        transform.version_file(b'wiz-id2', wiz_id)
807
797
                            u'\N{Euro Sign}wizard2',
808
798
                            u'b\N{Euro Sign}hind_curtain')
809
799
 
810
 
    def test_unsupported_symlink_no_conflict(self):
 
800
    def test_unable_create_symlink(self):
811
801
        def tt_helper():
812
802
            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)
 
803
            tt = TreeTransform(wt)  # TreeTransform obtains write lock
 
804
            try:
 
805
                tt.new_symlink('foo', tt.root, 'bar')
 
806
                tt.apply()
 
807
            finally:
 
808
                wt.unlock()
818
809
        os_symlink = getattr(os, 'symlink', None)
819
810
        os.symlink = None
820
811
        try:
821
 
            tt_helper()
 
812
            err = self.assertRaises(errors.UnableCreateSymlink, tt_helper)
 
813
            self.assertEqual(
 
814
                "Unable to create symlink 'foo' on this platform",
 
815
                str(err))
822
816
        finally:
823
817
            if os_symlink:
824
818
                os.symlink = os_symlink
853
847
        self.assertEqual(conflicts.final_name(old_dorothy), 'dorothy.moved')
854
848
        self.assertIs(conflicts.final_file_id(old_dorothy), None)
855
849
        self.assertEqual(conflicts.final_name(new_dorothy), 'dorothy')
856
 
        self.assertEqual(conflicts.final_file_id(new_dorothy), b'dorothy-id')
 
850
        self.assertEqual(conflicts.final_file_id(new_dorothy), 'dorothy-id')
857
851
        self.assertEqual(conflicts.final_parent(emerald), oz)
858
852
        conflicts.apply()
859
853
 
876
870
                                               'munchkincity',
877
871
                                               b'munchkincity-id')
878
872
        unversioned_parent2 = UnversionedParent('Versioned directory', 'oz',
879
 
                                                b'oz-id')
 
873
                                               b'oz-id')
880
874
        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')
 
875
        parent_loop = ParentLoop('Cancelled move', 'oz/emeraldcity',
 
876
                                 'oz/emeraldcity', b'emerald-id', b'emerald-id')
884
877
        self.assertEqual(cooked_conflicts[4], deleted_parent)
885
878
        self.assertEqual(cooked_conflicts[5], unversioned_parent2)
886
879
        self.assertEqual(cooked_conflicts[6], parent_loop)
905
898
        self.assertEqual(conflicts_s[3], 'Conflict because munchkincity is not'
906
899
                                         ' versioned, but has versioned'
907
900
                                         ' children.  Versioned directory.')
908
 
        self.assertEqualDiff(
909
 
            conflicts_s[4], "Conflict: can't delete oz because it"
910
 
                            " is not empty.  Not deleting.")
 
901
        self.assertEqualDiff(conflicts_s[4], "Conflict: can't delete oz because it"
 
902
                                         " is not empty.  Not deleting.")
911
903
        self.assertEqual(conflicts_s[5], 'Conflict because oz is not'
912
904
                                         ' versioned, but has versioned'
913
905
                                         ' children.  Versioned directory.')
931
923
        tt = self.prepare_wrong_parent_kind()
932
924
        raw_conflicts = resolve_conflicts(tt)
933
925
        self.assertEqual({('non-directory parent', 'Created directory',
934
 
                           'new-3')}, raw_conflicts)
 
926
                         'new-3')}, raw_conflicts)
935
927
        cooked_conflicts = cook_conflicts(raw_conflicts, tt)
936
928
        self.assertEqual([NonDirectoryParent('Created directory', 'parent.new',
937
 
                                             b'parent-id')], cooked_conflicts)
 
929
        b'parent-id')], cooked_conflicts)
938
930
        tt.apply()
939
931
        self.assertFalse(self.wt.is_versioned('parent'))
940
 
        self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
 
932
        self.assertEqual('parent-id', self.wt.path2id('parent.new'))
941
933
 
942
934
    def test_resolve_conflicts_wrong_new_parent_kind(self):
943
935
        tt, root = self.get_transform()
950
942
        tt.create_file([b'contents'], parent_id)
951
943
        raw_conflicts = resolve_conflicts(tt)
952
944
        self.assertEqual({('non-directory parent', 'Created directory',
953
 
                           'new-3')}, raw_conflicts)
 
945
                         'new-3')}, raw_conflicts)
954
946
        tt.apply()
955
947
        self.assertFalse(self.wt.is_versioned('parent'))
956
948
        self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
986
978
 
987
979
    def test_moving_versioned_directories(self):
988
980
        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')
 
981
        kansas = create.new_directory('kansas', root, 'kansas-id')
 
982
        create.new_directory('house', kansas, 'house-id')
 
983
        create.new_directory('oz', root, 'oz-id')
992
984
        create.apply()
993
985
        cyclone, root = self.get_transform()
994
986
        oz = cyclone.trans_id_tree_path('oz')
1026
1018
        self.requireFeature(features.not_running_as_root)
1027
1019
        # see https://bugs.launchpad.net/bzr/+bug/491763
1028
1020
        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')
 
1021
        first_dir = create.new_directory('first-dir', root_id, b'first-id')
 
1022
        myfile = create.new_file('myfile', root_id, [b'myfile-text'],
 
1023
                                 b'myfile-id')
1031
1024
        create.apply()
1032
1025
        if os.name == "posix" and sys.platform != "cygwin":
1033
1026
            # posix filesystems fail on renaming if the readonly bit is set
1043
1036
        dir_id = rename_transform.trans_id_file_id(b'first-id')
1044
1037
        rename_transform.adjust_path('newname', dir_id, file_trans_id)
1045
1038
        e = self.assertRaises(errors.TransformRenameFailed,
1046
 
                              rename_transform.apply)
1047
 
        # On nix looks like:
 
1039
            rename_transform.apply)
 
1040
        # On nix looks like: 
1048
1041
        # "Failed to rename .../work/.bzr/checkout/limbo/new-1
1049
1042
        # to .../first-dir/newname: [Errno 13] Permission denied"
1050
1043
        # On windows looks like:
1051
 
        # "Failed to rename .../work/myfile to
 
1044
        # "Failed to rename .../work/myfile to 
1052
1045
        # .../work/.bzr/checkout/limbo/new-1: [Errno 13] Permission denied"
1053
1046
        # This test isn't concerned with exactly what the error looks like,
1054
1047
        # and the strerror will vary across OS and locales, but the assert
1064
1057
 
1065
1058
        - create file and set executability simultaneously
1066
1059
        - create file and set executability afterward
1067
 
        - unsetting the executability of a file whose executability has not
1068
 
          been
 
1060
        - unsetting the executability of a file whose executability has not been
1069
1061
        declared should throw an exception (this may happen when a
1070
1062
        merge attempts to create a file with a duplicate ID)
1071
1063
        """
1073
1065
        wt = transform._tree
1074
1066
        wt.lock_read()
1075
1067
        self.addCleanup(wt.unlock)
1076
 
        transform.new_file('set_on_creation', root, [b'Set on creation'],
1077
 
                           b'soc', True)
 
1068
        transform.new_file('set_on_creation', root, [b'Set on creation'], 'soc',
 
1069
                           True)
1078
1070
        sac = transform.new_file('set_after_creation', root,
1079
 
                                 [b'Set after creation'], b'sac')
 
1071
                                 [b'Set after creation'], 'sac')
1080
1072
        transform.set_executability(True, sac)
1081
1073
        uws = transform.new_file('unset_without_set', root, [b'Unset badly'],
1082
 
                                 b'uws')
 
1074
                                 'uws')
1083
1075
        self.assertRaises(KeyError, transform.set_executability, None, uws)
1084
1076
        transform.apply()
1085
1077
        self.assertTrue(wt.is_executable('set_on_creation'))
1109
1101
 
1110
1102
        stat_paths = []
1111
1103
        real_stat = os.stat
1112
 
 
1113
1104
        def instrumented_stat(path):
1114
1105
            stat_paths.append(path)
1115
1106
            return real_stat(path)
1125
1116
        bar2_id = transform.trans_id_tree_path('bar2')
1126
1117
        try:
1127
1118
            os.stat = instrumented_stat
1128
 
            transform.create_file([b'bar2 contents\n'],
1129
 
                                  bar2_id, mode_id=bar1_id)
 
1119
            transform.create_file([b'bar2 contents\n'], bar2_id, mode_id=bar1_id)
1130
1120
        finally:
1131
1121
            os.stat = real_stat
1132
1122
            transform.finalize()
1145
1135
            old = transform.trans_id_tree_path('old')
1146
1136
            transform.unversion_file(old)
1147
1137
            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()))
 
1138
                (b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1139
                (True, True))], list(transform.iter_changes()))
1152
1140
            transform.new_directory('new', root, b'id-1')
1153
1141
            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()))
 
1142
                (b'eert_toor', b'eert_toor'), ('old', 'new'),
 
1143
                ('file', 'directory'),
 
1144
                (True, False))], list(transform.iter_changes()))
1158
1145
        finally:
1159
1146
            transform.finalize()
1160
1147
 
1168
1155
            old = transform.trans_id_tree_path('old')
1169
1156
            transform.version_file(b'id-1', old)
1170
1157
            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()))
 
1158
                (b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1159
                (False, False))], list(transform.iter_changes()))
1175
1160
        finally:
1176
1161
            transform.finalize()
1177
1162
 
1178
1163
    def test_iter_changes_modifications(self):
1179
1164
        self.wt.set_root_id(b'eert_toor')
1180
1165
        transform, root = self.get_transform()
1181
 
        transform.new_file('old', root, [b'blah'], b'id-1')
 
1166
        transform.new_file('old', root, [b'blah'], 'id-1')
1182
1167
        transform.new_file('new', root, [b'blah'])
1183
 
        transform.new_directory('subdir', root, b'subdir-id')
 
1168
        transform.new_directory('subdir', root, 'subdir-id')
1184
1169
        transform.apply()
1185
1170
        transform, root = self.get_transform()
1186
1171
        try:
1189
1174
            new = transform.trans_id_tree_path('new')
1190
1175
            self.assertEqual([], list(transform.iter_changes()))
1191
1176
 
1192
 
            # content deletion
 
1177
            #content deletion
1193
1178
            transform.delete_contents(old)
1194
1179
            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()))
 
1180
                (b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', None),
 
1181
                (False, False))], list(transform.iter_changes()))
1199
1182
 
1200
 
            # content change
 
1183
            #content change
1201
1184
            transform.create_file([b'blah'], old)
1202
1185
            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()))
 
1186
                (b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1187
                (False, False))], list(transform.iter_changes()))
1207
1188
            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()))
 
1189
            self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
 
1190
                (b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1191
                (False, False))], list(transform.iter_changes()))
1213
1192
            transform.cancel_creation(old)
1214
1193
 
1215
1194
            # move file_id to a different file
1218
1197
            transform.version_file(b'id-1', new)
1219
1198
            transform.adjust_path('old', root, new)
1220
1199
            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()))
 
1200
                ('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1201
                (False, False))], list(transform.iter_changes()))
1225
1202
            transform.cancel_versioning(new)
1226
1203
            transform._removed_id = set()
1227
1204
 
1228
 
            # execute bit
 
1205
            #execute bit
1229
1206
            self.assertEqual([], list(transform.iter_changes()))
1230
1207
            transform.set_executability(True, old)
1231
1208
            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()))
 
1209
                (b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
 
1210
                (False, True))], list(transform.iter_changes()))
1236
1211
            transform.set_executability(None, old)
1237
1212
 
1238
1213
            # filename
1240
1215
            transform.adjust_path('new', root, old)
1241
1216
            transform._new_parent = {}
1242
1217
            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()))
 
1218
                (b'eert_toor', b'eert_toor'), ('old', 'new'), ('file', 'file'),
 
1219
                (False, False))], list(transform.iter_changes()))
1247
1220
            transform._new_name = {}
1248
1221
 
1249
1222
            # parent directory
1251
1224
            transform.adjust_path('new', subdir, old)
1252
1225
            transform._new_name = {}
1253
1226
            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()))
 
1227
                (True, True), (b'eert_toor', b'subdir-id'), ('old', 'old'),
 
1228
                ('file', 'file'), (False, False))],
 
1229
                list(transform.iter_changes()))
1258
1230
            transform._new_path = {}
1259
1231
 
1260
1232
        finally:
1275
1247
        try:
1276
1248
            transform.delete_contents(transform.trans_id_file_id(b'id-1'))
1277
1249
            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)],
 
1250
            transform.trans_id_file_id(b'id-2'))
 
1251
            self.assertEqual([(b'id-1', (u'file1', u'file1'), True, (True, True),
 
1252
                (b'eert_toor', b'eert_toor'), ('file1', u'file1'),
 
1253
                ('file', None), (False, False)),
 
1254
                (b'id-2', (u'file2', u'file2'), False, (True, True),
 
1255
                (b'eert_toor', b'eert_toor'), ('file2', u'file2'),
 
1256
                ('file', 'file'), (False, True))],
1286
1257
                list(transform.iter_changes()))
1287
1258
        finally:
1288
1259
            transform.finalize()
1302
1273
        try:
1303
1274
            transform.adjust_path('flitter', root, floater)
1304
1275
            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()))
 
1276
            (True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
 
1277
            (None, None), (False, False))], list(transform.iter_changes()))
1310
1278
        finally:
1311
1279
            transform.finalize()
1312
1280
 
1433
1401
            transform.create_directory(parent)
1434
1402
        except KeyError:
1435
1403
            self.fail("Can't handle contents with no name")
1436
 
        transform.new_directory('child', parent)
 
1404
        child = transform.new_directory('child', parent)
1437
1405
        transform.adjust_path('parent', root, parent)
1438
1406
        transform.apply()
1439
1407
        self.assertPathExists(self.wt.abspath('parent/child'))
1443
1411
        """Avoid reusing the same limbo name for different files"""
1444
1412
        transform, root = self.get_transform()
1445
1413
        parent = transform.new_directory('parent', root)
1446
 
        transform.new_directory('child', parent)
 
1414
        child1 = transform.new_directory('child', parent)
1447
1415
        try:
1448
1416
            child2 = transform.new_directory('child', parent)
1449
1417
        except OSError:
1463
1431
        parent = transform.new_directory('parent', root)
1464
1432
        child1 = transform.new_directory('child', parent)
1465
1433
        transform.adjust_path('child1', parent, child1)
1466
 
        transform.new_directory('child', parent)
 
1434
        child2 = transform.new_directory('child', parent)
1467
1435
        transform.apply()
1468
1436
        # limbo/new-1 => parent
1469
1437
        self.assertEqual(1, transform.rename_count)
1475
1443
        child1 = transform.new_directory('child1', parent2)
1476
1444
        transform.cancel_creation(parent2)
1477
1445
        transform.create_directory(parent2)
1478
 
        transform.new_directory('child1', parent2)
 
1446
        child2 = transform.new_directory('child1', parent2)
1479
1447
        transform.adjust_path('child2', parent2, child1)
1480
1448
        transform.apply()
1481
1449
        # limbo/new-1 => parent2, limbo/new-2 => parent2/child1
1485
1453
        """Finalize must be done in child-to-parent order"""
1486
1454
        transform, root = self.get_transform()
1487
1455
        parent = transform.new_directory('parent', root)
1488
 
        transform.new_directory('child', parent)
 
1456
        child = transform.new_directory('child', parent)
1489
1457
        try:
1490
1458
            transform.finalize()
1491
1459
        except OSError:
1512
1480
                tt.adjust_path('baz', tt.root, foo)
1513
1481
                # Lie to tt that we've already resolved all conflicts.
1514
1482
                tt.apply(no_conflicts=True)
1515
 
            except BaseException:
 
1483
            except:
1516
1484
                wt.unlock()
1517
1485
                raise
1518
1486
        # The rename will fail because the target directory is not empty (but
1532
1500
                tt.new_directory('baz', foo_2)
1533
1501
                # Lie to tt that we've already resolved all conflicts.
1534
1502
                tt.apply(no_conflicts=True)
1535
 
            except BaseException:
 
1503
            except:
1536
1504
                wt.unlock()
1537
1505
                raise
1538
1506
        err = self.assertRaises(errors.FileExists, tt_helper)
1550
1518
                tt.new_directory('baz', foo_2)
1551
1519
                # Lie to tt that we've already resolved all conflicts.
1552
1520
                tt.apply(no_conflicts=True)
1553
 
            except BaseException:
 
1521
            except:
1554
1522
                tt.finalize()
1555
1523
                raise
1556
1524
        err = self.assertRaises(errors.FileExists, tt_helper)
1568
1536
        tt.create_directory(foo_trans_id)
1569
1537
        bar_trans_id = tt.trans_id_tree_path("foo/bar")
1570
1538
        tt.create_file([b"aa\n"], bar_trans_id)
1571
 
        tt.version_file(b"bar-1", bar_trans_id)
 
1539
        tt.version_file("bar-1", bar_trans_id)
1572
1540
        tt.apply()
1573
1541
        self.assertPathExists("foo/bar")
1574
1542
        wt.lock_read()
1597
1565
        self.addCleanup(wt.unlock)
1598
1566
        self.assertEqual(wt.kind("foo"), "symlink")
1599
1567
 
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
1568
    def test_dir_to_file(self):
1619
1569
        wt = self.make_branch_and_tree('.')
1620
1570
        self.build_tree(['foo/', 'foo/bar'])
1668
1618
        tree2 = self.make_branch_and_tree('tree2')
1669
1619
        tt = TreeTransform(tree2)
1670
1620
        foo_trans_id = tt.create_path('foo', tt.root)
1671
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo')
 
1621
        create_from_tree(tt, foo_trans_id, tree1, 'foo', file_id=b'foo-id')
1672
1622
        bar_trans_id = tt.create_path('bar', tt.root)
1673
 
        create_from_tree(tt, bar_trans_id, tree1, 'bar')
 
1623
        create_from_tree(tt, bar_trans_id, tree1, 'bar', file_id=b'bar-id')
1674
1624
        tt.apply()
1675
1625
        self.assertEqual('directory', osutils.file_kind('tree2/foo'))
1676
1626
        self.assertFileEqual(b'baz', 'tree2/bar')
1678
1628
    def test_create_from_tree_bytes(self):
1679
1629
        """Provided lines are used instead of tree content."""
1680
1630
        tree1 = self.make_branch_and_tree('tree1')
1681
 
        self.build_tree_contents([('tree1/foo', b'bar'), ])
 
1631
        self.build_tree_contents([('tree1/foo', b'bar'),])
1682
1632
        tree1.add('foo', b'foo-id')
1683
1633
        tree2 = self.make_branch_and_tree('tree2')
1684
1634
        tt = TreeTransform(tree2)
1685
1635
        foo_trans_id = tt.create_path('foo', tt.root)
1686
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo', chunks=[b'qux'])
 
1636
        create_from_tree(tt, foo_trans_id, tree1, 'foo', file_id=b'foo-id',
 
1637
                         chunks=[b'qux'])
1687
1638
        tt.apply()
1688
1639
        self.assertFileEqual(b'qux', 'tree2/foo')
1689
1640
 
1694
1645
        tree1.add('foo', b'foo-id')
1695
1646
        tt = TreeTransform(self.make_branch_and_tree('tree2'))
1696
1647
        foo_trans_id = tt.create_path('foo', tt.root)
1697
 
        create_from_tree(tt, foo_trans_id, tree1, 'foo')
 
1648
        create_from_tree(tt, foo_trans_id, tree1, 'foo', file_id=b'foo-id')
1698
1649
        tt.apply()
1699
1650
        self.assertEqual('bar', os.readlink('tree2/foo'))
1700
1651
 
1743
1694
        tree.add('foo', b'foo-id')
1744
1695
        with TransformPreview(tree) as tt:
1745
1696
            tt.unversion_file(tt.root)
1746
 
            tt.version_file(tree.path2id(''), tt.root)
1747
 
            tt.trans_id_tree_path('foo')
 
1697
            tt.version_file(tree.get_root_id(), tt.root)
 
1698
            foo_trans_id = tt.trans_id_tree_path('foo')
1748
1699
            self.assertEqual([], tt._inventory_altered())
1749
1700
 
1750
1701
 
1791
1742
            self.assertEqual(f.read(), b'y\nb\nc\nd\bz\n')
1792
1743
        # three-way text conflict
1793
1744
        with this.wt.get_file(this.wt.id2path(b'b')) as f:
1794
 
            self.assertEqual(f.read(), conflict_text(b'b', b'b2'))
 
1745
            self.assertEqual(f.read(), conflict_text('b', 'b2'))
1795
1746
        # OTHER wins
1796
1747
        self.assertEqual(this.wt.get_file(this.wt.id2path(b'c')).read(), b'c2')
1797
1748
        # THIS wins
1821
1772
        merge_modified = this.wt.merge_modified()
1822
1773
        self.assertSubset(merge_modified, modified)
1823
1774
        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')
 
1775
        with open(this.wt.abspath(this.wt.id2path('a')), 'wb') as f: f.write(b'booga')
1826
1776
        modified.pop(0)
1827
1777
        merge_modified = this.wt.merge_modified()
1828
1778
        self.assertSubset(merge_modified, modified)
1848
1798
            for link, target in (('e', e_target), ('f', f_target),
1849
1799
                                 ('g', g_target), ('h', h_target)):
1850
1800
                if target is not None:
1851
 
                    tg.tt.new_symlink(link, tg.root, target,
1852
 
                                      link.encode('ascii'))
 
1801
                    tg.tt.new_symlink(link, tg.root, target, link)
1853
1802
 
1854
1803
        for tg in this, base, other:
1855
1804
            tg.tt.apply()
1858
1807
        self.assertIs(os.path.islink(this.wt.abspath('b')), True)
1859
1808
        self.assertIs(os.path.isfile(this.wt.abspath('c')), True)
1860
1809
        for suffix in ('THIS', 'BASE', 'OTHER'):
1861
 
            self.assertEqual(os.readlink(
1862
 
                this.wt.abspath('d.' + suffix)), suffix)
 
1810
            self.assertEqual(os.readlink(this.wt.abspath('d.'+suffix)), suffix)
1863
1811
        self.assertIs(os.path.lexists(this.wt.abspath('d')), False)
1864
1812
        self.assertEqual(this.wt.id2path(b'd'), 'd.OTHER')
1865
1813
        self.assertEqual(this.wt.id2path(b'f'), 'f.THIS')
1879
1827
        base = TransformGroup("BASE", root_id)
1880
1828
        this = TransformGroup("THIS", root_id)
1881
1829
        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')
 
1830
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a')
 
1831
                                   for t in [base, this, other]]
 
1832
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b')
 
1833
                                   for t in [base, this, other]]
 
1834
        base.tt.new_directory('c', base_a, 'c')
 
1835
        this.tt.new_directory('c1', this_a, 'c')
 
1836
        other.tt.new_directory('c', other_b, 'c')
 
1837
 
 
1838
        base.tt.new_directory('d', base_a, 'd')
 
1839
        this.tt.new_directory('d1', this_b, 'd')
 
1840
        other.tt.new_directory('d', other_a, 'd')
 
1841
 
 
1842
        base.tt.new_directory('e', base_a, 'e')
 
1843
        this.tt.new_directory('e', this_a, 'e')
 
1844
        other.tt.new_directory('e1', other_b, 'e')
 
1845
 
 
1846
        base.tt.new_directory('f', base_a, 'f')
 
1847
        this.tt.new_directory('f1', this_b, 'f')
 
1848
        other.tt.new_directory('f1', other_b, 'f')
1901
1849
 
1902
1850
        for tg in [this, base, other]:
1903
1851
            tg.tt.apply()
1912
1860
        base = TransformGroup("BASE", root_id)
1913
1861
        this = TransformGroup("THIS", root_id)
1914
1862
        other = TransformGroup("OTHER", root_id)
1915
 
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, b'a')
 
1863
        base_a, this_a, other_a = [t.tt.new_directory('a', t.root, 'a')
1916
1864
                                   for t in [base, this, other]]
1917
 
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, b'b')
 
1865
        base_b, this_b, other_b = [t.tt.new_directory('b', t.root, 'b')
1918
1866
                                   for t in [base, this, other]]
1919
1867
 
1920
1868
        base.tt.new_file('g', base_a, [b'g'], b'g')
1946
1894
        os.mkdir('a')
1947
1895
        a = ControlDir.create_standalone_workingtree('a')
1948
1896
        os.mkdir('a/foo')
1949
 
        with open('a/foo/bar', 'wb') as f:
1950
 
            f.write(b'contents')
 
1897
        with open('a/foo/bar', 'wb') as f: f.write(b'contents')
1951
1898
        os.symlink('a/foo/bar', 'a/foo/baz')
1952
1899
        a.add(['foo', 'foo/bar', 'foo/baz'])
1953
1900
        a.commit('initial commit')
1958
1905
        build_tree(basis, b)
1959
1906
        self.assertIs(os.path.isdir('b/foo'), True)
1960
1907
        with open('b/foo/bar', 'rb') as f:
1961
 
            self.assertEqual(f.read(), b"contents")
 
1908
            self.assertEqual(f.read(), "contents")
1962
1909
        self.assertEqual(os.readlink('b/foo/baz'), 'a/foo/bar')
1963
1910
 
1964
1911
    def test_build_with_references(self):
1965
1912
        tree = self.make_branch_and_tree('source',
1966
 
                                         format='development-subtree')
 
1913
            format='development-subtree')
1967
1914
        subtree = self.make_branch_and_tree('source/subtree',
1968
 
                                            format='development-subtree')
 
1915
            format='development-subtree')
1969
1916
        tree.add_reference(subtree)
1970
1917
        tree.commit('a revision')
1971
1918
        tree.branch.create_checkout('target')
1980
1927
        source.add('file', b'new-file')
1981
1928
        source.commit('added file')
1982
1929
        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())
 
1930
        self.assertEqual([DuplicateEntry('Moved existing file to',
 
1931
                          'file.moved', 'file', None, 'new-file')],
 
1932
                         target.conflicts())
1987
1933
        target2 = self.make_branch_and_tree('target2')
1988
1934
        with open('target2/file', 'wb') as target_file, \
1989
1935
                open('source/file', 'rb') as source_file:
2001
1947
        target = self.make_branch_and_tree('target')
2002
1948
        os.symlink('bar', 'target/symlink')
2003
1949
        build_tree(source.basis_tree(), target)
2004
 
        self.assertEqual(
2005
 
            [DuplicateEntry('Moved existing file to', 'symlink.moved',
2006
 
                            'symlink', None, 'new-symlink')],
 
1950
        self.assertEqual([DuplicateEntry('Moved existing file to',
 
1951
            'symlink.moved', 'symlink', None, 'new-symlink')],
2007
1952
            target.conflicts())
2008
1953
        target = self.make_branch_and_tree('target2')
2009
1954
        os.symlink('foo', 'target2/symlink')
2037
1982
        self.assertPathDoesNotExist('target3/dir1/file')
2038
1983
        self.assertPathExists('target3/dir1/file2')
2039
1984
        self.assertPathExists('target3/dir1.diverted/file')
2040
 
        self.assertEqual(
2041
 
            [DuplicateEntry('Diverted to', 'dir1.diverted',
2042
 
                            'dir1', 'new-dir1', None)],
 
1985
        self.assertEqual([DuplicateEntry('Diverted to',
 
1986
            'dir1.diverted', 'dir1', 'new-dir1', None)],
2043
1987
            target.conflicts())
2044
1988
 
2045
1989
        target = self.make_branch_and_tree('target4')
2049
1993
        self.assertPathExists('target4/dir1/file')
2050
1994
        self.assertEqual('directory', file_kind('target4/dir1/file'))
2051
1995
        self.assertPathExists('target4/dir1/file.diverted')
2052
 
        self.assertEqual(
2053
 
            [DuplicateEntry('Diverted to', 'dir1/file.diverted',
2054
 
                            'dir1/file', 'new-file', None)],
 
1996
        self.assertEqual([DuplicateEntry('Diverted to',
 
1997
            'dir1/file.diverted', 'dir1/file', 'new-file', None)],
2055
1998
            target.conflicts())
2056
1999
 
2057
2000
    def test_mixed_conflict_handling(self):
2062
2005
        source.add('name', b'new-name')
2063
2006
        source.commit('added file')
2064
2007
        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())
 
2008
        self.assertEqual([DuplicateEntry('Moved existing file to',
 
2009
            'name.moved', 'name', None, 'new-name')], target.conflicts())
2069
2010
 
2070
2011
    def test_raises_in_populated(self):
2071
2012
        source = self.make_branch_and_tree('source')
2076
2017
        self.build_tree(['target/name'])
2077
2018
        target.add('name')
2078
2019
        self.assertRaises(errors.WorkingTreeAlreadyPopulated,
2079
 
                          build_tree, source.basis_tree(), target)
 
2020
            build_tree, source.basis_tree(), target)
2080
2021
 
2081
2022
    def test_build_tree_rename_count(self):
2082
2023
        source = self.make_branch_and_tree('source')
2111
2052
        self.build_tree_contents([('source/file2', b'C')])
2112
2053
        calls = []
2113
2054
        real_source_get_file = source.get_file
2114
 
 
2115
 
        def get_file(path):
2116
 
            calls.append(path)
2117
 
            return real_source_get_file(path)
 
2055
        def get_file(path, file_id=None):
 
2056
            calls.append(file_id)
 
2057
            return real_source_get_file(path, file_id)
2118
2058
        source.get_file = get_file
2119
2059
        target = self.make_branch_and_tree('target')
2120
2060
        revision_tree = source.basis_tree()
2121
2061
        revision_tree.lock_read()
2122
2062
        self.addCleanup(revision_tree.unlock)
2123
2063
        build_tree(revision_tree, target, source)
2124
 
        self.assertEqual(['file1'], calls)
 
2064
        self.assertEqual([b'file1-id'], calls)
2125
2065
        target.lock_read()
2126
2066
        self.addCleanup(target.unlock)
2127
2067
        self.assertEqual([], list(target.iter_changes(revision_tree)))
2164
2104
        os.symlink('file2', 'source/file1')
2165
2105
        calls = []
2166
2106
        real_source_get_file = source.get_file
2167
 
 
2168
 
        def get_file(path):
2169
 
            calls.append(path)
2170
 
            return real_source_get_file(path)
 
2107
        def get_file(path, file_id=None):
 
2108
            calls.append(file_id)
 
2109
            return real_source_get_file(path, file_id)
2171
2110
        source.get_file = get_file
2172
2111
        target = self.make_branch_and_tree('target')
2173
2112
        revision_tree = source.basis_tree()
2245
2184
        # below, but that looks a bit... hard to read even if it's exactly
2246
2185
        # the same thing.
2247
2186
        original_registry = filters._reset_registry()
2248
 
 
2249
2187
        def restore_registry():
2250
2188
            filters._reset_registry(original_registry)
2251
2189
        self.addCleanup(restore_registry)
2252
 
 
2253
2190
        def rot13(chunks, context=None):
2254
 
            return [
2255
 
                codecs.encode(chunk.decode('ascii'), 'rot13').encode('ascii')
2256
 
                for chunk in chunks]
 
2191
            return [b''.join(chunks).encode('rot13')]
2257
2192
        rot13filter = filters.ContentFilter(rot13, rot13)
2258
2193
        filters.filter_stacks_registry.register(
2259
2194
            'rot13', {'yes': [rot13filter]}.get)
2261
2196
        rules_filename = self.test_home_dir + '/.bazaar/rules'
2262
2197
        with open(rules_filename, 'wb') as f:
2263
2198
            f.write(b'[name %s]\nrot13=yes\n' % (pattern,))
2264
 
 
2265
2199
        def uninstall_rules():
2266
2200
            os.remove(rules_filename)
2267
2201
            rules.reset_rules()
2293
2227
 
2294
2228
    def test_case_insensitive_build_tree_inventory(self):
2295
2229
        if (features.CaseInsensitiveFilesystemFeature.available()
2296
 
                or features.CaseInsCasePresFilenameFeature.available()):
 
2230
            or features.CaseInsCasePresFilenameFeature.available()):
2297
2231
            raise tests.UnavailableFeature('Fully case sensitive filesystem')
2298
2232
        source = self.make_branch_and_tree('source')
2299
2233
        self.build_tree(['source/file', 'source/FILE'])
2326
2260
        # entry[1] is the state information, entry[1][0] is the state of the
2327
2261
        # working tree, entry[1][0][1] is the sha value for the current working
2328
2262
        # tree
2329
 
        entry1 = state._get_entry(0, path_utf8=b'file1')
 
2263
        entry1 = state._get_entry(0, path_utf8='file1')
2330
2264
        self.assertEqual(entry1_sha, entry1[1][0][1])
2331
2265
        # The 'size' field must also be set.
2332
2266
        self.assertEqual(25, entry1[1][0][2])
2333
2267
        entry1_state = entry1[1][0]
2334
 
        entry2 = state._get_entry(0, path_utf8=b'dir/file2')
 
2268
        entry2 = state._get_entry(0, path_utf8='dir/file2')
2335
2269
        self.assertEqual(entry2_sha, entry2[1][0][1])
2336
2270
        self.assertEqual(29, entry2[1][0][2])
2337
2271
        entry2_state = entry2[1][0]
2338
2272
        # Now, make sure that we don't have to re-read the content. The
2339
2273
        # 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'))
 
2274
        self.assertEqual(entry1_sha, target.get_file_sha1('file1', b'file1-id'))
 
2275
        self.assertEqual(entry2_sha,
 
2276
                         target.get_file_sha1('dir/file2', b'file2-id'))
2342
2277
        self.assertEqual(entry1_state, entry1[1][0])
2343
2278
        self.assertEqual(entry2_state, entry2[1][0])
2344
2279
 
2377
2312
 
2378
2313
    def test_merge_parents(self):
2379
2314
        branch, tt = self.get_branch_and_transform()
2380
 
        tt.commit(branch, 'my message', [b'rev1b', b'rev1c'])
2381
 
        self.assertEqual([b'rev1b', b'rev1c'],
 
2315
        rev = tt.commit(branch, 'my message', ['rev1b', 'rev1c'])
 
2316
        self.assertEqual(['rev1b', 'rev1c'],
2382
2317
                         branch.basis_tree().get_parent_ids()[1:])
2383
2318
 
2384
2319
    def test_first_commit(self):
2387
2322
        self.addCleanup(branch.unlock)
2388
2323
        tt = TransformPreview(branch.basis_tree())
2389
2324
        self.addCleanup(tt.finalize)
2390
 
        tt.new_directory('', ROOT_PARENT, b'TREE_ROOT')
2391
 
        tt.commit(branch, 'my message')
 
2325
        tt.new_directory('', ROOT_PARENT, 'TREE_ROOT')
 
2326
        rev = tt.commit(branch, 'my message')
2392
2327
        self.assertEqual([], branch.basis_tree().get_parent_ids())
2393
2328
        self.assertNotEqual(_mod_revision.NULL_REVISION,
2394
2329
                            branch.last_revision())
2400
2335
        tt = TransformPreview(branch.basis_tree())
2401
2336
        self.addCleanup(tt.finalize)
2402
2337
        e = self.assertRaises(ValueError, tt.commit, branch,
2403
 
                              'my message', [b'rev1b-id'])
 
2338
                          'my message', ['rev1b-id'])
2404
2339
        self.assertEqual('Cannot supply merge parents for first commit.',
2405
2340
                         str(e))
2406
2341
        self.assertEqual(_mod_revision.NULL_REVISION, branch.last_revision())
2411
2346
        trans_id = tt.new_directory('dir', tt.root, b'dir-id')
2412
2347
        if SymlinkFeature.available():
2413
2348
            tt.new_symlink('symlink', trans_id, 'target', b'symlink-id')
2414
 
        tt.commit(branch, 'message')
 
2349
        rev = tt.commit(branch, 'message')
2415
2350
        tree = branch.basis_tree()
2416
2351
        self.assertEqual('file', tree.id2path(b'file-id'))
2417
 
        self.assertEqual(b'contents', tree.get_file_text('file'))
 
2352
        self.assertEqual(b'contents', tree.get_file_text('file', b'file-id'))
2418
2353
        self.assertEqual('dir', tree.id2path(b'dir-id'))
2419
2354
        if SymlinkFeature.available():
2420
2355
            self.assertEqual('dir/symlink', tree.id2path(b'symlink-id'))
2454
2389
                           committer='me <me@example.com>',
2455
2390
                           revprops={u'foo': 'bar'}, revision_id=b'revid-1',
2456
2391
                           authors=['Author1 <author1@example.com>',
2457
 
                                    'Author2 <author2@example.com>',
2458
 
                                    ])
 
2392
                              'Author2 <author2@example.com>',
 
2393
                               ])
2459
2394
        self.assertEqual(b'revid-1', rev_id)
2460
2395
        revision = branch.repository.get_revision(rev_id)
2461
2396
        self.assertEqual(1, revision.timestamp)
2525
2460
        mover.rename('c/e', 'c/d')
2526
2461
        try:
2527
2462
            mover.rename('a', 'c')
2528
 
        except errors.FileExists:
 
2463
        except errors.FileExists as e:
2529
2464
            mover.rollback()
2530
2465
        self.assertPathExists('a')
2531
2466
        self.assertPathExists('c/d')
2546
2481
 
2547
2482
        def rename(self, source, target):
2548
2483
            if (self.bad_source is not None and
2549
 
                    source.endswith(self.bad_source)):
 
2484
                source.endswith(self.bad_source)):
2550
2485
                raise Bogus
2551
2486
            elif (self.bad_target is not None and
2552
 
                  target.endswith(self.bad_target)):
 
2487
                target.endswith(self.bad_target)):
2553
2488
                raise Bogus
2554
2489
            else:
2555
2490
                _FileMover.rename(self, source, target)
2610
2545
        new_globals = dict(func.__globals__)
2611
2546
        new_globals.update(globals)
2612
2547
        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__))
 
2548
            func.__name__, func.__defaults__)
 
2549
        setattr(instance, method_name,
 
2550
            types.MethodType(new_func, instance, instance.__class__))
2620
2551
        self.addCleanup(delattr, instance, method_name)
2621
2552
 
2622
2553
    @staticmethod
2648
2579
 
2649
2580
    def test_root_create_file_open_raises_before_creation(self):
2650
2581
        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)
 
2582
        self._override_globals_in_method(tt, "create_file",
 
2583
            {"open": self._fake_open_raises_before})
 
2584
        self.assertRaises(RuntimeError, tt.create_file, [b"contents"], trans_id)
2655
2585
        path = tt._limbo_name(trans_id)
2656
2586
        self.assertPathDoesNotExist(path)
2657
2587
        tt.finalize()
2659
2589
 
2660
2590
    def test_root_create_file_open_raises_after_creation(self):
2661
2591
        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)
 
2592
        self._override_globals_in_method(tt, "create_file",
 
2593
            {"open": self._fake_open_raises_after})
 
2594
        self.assertRaises(RuntimeError, tt.create_file, [b"contents"], trans_id)
2666
2595
        path = tt._limbo_name(trans_id)
2667
2596
        self.assertPathExists(path)
2668
2597
        tt.finalize()
2671
2600
 
2672
2601
    def test_subdir_create_file_open_raises_before_creation(self):
2673
2602
        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)
 
2603
        self._override_globals_in_method(tt, "create_file",
 
2604
            {"open": self._fake_open_raises_before})
 
2605
        self.assertRaises(RuntimeError, tt.create_file, [b"contents"], trans_id)
2678
2606
        path = tt._limbo_name(trans_id)
2679
2607
        self.assertPathDoesNotExist(path)
2680
2608
        tt.finalize()
2682
2610
 
2683
2611
    def test_subdir_create_file_open_raises_after_creation(self):
2684
2612
        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)
 
2613
        self._override_globals_in_method(tt, "create_file",
 
2614
            {"open": self._fake_open_raises_after})
 
2615
        self.assertRaises(RuntimeError, tt.create_file, [b"contents"], trans_id)
2689
2616
        path = tt._limbo_name(trans_id)
2690
2617
        self.assertPathExists(path)
2691
2618
        tt.finalize()
2703
2630
                os.rename(old, new)
2704
2631
                raise RuntimeError
2705
2632
        self._override_globals_in_method(tt, "_rename_in_limbo",
2706
 
                                         {"os": FakeOSModule()})
 
2633
            {"os": FakeOSModule()})
2707
2634
        self.assertRaises(
2708
2635
            RuntimeError, tt.adjust_path, "child1", parent2, child1)
2709
2636
        path = osutils.pathjoin(tt._limbo_name(parent2), "child1")
2722
2649
            def rename(self, old, new):
2723
2650
                raise RuntimeError
2724
2651
        self._override_globals_in_method(tt, "_rename_in_limbo",
2725
 
                                         {"os": FakeOSModule()})
 
2652
            {"os": FakeOSModule()})
2726
2653
        self.assertRaises(
2727
2654
            RuntimeError, tt.adjust_path, "child1", parent2, child1)
2728
2655
        path = osutils.pathjoin(tt._limbo_name(parent1), "child1")
2736
2663
 
2737
2664
    def make_tt_with_versioned_dir(self):
2738
2665
        wt = self.make_branch_and_tree('.')
2739
 
        self.build_tree(['dir/', ])
 
2666
        self.build_tree(['dir/',])
2740
2667
        wt.add(['dir'], [b'dir-id'])
2741
2668
        wt.commit('Create dir')
2742
2669
        tt = TreeTransform(wt)
2746
2673
    def test_resolve_create_parent_for_versioned_file(self):
2747
2674
        wt, tt = self.make_tt_with_versioned_dir()
2748
2675
        dir_tid = tt.trans_id_tree_path('dir')
2749
 
        tt.new_file('file', dir_tid, [b'Contents'], file_id=b'file-id')
 
2676
        file_tid = tt.new_file('file', dir_tid, [b'Contents'], file_id=b'file-id')
2750
2677
        tt.delete_contents(dir_tid)
2751
2678
        tt.unversion_file(dir_tid)
2752
2679
        conflicts = resolve_conflicts(tt)
2768
2695
 
2769
2696
 
2770
2697
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)
 
2698
                  (b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
 
2699
                  (False, False))
2773
2700
ROOT_ENTRY = (b'TREE_ROOT', ('', ''), False, (True, True), (None, None),
2774
 
              ('', ''), ('directory', 'directory'), (False, False), False)
 
2701
              ('', ''), ('directory', 'directory'), (False, False))
2775
2702
 
2776
2703
 
2777
2704
class TestTransformPreview(tests.TestCaseWithTransport):
2809
2736
        preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
2810
2737
        preview_tree = preview.get_preview_tree()
2811
2738
        self.assertEqual(preview_tree.kind('file2'), 'file')
2812
 
        with preview_tree.get_file('file2') as f:
 
2739
        with preview_tree.get_file('file2', b'file2-id') as f:
2813
2740
            self.assertEqual(f.read(), b'content B\n')
2814
2741
 
2815
2742
    def test_diff_preview_tree(self):
2821
2748
        out = BytesIO()
2822
2749
        show_diff_trees(revision_tree, preview_tree, out)
2823
2750
        lines = out.getvalue().splitlines()
2824
 
        self.assertEqual(lines[0], b"=== added file 'file2'")
 
2751
        self.assertEqual(lines[0], "=== added file 'file2'")
2825
2752
        # 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')
 
2753
        self.assertEqual(lines[4], "+content B")
2855
2754
 
2856
2755
    def test_transform_conflicts(self):
2857
2756
        revision_tree = self.create_tree()
2874
2773
 
2875
2774
    def test_iter_changes(self):
2876
2775
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2877
 
        root = revision_tree.path2id('')
 
2776
        root = revision_tree.get_root_id()
2878
2777
        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)))
 
2778
                          (root, root), ('a', 'a'), ('file', 'file'),
 
2779
                          (False, False))],
 
2780
                          list(preview_tree.iter_changes(revision_tree)))
2882
2781
 
2883
2782
    def test_include_unchanged_succeeds(self):
2884
2783
        revision_tree, preview_tree = self.get_tree_and_preview_tree()
2885
2784
        changes = preview_tree.iter_changes(revision_tree,
2886
2785
                                            include_unchanged=True)
 
2786
        root = revision_tree.get_root_id()
 
2787
 
2887
2788
        self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
2888
2789
 
2889
2790
    def test_specific_files(self):
2919
2820
        preview = TransformPreview(revision_tree)
2920
2821
        self.addCleanup(preview.finalize)
2921
2822
        preview.new_file('file', preview.root, [b'contents'], b'file-id')
2922
 
        preview.new_directory('directory', preview.root, b'dir-id')
 
2823
        preview.new_directory('directory', preview.root, 'dir-id')
2923
2824
        preview_tree = preview.get_preview_tree()
2924
2825
        self.assertEqual('file', preview_tree.kind('file'))
2925
2826
        self.assertEqual('directory', preview_tree.kind('directory'))
2931
2832
        limbo_path = preview._limbo_name(file_trans_id)
2932
2833
        preview_tree = preview.get_preview_tree()
2933
2834
        self.assertEqual(os.stat(limbo_path).st_mtime,
2934
 
                         preview_tree.get_file_mtime('file'))
 
2835
                         preview_tree.get_file_mtime('file', b'file-id'))
2935
2836
 
2936
2837
    def test_get_file_mtime_renamed(self):
2937
2838
        work_tree = self.make_branch_and_tree('tree')
2942
2843
        file_trans_id = preview.trans_id_tree_path('file')
2943
2844
        preview.adjust_path('renamed', preview.root, file_trans_id)
2944
2845
        preview_tree = preview.get_preview_tree()
2945
 
        preview_mtime = preview_tree.get_file_mtime('renamed')
2946
 
        work_mtime = work_tree.get_file_mtime('file')
 
2846
        preview_mtime = preview_tree.get_file_mtime('renamed', b'file-id')
 
2847
        work_mtime = work_tree.get_file_mtime('file', b'file-id')
2947
2848
 
2948
2849
    def test_get_file_size(self):
2949
2850
        work_tree = self.make_branch_and_tree('tree')
2951
2852
        work_tree.add('old', b'old-id')
2952
2853
        preview = TransformPreview(work_tree)
2953
2854
        self.addCleanup(preview.finalize)
2954
 
        preview.new_file('name', preview.root, [b'contents'], b'new-id',
2955
 
                         'executable')
 
2855
        new_id = preview.new_file('name', preview.root, [b'contents'], b'new-id',
 
2856
                                  'executable')
2956
2857
        tree = preview.get_preview_tree()
2957
2858
        self.assertEqual(len('old'), tree.get_file_size('old'))
2958
2859
        self.assertEqual(len('contents'), tree.get_file_size('name'))
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
            [b'contents'], b'new-id')
3008
2909
        preview_tree = preview.get_preview_tree()
3009
2910
        self.assertEqual(b'new-id', preview_tree.path2id('unchanged/new'))
3010
2911
 
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, [b'contents'], b'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))
3155
3055
    def test_tree_content_summary(self):
3156
3056
        preview = self.get_empty_preview()
3157
3057
        path = preview.new_directory('path', preview.root, b'path-id')
3158
 
        preview.set_tree_reference(b'rev-1', path)
 
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])
3177
3077
            (b'me:', b'b\n'),
3178
3078
            (b'me:', b'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):
3189
3088
            (b'me:', b'a\n'),
3190
3089
            (b'me:', b'b\n'),
3191
3090
            (b'me:', b'c\n'),
3192
 
            ]
3193
 
        annotation = preview_tree.annotate_iter(
3194
 
            'file', default_revision=b'me:')
 
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):
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')
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, b'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, [b'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):
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
                b'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')
3401
3298
        self.addCleanup(preview.finalize)
3402
3299
        preview.new_file('foo', preview.root, [b'bar'], b'baz-id')
3403
3300
        preview_tree = preview.get_preview_tree()
 
3301
        self.assertEqual(False, preview_tree.is_executable('tree/foo', b'baz-id'))
3404
3302
        self.assertEqual(False, preview_tree.is_executable('tree/foo'))
3405
3303
 
3406
3304
    def test_commit_preview_tree(self):
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
 
3486
3384
        attribs[b'_new_parent'] = {b'new-1': b'new-0', b'new-2': b'new-0'}
3487
3385
        attribs[b'_new_executability'] = {b'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', b'i 1\nbar\n'),
 
3388
            ('new-2', 'directory', b''),
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
3394
        tt.new_file(u'foo\u1234', tt.root, [b'bar'], b'baz', True)
3497
 
        tt.new_directory('qux', tt.root, b'quxx')
 
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
 
3580
3478
        attribs = self.default_attribs()
3581
3479
        attribs[b'_id_number'] = 2
3582
3480
        attribs[b'_non_present_ids'] = {
3583
 
            b'boo': b'new-1', }
 
3481
            b'boo': b'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(b'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({b'boo': b'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):
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
3526
        LINES = b'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
3534
        attribs[b'_id_number'] = 2
3637
3535
        attribs[b'_tree_path_ids'] = {
3638
3536
            b'foo': b'new-1',
3639
 
            b'': b'new-0', }
 
3537
            b'': b'new-0',}
3640
3538
        attribs[b'_removed_contents'] = [b'new-1']
3641
 
        contents = [(b'new-1', b'file',
 
3539
        contents = [('new-1', 'file',
3642
3540
                     b'i 4\na\nb\nc\nd\n\n')]
3643
3541
        return self.make_records(attribs, contents)
3644
3542
 
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
3556
        LINES = b'a\nb\nc\nd\n'
3667
3565
        attribs[b'_id_number'] = 2
3668
3566
        attribs[b'_tree_path_ids'] = {
3669
3567
            b'foo': b'new-1',
3670
 
            b'': b'new-0', }
3671
 
        contents = [(b'new-1', b'file',
 
3568
            b'': b'new-0',}
 
3569
        contents = [('new-1', 'file',
3672
3570
                     b'i 4\na\nb\nc\nd\n\n')]
3673
3571
        return self.make_records(attribs, contents)
3674
3572
 
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
3592
        self.assertEqual(([b'aa\n', b'bb\n', b'cc\n', b'dd\n'],),
3694
 
                         tt._get_parents_lines(trans_id))
 
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