509
556
wt = transform._tree
510
557
transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
512
sac = transform.new_file('set_after_creation', root, 'Set after creation', 'sac')
559
sac = transform.new_file('set_after_creation', root,
560
'Set after creation', 'sac')
513
561
transform.set_executability(True, sac)
514
uws = transform.new_file('unset_without_set', root, 'Unset badly', 'uws')
562
uws = transform.new_file('unset_without_set', root, 'Unset badly',
515
564
self.assertRaises(KeyError, transform.set_executability, None, uws)
516
565
transform.apply()
517
566
self.assertTrue(wt.is_executable('soc'))
518
567
self.assertTrue(wt.is_executable('sac'))
569
def test_preserve_mode(self):
570
"""File mode is preserved when replacing content"""
571
if sys.platform == 'win32':
572
raise TestSkipped('chmod has no effect on win32')
573
transform, root = self.get_transform()
574
transform.new_file('file1', root, 'contents', 'file1-id', True)
576
self.assertTrue(self.wt.is_executable('file1-id'))
577
transform, root = self.get_transform()
578
file1_id = transform.trans_id_tree_file_id('file1-id')
579
transform.delete_contents(file1_id)
580
transform.create_file('contents2', file1_id)
582
self.assertTrue(self.wt.is_executable('file1-id'))
584
def test__set_mode_stats_correctly(self):
585
"""_set_mode stats to determine file mode."""
586
if sys.platform == 'win32':
587
raise TestSkipped('chmod has no effect on win32')
591
def instrumented_stat(path):
592
stat_paths.append(path)
593
return real_stat(path)
595
transform, root = self.get_transform()
597
bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
598
file_id='bar-id-1', executable=False)
601
transform, root = self.get_transform()
602
bar1_id = transform.trans_id_tree_path('bar')
603
bar2_id = transform.trans_id_tree_path('bar2')
605
os.stat = instrumented_stat
606
transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
611
bar1_abspath = self.wt.abspath('bar')
612
self.assertEqual([bar1_abspath], stat_paths)
614
def test_iter_changes(self):
615
self.wt.set_root_id('eert_toor')
616
transform, root = self.get_transform()
617
transform.new_file('old', root, 'blah', 'id-1', True)
619
transform, root = self.get_transform()
621
self.assertEqual([], list(transform._iter_changes()))
622
old = transform.trans_id_tree_file_id('id-1')
623
transform.unversion_file(old)
624
self.assertEqual([('id-1', ('old', None), False, (True, False),
625
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
626
(True, True))], list(transform._iter_changes()))
627
transform.new_directory('new', root, 'id-1')
628
self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
629
('eert_toor', 'eert_toor'), ('old', 'new'),
630
('file', 'directory'),
631
(True, False))], list(transform._iter_changes()))
635
def test_iter_changes_new(self):
636
self.wt.set_root_id('eert_toor')
637
transform, root = self.get_transform()
638
transform.new_file('old', root, 'blah')
640
transform, root = self.get_transform()
642
old = transform.trans_id_tree_path('old')
643
transform.version_file('id-1', old)
644
self.assertEqual([('id-1', (None, 'old'), False, (False, True),
645
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
646
(False, False))], list(transform._iter_changes()))
650
def test_iter_changes_modifications(self):
651
self.wt.set_root_id('eert_toor')
652
transform, root = self.get_transform()
653
transform.new_file('old', root, 'blah', 'id-1')
654
transform.new_file('new', root, 'blah')
655
transform.new_directory('subdir', root, 'subdir-id')
657
transform, root = self.get_transform()
659
old = transform.trans_id_tree_path('old')
660
subdir = transform.trans_id_tree_file_id('subdir-id')
661
new = transform.trans_id_tree_path('new')
662
self.assertEqual([], list(transform._iter_changes()))
665
transform.delete_contents(old)
666
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
667
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
668
(False, False))], list(transform._iter_changes()))
671
transform.create_file('blah', old)
672
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
673
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
674
(False, False))], list(transform._iter_changes()))
675
transform.cancel_deletion(old)
676
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
677
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
678
(False, False))], list(transform._iter_changes()))
679
transform.cancel_creation(old)
681
# move file_id to a different file
682
self.assertEqual([], list(transform._iter_changes()))
683
transform.unversion_file(old)
684
transform.version_file('id-1', new)
685
transform.adjust_path('old', root, new)
686
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
687
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
688
(False, False))], list(transform._iter_changes()))
689
transform.cancel_versioning(new)
690
transform._removed_id = set()
693
self.assertEqual([], list(transform._iter_changes()))
694
transform.set_executability(True, old)
695
self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
696
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
697
(False, True))], list(transform._iter_changes()))
698
transform.set_executability(None, old)
701
self.assertEqual([], list(transform._iter_changes()))
702
transform.adjust_path('new', root, old)
703
transform._new_parent = {}
704
self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
705
('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
706
(False, False))], list(transform._iter_changes()))
707
transform._new_name = {}
710
self.assertEqual([], list(transform._iter_changes()))
711
transform.adjust_path('new', subdir, old)
712
transform._new_name = {}
713
self.assertEqual([('id-1', ('old', 'subdir/old'), False,
714
(True, True), ('eert_toor', 'subdir-id'), ('old', 'old'),
715
('file', 'file'), (False, False))],
716
list(transform._iter_changes()))
717
transform._new_path = {}
722
def test_iter_changes_modified_bleed(self):
723
self.wt.set_root_id('eert_toor')
724
"""Modified flag should not bleed from one change to another"""
725
# unfortunately, we have no guarantee that file1 (which is modified)
726
# will be applied before file2. And if it's applied after file2, it
727
# obviously can't bleed into file2's change output. But for now, it
729
transform, root = self.get_transform()
730
transform.new_file('file1', root, 'blah', 'id-1')
731
transform.new_file('file2', root, 'blah', 'id-2')
733
transform, root = self.get_transform()
735
transform.delete_contents(transform.trans_id_file_id('id-1'))
736
transform.set_executability(True,
737
transform.trans_id_file_id('id-2'))
738
self.assertEqual([('id-1', (u'file1', u'file1'), True, (True, True),
739
('eert_toor', 'eert_toor'), ('file1', u'file1'),
740
('file', None), (False, False)),
741
('id-2', (u'file2', u'file2'), False, (True, True),
742
('eert_toor', 'eert_toor'), ('file2', u'file2'),
743
('file', 'file'), (False, True))],
744
list(transform._iter_changes()))
748
def test_iter_changes_move_missing(self):
749
"""Test moving ids with no files around"""
750
self.wt.set_root_id('toor_eert')
751
# Need two steps because versioning a non-existant file is a conflict.
752
transform, root = self.get_transform()
753
transform.new_directory('floater', root, 'floater-id')
755
transform, root = self.get_transform()
756
transform.delete_contents(transform.trans_id_tree_path('floater'))
758
transform, root = self.get_transform()
759
floater = transform.trans_id_tree_path('floater')
761
transform.adjust_path('flitter', root, floater)
762
self.assertEqual([('floater-id', ('floater', 'flitter'), False,
763
(True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
764
(None, None), (False, False))], list(transform._iter_changes()))
768
def test_iter_changes_pointless(self):
769
"""Ensure that no-ops are not treated as modifications"""
770
self.wt.set_root_id('eert_toor')
771
transform, root = self.get_transform()
772
transform.new_file('old', root, 'blah', 'id-1')
773
transform.new_directory('subdir', root, 'subdir-id')
775
transform, root = self.get_transform()
777
old = transform.trans_id_tree_path('old')
778
subdir = transform.trans_id_tree_file_id('subdir-id')
779
self.assertEqual([], list(transform._iter_changes()))
780
transform.delete_contents(subdir)
781
transform.create_directory(subdir)
782
transform.set_executability(False, old)
783
transform.unversion_file(old)
784
transform.version_file('id-1', old)
785
transform.adjust_path('old', root, old)
786
self.assertEqual([], list(transform._iter_changes()))
790
def test_rename_count(self):
791
transform, root = self.get_transform()
792
transform.new_file('name1', root, 'contents')
793
self.assertEqual(transform.rename_count, 0)
795
self.assertEqual(transform.rename_count, 1)
796
transform2, root = self.get_transform()
797
transform2.adjust_path('name2', root,
798
transform2.trans_id_tree_path('name1'))
799
self.assertEqual(transform2.rename_count, 0)
801
self.assertEqual(transform2.rename_count, 2)
803
def test_change_parent(self):
804
"""Ensure that after we change a parent, the results are still right.
806
Renames and parent changes on pending transforms can happen as part
807
of conflict resolution, and are explicitly permitted by the
810
This test ensures they work correctly with the rename-avoidance
813
transform, root = self.get_transform()
814
parent1 = transform.new_directory('parent1', root)
815
child1 = transform.new_file('child1', parent1, 'contents')
816
parent2 = transform.new_directory('parent2', root)
817
transform.adjust_path('child1', parent2, child1)
819
self.failIfExists(self.wt.abspath('parent1/child1'))
820
self.failUnlessExists(self.wt.abspath('parent2/child1'))
821
# rename limbo/new-1 => parent1, rename limbo/new-3 => parent2
822
# no rename for child1 (counting only renames during apply)
823
self.failUnlessEqual(2, transform.rename_count)
825
def test_cancel_parent(self):
826
"""Cancelling a parent doesn't cause deletion of a non-empty directory
828
This is like the test_change_parent, except that we cancel the parent
829
before adjusting the path. The transform must detect that the
830
directory is non-empty, and move children to safe locations.
832
transform, root = self.get_transform()
833
parent1 = transform.new_directory('parent1', root)
834
child1 = transform.new_file('child1', parent1, 'contents')
835
child2 = transform.new_file('child2', parent1, 'contents')
837
transform.cancel_creation(parent1)
839
self.fail('Failed to move child1 before deleting parent1')
840
transform.cancel_creation(child2)
841
transform.create_directory(parent1)
843
transform.cancel_creation(parent1)
844
# If the transform incorrectly believes that child2 is still in
845
# parent1's limbo directory, it will try to rename it and fail
846
# because was already moved by the first cancel_creation.
848
self.fail('Transform still thinks child2 is a child of parent1')
849
parent2 = transform.new_directory('parent2', root)
850
transform.adjust_path('child1', parent2, child1)
852
self.failIfExists(self.wt.abspath('parent1'))
853
self.failUnlessExists(self.wt.abspath('parent2/child1'))
854
# rename limbo/new-3 => parent2, rename limbo/new-2 => child1
855
self.failUnlessEqual(2, transform.rename_count)
857
def test_adjust_and_cancel(self):
858
"""Make sure adjust_path keeps track of limbo children properly"""
859
transform, root = self.get_transform()
860
parent1 = transform.new_directory('parent1', root)
861
child1 = transform.new_file('child1', parent1, 'contents')
862
parent2 = transform.new_directory('parent2', root)
863
transform.adjust_path('child1', parent2, child1)
864
transform.cancel_creation(child1)
866
transform.cancel_creation(parent1)
867
# if the transform thinks child1 is still in parent1's limbo
868
# directory, it will attempt to move it and fail.
870
self.fail('Transform still thinks child1 is a child of parent1')
873
def test_noname_contents(self):
874
"""TreeTransform should permit deferring naming files."""
875
transform, root = self.get_transform()
876
parent = transform.trans_id_file_id('parent-id')
878
transform.create_directory(parent)
880
self.fail("Can't handle contents with no name")
883
def test_noname_contents_nested(self):
884
"""TreeTransform should permit deferring naming files."""
885
transform, root = self.get_transform()
886
parent = transform.trans_id_file_id('parent-id')
888
transform.create_directory(parent)
890
self.fail("Can't handle contents with no name")
891
child = transform.new_directory('child', parent)
892
transform.adjust_path('parent', root, parent)
894
self.failUnlessExists(self.wt.abspath('parent/child'))
895
self.assertEqual(1, transform.rename_count)
897
def test_reuse_name(self):
898
"""Avoid reusing the same limbo name for different files"""
899
transform, root = self.get_transform()
900
parent = transform.new_directory('parent', root)
901
child1 = transform.new_directory('child', parent)
903
child2 = transform.new_directory('child', parent)
905
self.fail('Tranform tried to use the same limbo name twice')
906
transform.adjust_path('child2', parent, child2)
908
# limbo/new-1 => parent, limbo/new-3 => parent/child2
909
# child2 is put into top-level limbo because child1 has already
910
# claimed the direct limbo path when child2 is created. There is no
911
# advantage in renaming files once they're in top-level limbo, except
913
self.assertEqual(2, transform.rename_count)
915
def test_reuse_when_first_moved(self):
916
"""Don't avoid direct paths when it is safe to use them"""
917
transform, root = self.get_transform()
918
parent = transform.new_directory('parent', root)
919
child1 = transform.new_directory('child', parent)
920
transform.adjust_path('child1', parent, child1)
921
child2 = transform.new_directory('child', parent)
923
# limbo/new-1 => parent
924
self.assertEqual(1, transform.rename_count)
926
def test_reuse_after_cancel(self):
927
"""Don't avoid direct paths when it is safe to use them"""
928
transform, root = self.get_transform()
929
parent2 = transform.new_directory('parent2', root)
930
child1 = transform.new_directory('child1', parent2)
931
transform.cancel_creation(parent2)
932
transform.create_directory(parent2)
933
child2 = transform.new_directory('child1', parent2)
934
transform.adjust_path('child2', parent2, child1)
936
# limbo/new-1 => parent2, limbo/new-2 => parent2/child1
937
self.assertEqual(2, transform.rename_count)
939
def test_finalize_order(self):
940
"""Finalize must be done in child-to-parent order"""
941
transform, root = self.get_transform()
942
parent = transform.new_directory('parent', root)
943
child = transform.new_directory('child', parent)
947
self.fail('Tried to remove parent before child1')
949
def test_cancel_with_cancelled_child_should_succeed(self):
950
transform, root = self.get_transform()
951
parent = transform.new_directory('parent', root)
952
child = transform.new_directory('child', parent)
953
transform.cancel_creation(child)
954
transform.cancel_creation(parent)
957
def test_change_entry(self):
958
txt = 'bzrlib.transform.change_entry was deprecated in version 0.90.'
959
self.callDeprecated([txt], change_entry, None, None, None, None, None,
521
963
class TransformGroup(object):
522
def __init__(self, dirname):
964
def __init__(self, dirname, root_id):
523
965
self.name = dirname
524
966
os.mkdir(dirname)
525
967
self.wt = BzrDir.create_standalone_workingtree(dirname)
968
self.wt.set_root_id(root_id)
526
969
self.b = self.wt.branch
527
970
self.tt = TreeTransform(self.wt)
528
971
self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
530
974
def conflict_text(tree, merge):
531
975
template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
532
976
return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
725
1175
a.add(['foo', 'foo/bar', 'foo/baz'])
726
1176
a.commit('initial commit')
727
1177
b = BzrDir.create_standalone_workingtree('b')
728
build_tree(a.basis_tree(), b)
1178
basis = a.basis_tree()
1180
self.addCleanup(basis.unlock)
1181
build_tree(basis, b)
729
1182
self.assertIs(os.path.isdir('b/foo'), True)
730
1183
self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
731
1184
self.assertEqual(os.readlink('b/foo/baz'), 'a/foo/bar')
1186
def test_build_with_references(self):
1187
tree = self.make_branch_and_tree('source',
1188
format='dirstate-with-subtree')
1189
subtree = self.make_branch_and_tree('source/subtree',
1190
format='dirstate-with-subtree')
1191
tree.add_reference(subtree)
1192
tree.commit('a revision')
1193
tree.branch.create_checkout('target')
1194
self.failUnlessExists('target')
1195
self.failUnlessExists('target/subtree')
1197
def test_file_conflict_handling(self):
1198
"""Ensure that when building trees, conflict handling is done"""
1199
source = self.make_branch_and_tree('source')
1200
target = self.make_branch_and_tree('target')
1201
self.build_tree(['source/file', 'target/file'])
1202
source.add('file', 'new-file')
1203
source.commit('added file')
1204
build_tree(source.basis_tree(), target)
1205
self.assertEqual([DuplicateEntry('Moved existing file to',
1206
'file.moved', 'file', None, 'new-file')],
1208
target2 = self.make_branch_and_tree('target2')
1209
target_file = file('target2/file', 'wb')
1211
source_file = file('source/file', 'rb')
1213
target_file.write(source_file.read())
1218
build_tree(source.basis_tree(), target2)
1219
self.assertEqual([], target2.conflicts())
1221
def test_symlink_conflict_handling(self):
1222
"""Ensure that when building trees, conflict handling is done"""
1223
if not has_symlinks():
1224
raise TestSkipped('Test requires symlink support')
1225
source = self.make_branch_and_tree('source')
1226
os.symlink('foo', 'source/symlink')
1227
source.add('symlink', 'new-symlink')
1228
source.commit('added file')
1229
target = self.make_branch_and_tree('target')
1230
os.symlink('bar', 'target/symlink')
1231
build_tree(source.basis_tree(), target)
1232
self.assertEqual([DuplicateEntry('Moved existing file to',
1233
'symlink.moved', 'symlink', None, 'new-symlink')],
1235
target = self.make_branch_and_tree('target2')
1236
os.symlink('foo', 'target2/symlink')
1237
build_tree(source.basis_tree(), target)
1238
self.assertEqual([], target.conflicts())
1240
def test_directory_conflict_handling(self):
1241
"""Ensure that when building trees, conflict handling is done"""
1242
source = self.make_branch_and_tree('source')
1243
target = self.make_branch_and_tree('target')
1244
self.build_tree(['source/dir1/', 'source/dir1/file', 'target/dir1/'])
1245
source.add(['dir1', 'dir1/file'], ['new-dir1', 'new-file'])
1246
source.commit('added file')
1247
build_tree(source.basis_tree(), target)
1248
self.assertEqual([], target.conflicts())
1249
self.failUnlessExists('target/dir1/file')
1251
# Ensure contents are merged
1252
target = self.make_branch_and_tree('target2')
1253
self.build_tree(['target2/dir1/', 'target2/dir1/file2'])
1254
build_tree(source.basis_tree(), target)
1255
self.assertEqual([], target.conflicts())
1256
self.failUnlessExists('target2/dir1/file2')
1257
self.failUnlessExists('target2/dir1/file')
1259
# Ensure new contents are suppressed for existing branches
1260
target = self.make_branch_and_tree('target3')
1261
self.make_branch('target3/dir1')
1262
self.build_tree(['target3/dir1/file2'])
1263
build_tree(source.basis_tree(), target)
1264
self.failIfExists('target3/dir1/file')
1265
self.failUnlessExists('target3/dir1/file2')
1266
self.failUnlessExists('target3/dir1.diverted/file')
1267
self.assertEqual([DuplicateEntry('Diverted to',
1268
'dir1.diverted', 'dir1', 'new-dir1', None)],
1271
target = self.make_branch_and_tree('target4')
1272
self.build_tree(['target4/dir1/'])
1273
self.make_branch('target4/dir1/file')
1274
build_tree(source.basis_tree(), target)
1275
self.failUnlessExists('target4/dir1/file')
1276
self.assertEqual('directory', file_kind('target4/dir1/file'))
1277
self.failUnlessExists('target4/dir1/file.diverted')
1278
self.assertEqual([DuplicateEntry('Diverted to',
1279
'dir1/file.diverted', 'dir1/file', 'new-file', None)],
1282
def test_mixed_conflict_handling(self):
1283
"""Ensure that when building trees, conflict handling is done"""
1284
source = self.make_branch_and_tree('source')
1285
target = self.make_branch_and_tree('target')
1286
self.build_tree(['source/name', 'target/name/'])
1287
source.add('name', 'new-name')
1288
source.commit('added file')
1289
build_tree(source.basis_tree(), target)
1290
self.assertEqual([DuplicateEntry('Moved existing file to',
1291
'name.moved', 'name', None, 'new-name')], target.conflicts())
1293
def test_raises_in_populated(self):
1294
source = self.make_branch_and_tree('source')
1295
self.build_tree(['source/name'])
1297
source.commit('added name')
1298
target = self.make_branch_and_tree('target')
1299
self.build_tree(['target/name'])
1301
self.assertRaises(errors.WorkingTreeAlreadyPopulated,
1302
build_tree, source.basis_tree(), target)
1304
def test_build_tree_rename_count(self):
1305
source = self.make_branch_and_tree('source')
1306
self.build_tree(['source/file1', 'source/dir1/'])
1307
source.add(['file1', 'dir1'])
1308
source.commit('add1')
1309
target1 = self.make_branch_and_tree('target1')
1310
transform_result = build_tree(source.basis_tree(), target1)
1311
self.assertEqual(2, transform_result.rename_count)
1313
self.build_tree(['source/dir1/file2'])
1314
source.add(['dir1/file2'])
1315
source.commit('add3')
1316
target2 = self.make_branch_and_tree('target2')
1317
transform_result = build_tree(source.basis_tree(), target2)
1318
# children of non-root directories should not be renamed
1319
self.assertEqual(2, transform_result.rename_count)
733
1322
class MockTransform(object):
735
1324
def has_named_child(self, by_parent, parent_id, name):
759
1349
self.assertEqual(name, 'name.~1~')
760
1350
name = get_backup_name(MockEntry(), {'a':['1', '2', '3']}, 'a', tt)
761
1351
self.assertEqual(name, 'name.~4~')
1354
class TestFileMover(tests.TestCaseWithTransport):
1356
def test_file_mover(self):
1357
self.build_tree(['a/', 'a/b', 'c/', 'c/d'])
1358
mover = _FileMover()
1359
mover.rename('a', 'q')
1360
self.failUnlessExists('q')
1361
self.failIfExists('a')
1362
self.failUnlessExists('q/b')
1363
self.failUnlessExists('c')
1364
self.failUnlessExists('c/d')
1366
def test_pre_delete_rollback(self):
1367
self.build_tree(['a/'])
1368
mover = _FileMover()
1369
mover.pre_delete('a', 'q')
1370
self.failUnlessExists('q')
1371
self.failIfExists('a')
1373
self.failIfExists('q')
1374
self.failUnlessExists('a')
1376
def test_apply_deletions(self):
1377
self.build_tree(['a/', 'b/'])
1378
mover = _FileMover()
1379
mover.pre_delete('a', 'q')
1380
mover.pre_delete('b', 'r')
1381
self.failUnlessExists('q')
1382
self.failUnlessExists('r')
1383
self.failIfExists('a')
1384
self.failIfExists('b')
1385
mover.apply_deletions()
1386
self.failIfExists('q')
1387
self.failIfExists('r')
1388
self.failIfExists('a')
1389
self.failIfExists('b')
1391
def test_file_mover_rollback(self):
1392
self.build_tree(['a/', 'a/b', 'c/', 'c/d/', 'c/e/'])
1393
mover = _FileMover()
1394
mover.rename('c/d', 'c/f')
1395
mover.rename('c/e', 'c/d')
1397
mover.rename('a', 'c')
1400
self.failUnlessExists('a')
1401
self.failUnlessExists('c/d')
1404
class Bogus(Exception):
1408
class TestTransformRollback(tests.TestCaseWithTransport):
1410
class ExceptionFileMover(_FileMover):
1412
def __init__(self, bad_source=None, bad_target=None):
1413
_FileMover.__init__(self)
1414
self.bad_source = bad_source
1415
self.bad_target = bad_target
1417
def rename(self, source, target):
1418
if (self.bad_source is not None and
1419
source.endswith(self.bad_source)):
1421
elif (self.bad_target is not None and
1422
target.endswith(self.bad_target)):
1425
_FileMover.rename(self, source, target)
1427
def test_rollback_rename(self):
1428
tree = self.make_branch_and_tree('.')
1429
self.build_tree(['a/', 'a/b'])
1430
tt = TreeTransform(tree)
1431
self.addCleanup(tt.finalize)
1432
a_id = tt.trans_id_tree_path('a')
1433
tt.adjust_path('c', tt.root, a_id)
1434
tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
1435
self.assertRaises(Bogus, tt.apply,
1436
_mover=self.ExceptionFileMover(bad_source='a'))
1437
self.failUnlessExists('a')
1438
self.failUnlessExists('a/b')
1440
self.failUnlessExists('c')
1441
self.failUnlessExists('c/d')
1443
def test_rollback_rename_into_place(self):
1444
tree = self.make_branch_and_tree('.')
1445
self.build_tree(['a/', 'a/b'])
1446
tt = TreeTransform(tree)
1447
self.addCleanup(tt.finalize)
1448
a_id = tt.trans_id_tree_path('a')
1449
tt.adjust_path('c', tt.root, a_id)
1450
tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
1451
self.assertRaises(Bogus, tt.apply,
1452
_mover=self.ExceptionFileMover(bad_target='c/d'))
1453
self.failUnlessExists('a')
1454
self.failUnlessExists('a/b')
1456
self.failUnlessExists('c')
1457
self.failUnlessExists('c/d')
1459
def test_rollback_deletion(self):
1460
tree = self.make_branch_and_tree('.')
1461
self.build_tree(['a/', 'a/b'])
1462
tt = TreeTransform(tree)
1463
self.addCleanup(tt.finalize)
1464
a_id = tt.trans_id_tree_path('a')
1465
tt.delete_contents(a_id)
1466
tt.adjust_path('d', tt.root, tt.trans_id_tree_path('a/b'))
1467
self.assertRaises(Bogus, tt.apply,
1468
_mover=self.ExceptionFileMover(bad_target='d'))
1469
self.failUnlessExists('a')
1470
self.failUnlessExists('a/b')