185
234
transform3.delete_contents(oz_id)
186
235
self.assertEqual(transform3.find_conflicts(),
187
236
[('missing parent', oz_id)])
188
root_id = transform3.trans_id_tree_file_id('TREE_ROOT')
237
root_id = transform3.root
189
238
tip_id = transform3.trans_id_tree_file_id('tip-id')
190
239
transform3.adjust_path('tip', root_id, tip_id)
191
240
transform3.apply()
242
def test_conflict_on_case_insensitive(self):
243
tree = self.make_branch_and_tree('tree')
244
# Don't try this at home, kids!
245
# Force the tree to report that it is case sensitive, for conflict
247
tree.case_sensitive = True
248
transform = TreeTransform(tree)
249
self.addCleanup(transform.finalize)
250
transform.new_file('file', transform.root, 'content')
251
transform.new_file('FiLe', transform.root, 'content')
252
result = transform.find_conflicts()
253
self.assertEqual([], result)
254
# Force the tree to report that it is case insensitive, for conflict
256
tree.case_sensitive = False
257
result = transform.find_conflicts()
258
self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
260
def test_conflict_on_case_insensitive_existing(self):
261
tree = self.make_branch_and_tree('tree')
262
self.build_tree(['tree/FiLe'])
263
# Don't try this at home, kids!
264
# Force the tree to report that it is case sensitive, for conflict
266
tree.case_sensitive = True
267
transform = TreeTransform(tree)
268
self.addCleanup(transform.finalize)
269
transform.new_file('file', transform.root, 'content')
270
result = transform.find_conflicts()
271
self.assertEqual([], result)
272
# Force the tree to report that it is case insensitive, for conflict
274
tree.case_sensitive = False
275
result = transform.find_conflicts()
276
self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
278
def test_resolve_case_insensitive_conflict(self):
279
tree = self.make_branch_and_tree('tree')
280
# Don't try this at home, kids!
281
# Force the tree to report that it is case insensitive, for conflict
283
tree.case_sensitive = False
284
transform = TreeTransform(tree)
285
self.addCleanup(transform.finalize)
286
transform.new_file('file', transform.root, 'content')
287
transform.new_file('FiLe', transform.root, 'content')
288
resolve_conflicts(transform)
290
self.failUnlessExists('tree/file')
291
self.failUnlessExists('tree/FiLe.moved')
293
def test_resolve_checkout_case_conflict(self):
294
tree = self.make_branch_and_tree('tree')
295
# Don't try this at home, kids!
296
# Force the tree to report that it is case insensitive, for conflict
298
tree.case_sensitive = False
299
transform = TreeTransform(tree)
300
self.addCleanup(transform.finalize)
301
transform.new_file('file', transform.root, 'content')
302
transform.new_file('FiLe', transform.root, 'content')
303
resolve_conflicts(transform,
304
pass_func=lambda t, c: resolve_checkout(t, c, []))
306
self.failUnlessExists('tree/file')
307
self.failUnlessExists('tree/FiLe.moved')
309
def test_apply_case_conflict(self):
310
"""Ensure that a transform with case conflicts can always be applied"""
311
tree = self.make_branch_and_tree('tree')
312
transform = TreeTransform(tree)
313
self.addCleanup(transform.finalize)
314
transform.new_file('file', transform.root, 'content')
315
transform.new_file('FiLe', transform.root, 'content')
316
dir = transform.new_directory('dir', transform.root)
317
transform.new_file('dirfile', dir, 'content')
318
transform.new_file('dirFiLe', dir, 'content')
319
resolve_conflicts(transform)
321
self.failUnlessExists('tree/file')
322
if not os.path.exists('tree/FiLe.moved'):
323
self.failUnlessExists('tree/FiLe')
324
self.failUnlessExists('tree/dir/dirfile')
325
if not os.path.exists('tree/dir/dirFiLe.moved'):
326
self.failUnlessExists('tree/dir/dirFiLe')
328
def test_case_insensitive_limbo(self):
329
tree = self.make_branch_and_tree('tree')
330
# Don't try this at home, kids!
331
# Force the tree to report that it is case insensitive
332
tree.case_sensitive = False
333
transform = TreeTransform(tree)
334
self.addCleanup(transform.finalize)
335
dir = transform.new_directory('dir', transform.root)
336
first = transform.new_file('file', dir, 'content')
337
second = transform.new_file('FiLe', dir, 'content')
338
self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
339
self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
193
341
def test_add_del(self):
194
342
start, root = self.get_transform()
195
343
start.new_directory('a', root, 'a')
485
723
create.new_file('vfile', root, 'myfile-text', 'myfile-id')
486
724
create.new_file('uvfile', root, 'othertext')
488
self.assertEqual(find_interesting(wt, wt, ['vfile']),
490
self.assertRaises(NotVersionedError, find_interesting, wt, wt,
726
result = self.applyDeprecated(symbol_versioning.zero_fifteen,
727
find_interesting, wt, wt, ['vfile'])
728
self.assertEqual(result, set(['myfile-id']))
730
def test_set_executability_order(self):
731
"""Ensure that executability behaves the same, no matter what order.
733
- create file and set executability simultaneously
734
- create file and set executability afterward
735
- unsetting the executability of a file whose executability has not been
736
declared should throw an exception (this may happen when a
737
merge attempts to create a file with a duplicate ID)
739
transform, root = self.get_transform()
742
self.addCleanup(wt.unlock)
743
transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
745
sac = transform.new_file('set_after_creation', root,
746
'Set after creation', 'sac')
747
transform.set_executability(True, sac)
748
uws = transform.new_file('unset_without_set', root, 'Unset badly',
750
self.assertRaises(KeyError, transform.set_executability, None, uws)
752
self.assertTrue(wt.is_executable('soc'))
753
self.assertTrue(wt.is_executable('sac'))
755
def test_preserve_mode(self):
756
"""File mode is preserved when replacing content"""
757
if sys.platform == 'win32':
758
raise TestSkipped('chmod has no effect on win32')
759
transform, root = self.get_transform()
760
transform.new_file('file1', root, 'contents', 'file1-id', True)
763
self.addCleanup(self.wt.unlock)
764
self.assertTrue(self.wt.is_executable('file1-id'))
765
transform, root = self.get_transform()
766
file1_id = transform.trans_id_tree_file_id('file1-id')
767
transform.delete_contents(file1_id)
768
transform.create_file('contents2', file1_id)
770
self.assertTrue(self.wt.is_executable('file1-id'))
772
def test__set_mode_stats_correctly(self):
773
"""_set_mode stats to determine file mode."""
774
if sys.platform == 'win32':
775
raise TestSkipped('chmod has no effect on win32')
779
def instrumented_stat(path):
780
stat_paths.append(path)
781
return real_stat(path)
783
transform, root = self.get_transform()
785
bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
786
file_id='bar-id-1', executable=False)
789
transform, root = self.get_transform()
790
bar1_id = transform.trans_id_tree_path('bar')
791
bar2_id = transform.trans_id_tree_path('bar2')
793
os.stat = instrumented_stat
794
transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
799
bar1_abspath = self.wt.abspath('bar')
800
self.assertEqual([bar1_abspath], stat_paths)
802
def test_iter_changes(self):
803
self.wt.set_root_id('eert_toor')
804
transform, root = self.get_transform()
805
transform.new_file('old', root, 'blah', 'id-1', True)
807
transform, root = self.get_transform()
809
self.assertEqual([], list(transform._iter_changes()))
810
old = transform.trans_id_tree_file_id('id-1')
811
transform.unversion_file(old)
812
self.assertEqual([('id-1', ('old', None), False, (True, False),
813
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
814
(True, True))], list(transform._iter_changes()))
815
transform.new_directory('new', root, 'id-1')
816
self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
817
('eert_toor', 'eert_toor'), ('old', 'new'),
818
('file', 'directory'),
819
(True, False))], list(transform._iter_changes()))
823
def test_iter_changes_new(self):
824
self.wt.set_root_id('eert_toor')
825
transform, root = self.get_transform()
826
transform.new_file('old', root, 'blah')
828
transform, root = self.get_transform()
830
old = transform.trans_id_tree_path('old')
831
transform.version_file('id-1', old)
832
self.assertEqual([('id-1', (None, 'old'), False, (False, True),
833
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
834
(False, False))], list(transform._iter_changes()))
838
def test_iter_changes_modifications(self):
839
self.wt.set_root_id('eert_toor')
840
transform, root = self.get_transform()
841
transform.new_file('old', root, 'blah', 'id-1')
842
transform.new_file('new', root, 'blah')
843
transform.new_directory('subdir', root, 'subdir-id')
845
transform, root = self.get_transform()
847
old = transform.trans_id_tree_path('old')
848
subdir = transform.trans_id_tree_file_id('subdir-id')
849
new = transform.trans_id_tree_path('new')
850
self.assertEqual([], list(transform._iter_changes()))
853
transform.delete_contents(old)
854
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
855
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
856
(False, False))], list(transform._iter_changes()))
859
transform.create_file('blah', old)
860
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
861
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
862
(False, False))], list(transform._iter_changes()))
863
transform.cancel_deletion(old)
864
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
865
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
866
(False, False))], list(transform._iter_changes()))
867
transform.cancel_creation(old)
869
# move file_id to a different file
870
self.assertEqual([], list(transform._iter_changes()))
871
transform.unversion_file(old)
872
transform.version_file('id-1', new)
873
transform.adjust_path('old', root, new)
874
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
875
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
876
(False, False))], list(transform._iter_changes()))
877
transform.cancel_versioning(new)
878
transform._removed_id = set()
881
self.assertEqual([], list(transform._iter_changes()))
882
transform.set_executability(True, old)
883
self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
884
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
885
(False, True))], list(transform._iter_changes()))
886
transform.set_executability(None, old)
889
self.assertEqual([], list(transform._iter_changes()))
890
transform.adjust_path('new', root, old)
891
transform._new_parent = {}
892
self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
893
('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
894
(False, False))], list(transform._iter_changes()))
895
transform._new_name = {}
898
self.assertEqual([], list(transform._iter_changes()))
899
transform.adjust_path('new', subdir, old)
900
transform._new_name = {}
901
self.assertEqual([('id-1', ('old', 'subdir/old'), False,
902
(True, True), ('eert_toor', 'subdir-id'), ('old', 'old'),
903
('file', 'file'), (False, False))],
904
list(transform._iter_changes()))
905
transform._new_path = {}
910
def test_iter_changes_modified_bleed(self):
911
self.wt.set_root_id('eert_toor')
912
"""Modified flag should not bleed from one change to another"""
913
# unfortunately, we have no guarantee that file1 (which is modified)
914
# will be applied before file2. And if it's applied after file2, it
915
# obviously can't bleed into file2's change output. But for now, it
917
transform, root = self.get_transform()
918
transform.new_file('file1', root, 'blah', 'id-1')
919
transform.new_file('file2', root, 'blah', 'id-2')
921
transform, root = self.get_transform()
923
transform.delete_contents(transform.trans_id_file_id('id-1'))
924
transform.set_executability(True,
925
transform.trans_id_file_id('id-2'))
926
self.assertEqual([('id-1', (u'file1', u'file1'), True, (True, True),
927
('eert_toor', 'eert_toor'), ('file1', u'file1'),
928
('file', None), (False, False)),
929
('id-2', (u'file2', u'file2'), False, (True, True),
930
('eert_toor', 'eert_toor'), ('file2', u'file2'),
931
('file', 'file'), (False, True))],
932
list(transform._iter_changes()))
936
def test_iter_changes_move_missing(self):
937
"""Test moving ids with no files around"""
938
self.wt.set_root_id('toor_eert')
939
# Need two steps because versioning a non-existant file is a conflict.
940
transform, root = self.get_transform()
941
transform.new_directory('floater', root, 'floater-id')
943
transform, root = self.get_transform()
944
transform.delete_contents(transform.trans_id_tree_path('floater'))
946
transform, root = self.get_transform()
947
floater = transform.trans_id_tree_path('floater')
949
transform.adjust_path('flitter', root, floater)
950
self.assertEqual([('floater-id', ('floater', 'flitter'), False,
951
(True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
952
(None, None), (False, False))], list(transform._iter_changes()))
956
def test_iter_changes_pointless(self):
957
"""Ensure that no-ops are not treated as modifications"""
958
self.wt.set_root_id('eert_toor')
959
transform, root = self.get_transform()
960
transform.new_file('old', root, 'blah', 'id-1')
961
transform.new_directory('subdir', root, 'subdir-id')
963
transform, root = self.get_transform()
965
old = transform.trans_id_tree_path('old')
966
subdir = transform.trans_id_tree_file_id('subdir-id')
967
self.assertEqual([], list(transform._iter_changes()))
968
transform.delete_contents(subdir)
969
transform.create_directory(subdir)
970
transform.set_executability(False, old)
971
transform.unversion_file(old)
972
transform.version_file('id-1', old)
973
transform.adjust_path('old', root, old)
974
self.assertEqual([], list(transform._iter_changes()))
978
def test_rename_count(self):
979
transform, root = self.get_transform()
980
transform.new_file('name1', root, 'contents')
981
self.assertEqual(transform.rename_count, 0)
983
self.assertEqual(transform.rename_count, 1)
984
transform2, root = self.get_transform()
985
transform2.adjust_path('name2', root,
986
transform2.trans_id_tree_path('name1'))
987
self.assertEqual(transform2.rename_count, 0)
989
self.assertEqual(transform2.rename_count, 2)
991
def test_change_parent(self):
992
"""Ensure that after we change a parent, the results are still right.
994
Renames and parent changes on pending transforms can happen as part
995
of conflict resolution, and are explicitly permitted by the
998
This test ensures they work correctly with the rename-avoidance
1001
transform, root = self.get_transform()
1002
parent1 = transform.new_directory('parent1', root)
1003
child1 = transform.new_file('child1', parent1, 'contents')
1004
parent2 = transform.new_directory('parent2', root)
1005
transform.adjust_path('child1', parent2, child1)
1007
self.failIfExists(self.wt.abspath('parent1/child1'))
1008
self.failUnlessExists(self.wt.abspath('parent2/child1'))
1009
# rename limbo/new-1 => parent1, rename limbo/new-3 => parent2
1010
# no rename for child1 (counting only renames during apply)
1011
self.failUnlessEqual(2, transform.rename_count)
1013
def test_cancel_parent(self):
1014
"""Cancelling a parent doesn't cause deletion of a non-empty directory
1016
This is like the test_change_parent, except that we cancel the parent
1017
before adjusting the path. The transform must detect that the
1018
directory is non-empty, and move children to safe locations.
1020
transform, root = self.get_transform()
1021
parent1 = transform.new_directory('parent1', root)
1022
child1 = transform.new_file('child1', parent1, 'contents')
1023
child2 = transform.new_file('child2', parent1, 'contents')
1025
transform.cancel_creation(parent1)
1027
self.fail('Failed to move child1 before deleting parent1')
1028
transform.cancel_creation(child2)
1029
transform.create_directory(parent1)
1031
transform.cancel_creation(parent1)
1032
# If the transform incorrectly believes that child2 is still in
1033
# parent1's limbo directory, it will try to rename it and fail
1034
# because was already moved by the first cancel_creation.
1036
self.fail('Transform still thinks child2 is a child of parent1')
1037
parent2 = transform.new_directory('parent2', root)
1038
transform.adjust_path('child1', parent2, child1)
1040
self.failIfExists(self.wt.abspath('parent1'))
1041
self.failUnlessExists(self.wt.abspath('parent2/child1'))
1042
# rename limbo/new-3 => parent2, rename limbo/new-2 => child1
1043
self.failUnlessEqual(2, transform.rename_count)
1045
def test_adjust_and_cancel(self):
1046
"""Make sure adjust_path keeps track of limbo children properly"""
1047
transform, root = self.get_transform()
1048
parent1 = transform.new_directory('parent1', root)
1049
child1 = transform.new_file('child1', parent1, 'contents')
1050
parent2 = transform.new_directory('parent2', root)
1051
transform.adjust_path('child1', parent2, child1)
1052
transform.cancel_creation(child1)
1054
transform.cancel_creation(parent1)
1055
# if the transform thinks child1 is still in parent1's limbo
1056
# directory, it will attempt to move it and fail.
1058
self.fail('Transform still thinks child1 is a child of parent1')
1059
transform.finalize()
1061
def test_noname_contents(self):
1062
"""TreeTransform should permit deferring naming files."""
1063
transform, root = self.get_transform()
1064
parent = transform.trans_id_file_id('parent-id')
1066
transform.create_directory(parent)
1068
self.fail("Can't handle contents with no name")
1069
transform.finalize()
1071
def test_noname_contents_nested(self):
1072
"""TreeTransform should permit deferring naming files."""
1073
transform, root = self.get_transform()
1074
parent = transform.trans_id_file_id('parent-id')
1076
transform.create_directory(parent)
1078
self.fail("Can't handle contents with no name")
1079
child = transform.new_directory('child', parent)
1080
transform.adjust_path('parent', root, parent)
1082
self.failUnlessExists(self.wt.abspath('parent/child'))
1083
self.assertEqual(1, transform.rename_count)
1085
def test_reuse_name(self):
1086
"""Avoid reusing the same limbo name for different files"""
1087
transform, root = self.get_transform()
1088
parent = transform.new_directory('parent', root)
1089
child1 = transform.new_directory('child', parent)
1091
child2 = transform.new_directory('child', parent)
1093
self.fail('Tranform tried to use the same limbo name twice')
1094
transform.adjust_path('child2', parent, child2)
1096
# limbo/new-1 => parent, limbo/new-3 => parent/child2
1097
# child2 is put into top-level limbo because child1 has already
1098
# claimed the direct limbo path when child2 is created. There is no
1099
# advantage in renaming files once they're in top-level limbo, except
1101
self.assertEqual(2, transform.rename_count)
1103
def test_reuse_when_first_moved(self):
1104
"""Don't avoid direct paths when it is safe to use them"""
1105
transform, root = self.get_transform()
1106
parent = transform.new_directory('parent', root)
1107
child1 = transform.new_directory('child', parent)
1108
transform.adjust_path('child1', parent, child1)
1109
child2 = transform.new_directory('child', parent)
1111
# limbo/new-1 => parent
1112
self.assertEqual(1, transform.rename_count)
1114
def test_reuse_after_cancel(self):
1115
"""Don't avoid direct paths when it is safe to use them"""
1116
transform, root = self.get_transform()
1117
parent2 = transform.new_directory('parent2', root)
1118
child1 = transform.new_directory('child1', parent2)
1119
transform.cancel_creation(parent2)
1120
transform.create_directory(parent2)
1121
child2 = transform.new_directory('child1', parent2)
1122
transform.adjust_path('child2', parent2, child1)
1124
# limbo/new-1 => parent2, limbo/new-2 => parent2/child1
1125
self.assertEqual(2, transform.rename_count)
1127
def test_finalize_order(self):
1128
"""Finalize must be done in child-to-parent order"""
1129
transform, root = self.get_transform()
1130
parent = transform.new_directory('parent', root)
1131
child = transform.new_directory('child', parent)
1133
transform.finalize()
1135
self.fail('Tried to remove parent before child1')
1137
def test_cancel_with_cancelled_child_should_succeed(self):
1138
transform, root = self.get_transform()
1139
parent = transform.new_directory('parent', root)
1140
child = transform.new_directory('child', parent)
1141
transform.cancel_creation(child)
1142
transform.cancel_creation(parent)
1143
transform.finalize()
1145
def test_change_entry(self):
1146
txt = 'bzrlib.transform.change_entry was deprecated in version 0.90.'
1147
self.callDeprecated([txt], change_entry, None, None, None, None, None,
1150
def test_case_insensitive_clash(self):
1151
self.requireFeature(CaseInsensitiveFilesystemFeature)
1153
wt = self.make_branch_and_tree('.')
1154
tt = TreeTransform(wt) # TreeTransform obtains write lock
1156
tt.new_file('foo', tt.root, 'bar')
1157
tt.new_file('Foo', tt.root, 'spam')
1158
# Lie to tt that we've already resolved all conflicts.
1159
tt.apply(no_conflicts=True)
1163
err = self.assertRaises(errors.FileExists, tt_helper)
1164
self.assertContainsRe(str(err),
1165
"^File exists: .+/foo")
1167
def test_two_directories_clash(self):
1169
wt = self.make_branch_and_tree('.')
1170
tt = TreeTransform(wt) # TreeTransform obtains write lock
1172
foo_1 = tt.new_directory('foo', tt.root)
1173
tt.new_directory('bar', foo_1)
1174
foo_2 = tt.new_directory('foo', tt.root)
1175
tt.new_directory('baz', foo_2)
1176
# Lie to tt that we've already resolved all conflicts.
1177
tt.apply(no_conflicts=True)
1181
err = self.assertRaises(errors.FileExists, tt_helper)
1182
self.assertContainsRe(str(err),
1183
"^File exists: .+/foo")
1185
def test_two_directories_clash_finalize(self):
1187
wt = self.make_branch_and_tree('.')
1188
tt = TreeTransform(wt) # TreeTransform obtains write lock
1190
foo_1 = tt.new_directory('foo', tt.root)
1191
tt.new_directory('bar', foo_1)
1192
foo_2 = tt.new_directory('foo', tt.root)
1193
tt.new_directory('baz', foo_2)
1194
# Lie to tt that we've already resolved all conflicts.
1195
tt.apply(no_conflicts=True)
1199
err = self.assertRaises(errors.FileExists, tt_helper)
1200
self.assertContainsRe(str(err),
1201
"^File exists: .+/foo")
494
1204
class TransformGroup(object):
495
def __init__(self, dirname):
1206
def __init__(self, dirname, root_id):
496
1207
self.name = dirname
497
1208
os.mkdir(dirname)
498
1209
self.wt = BzrDir.create_standalone_workingtree(dirname)
1210
self.wt.set_root_id(root_id)
499
1211
self.b = self.wt.branch
500
1212
self.tt = TreeTransform(self.wt)
501
1213
self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
503
1216
def conflict_text(tree, merge):
504
1217
template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
505
1218
return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
698
1415
a.add(['foo', 'foo/bar', 'foo/baz'])
699
1416
a.commit('initial commit')
700
1417
b = BzrDir.create_standalone_workingtree('b')
701
build_tree(a.basis_tree(), b)
1418
basis = a.basis_tree()
1420
self.addCleanup(basis.unlock)
1421
build_tree(basis, b)
702
1422
self.assertIs(os.path.isdir('b/foo'), True)
703
1423
self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
704
1424
self.assertEqual(os.readlink('b/foo/baz'), 'a/foo/bar')
1426
def test_build_with_references(self):
1427
tree = self.make_branch_and_tree('source',
1428
format='dirstate-with-subtree')
1429
subtree = self.make_branch_and_tree('source/subtree',
1430
format='dirstate-with-subtree')
1431
tree.add_reference(subtree)
1432
tree.commit('a revision')
1433
tree.branch.create_checkout('target')
1434
self.failUnlessExists('target')
1435
self.failUnlessExists('target/subtree')
1437
def test_file_conflict_handling(self):
1438
"""Ensure that when building trees, conflict handling is done"""
1439
source = self.make_branch_and_tree('source')
1440
target = self.make_branch_and_tree('target')
1441
self.build_tree(['source/file', 'target/file'])
1442
source.add('file', 'new-file')
1443
source.commit('added file')
1444
build_tree(source.basis_tree(), target)
1445
self.assertEqual([DuplicateEntry('Moved existing file to',
1446
'file.moved', 'file', None, 'new-file')],
1448
target2 = self.make_branch_and_tree('target2')
1449
target_file = file('target2/file', 'wb')
1451
source_file = file('source/file', 'rb')
1453
target_file.write(source_file.read())
1458
build_tree(source.basis_tree(), target2)
1459
self.assertEqual([], target2.conflicts())
1461
def test_symlink_conflict_handling(self):
1462
"""Ensure that when building trees, conflict handling is done"""
1463
self.requireFeature(SymlinkFeature)
1464
source = self.make_branch_and_tree('source')
1465
os.symlink('foo', 'source/symlink')
1466
source.add('symlink', 'new-symlink')
1467
source.commit('added file')
1468
target = self.make_branch_and_tree('target')
1469
os.symlink('bar', 'target/symlink')
1470
build_tree(source.basis_tree(), target)
1471
self.assertEqual([DuplicateEntry('Moved existing file to',
1472
'symlink.moved', 'symlink', None, 'new-symlink')],
1474
target = self.make_branch_and_tree('target2')
1475
os.symlink('foo', 'target2/symlink')
1476
build_tree(source.basis_tree(), target)
1477
self.assertEqual([], target.conflicts())
1479
def test_directory_conflict_handling(self):
1480
"""Ensure that when building trees, conflict handling is done"""
1481
source = self.make_branch_and_tree('source')
1482
target = self.make_branch_and_tree('target')
1483
self.build_tree(['source/dir1/', 'source/dir1/file', 'target/dir1/'])
1484
source.add(['dir1', 'dir1/file'], ['new-dir1', 'new-file'])
1485
source.commit('added file')
1486
build_tree(source.basis_tree(), target)
1487
self.assertEqual([], target.conflicts())
1488
self.failUnlessExists('target/dir1/file')
1490
# Ensure contents are merged
1491
target = self.make_branch_and_tree('target2')
1492
self.build_tree(['target2/dir1/', 'target2/dir1/file2'])
1493
build_tree(source.basis_tree(), target)
1494
self.assertEqual([], target.conflicts())
1495
self.failUnlessExists('target2/dir1/file2')
1496
self.failUnlessExists('target2/dir1/file')
1498
# Ensure new contents are suppressed for existing branches
1499
target = self.make_branch_and_tree('target3')
1500
self.make_branch('target3/dir1')
1501
self.build_tree(['target3/dir1/file2'])
1502
build_tree(source.basis_tree(), target)
1503
self.failIfExists('target3/dir1/file')
1504
self.failUnlessExists('target3/dir1/file2')
1505
self.failUnlessExists('target3/dir1.diverted/file')
1506
self.assertEqual([DuplicateEntry('Diverted to',
1507
'dir1.diverted', 'dir1', 'new-dir1', None)],
1510
target = self.make_branch_and_tree('target4')
1511
self.build_tree(['target4/dir1/'])
1512
self.make_branch('target4/dir1/file')
1513
build_tree(source.basis_tree(), target)
1514
self.failUnlessExists('target4/dir1/file')
1515
self.assertEqual('directory', file_kind('target4/dir1/file'))
1516
self.failUnlessExists('target4/dir1/file.diverted')
1517
self.assertEqual([DuplicateEntry('Diverted to',
1518
'dir1/file.diverted', 'dir1/file', 'new-file', None)],
1521
def test_mixed_conflict_handling(self):
1522
"""Ensure that when building trees, conflict handling is done"""
1523
source = self.make_branch_and_tree('source')
1524
target = self.make_branch_and_tree('target')
1525
self.build_tree(['source/name', 'target/name/'])
1526
source.add('name', 'new-name')
1527
source.commit('added file')
1528
build_tree(source.basis_tree(), target)
1529
self.assertEqual([DuplicateEntry('Moved existing file to',
1530
'name.moved', 'name', None, 'new-name')], target.conflicts())
1532
def test_raises_in_populated(self):
1533
source = self.make_branch_and_tree('source')
1534
self.build_tree(['source/name'])
1536
source.commit('added name')
1537
target = self.make_branch_and_tree('target')
1538
self.build_tree(['target/name'])
1540
self.assertRaises(errors.WorkingTreeAlreadyPopulated,
1541
build_tree, source.basis_tree(), target)
1543
def test_build_tree_rename_count(self):
1544
source = self.make_branch_and_tree('source')
1545
self.build_tree(['source/file1', 'source/dir1/'])
1546
source.add(['file1', 'dir1'])
1547
source.commit('add1')
1548
target1 = self.make_branch_and_tree('target1')
1549
transform_result = build_tree(source.basis_tree(), target1)
1550
self.assertEqual(2, transform_result.rename_count)
1552
self.build_tree(['source/dir1/file2'])
1553
source.add(['dir1/file2'])
1554
source.commit('add3')
1555
target2 = self.make_branch_and_tree('target2')
1556
transform_result = build_tree(source.basis_tree(), target2)
1557
# children of non-root directories should not be renamed
1558
self.assertEqual(2, transform_result.rename_count)
1560
def test_build_tree_accelerator_tree(self):
1561
source = self.make_branch_and_tree('source')
1562
self.build_tree_contents([('source/file1', 'A')])
1563
self.build_tree_contents([('source/file2', 'B')])
1564
source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
1565
source.commit('commit files')
1566
self.build_tree_contents([('source/file2', 'C')])
1568
real_source_get_file = source.get_file
1569
def get_file(file_id, path=None):
1570
calls.append(file_id)
1571
return real_source_get_file(file_id, path)
1572
source.get_file = get_file
1574
self.addCleanup(source.unlock)
1575
target = self.make_branch_and_tree('target')
1576
revision_tree = source.basis_tree()
1577
revision_tree.lock_read()
1578
self.addCleanup(revision_tree.unlock)
1579
build_tree(revision_tree, target, source)
1580
self.assertEqual(['file1-id'], calls)
1582
self.addCleanup(target.unlock)
1583
self.assertEqual([], list(target._iter_changes(revision_tree)))
1585
def test_build_tree_accelerator_tree_missing_file(self):
1586
source = self.make_branch_and_tree('source')
1587
self.build_tree_contents([('source/file1', 'A')])
1588
self.build_tree_contents([('source/file2', 'B')])
1589
source.add(['file1', 'file2'])
1590
source.commit('commit files')
1591
os.unlink('source/file1')
1592
source.remove(['file2'])
1593
target = self.make_branch_and_tree('target')
1594
revision_tree = source.basis_tree()
1595
revision_tree.lock_read()
1596
self.addCleanup(revision_tree.unlock)
1597
build_tree(revision_tree, target, source)
1599
self.addCleanup(target.unlock)
1600
self.assertEqual([], list(target._iter_changes(revision_tree)))
1602
def test_build_tree_accelerator_wrong_kind(self):
1603
self.requireFeature(SymlinkFeature)
1604
source = self.make_branch_and_tree('source')
1605
self.build_tree_contents([('source/file1', '')])
1606
self.build_tree_contents([('source/file2', '')])
1607
source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
1608
source.commit('commit files')
1609
os.unlink('source/file2')
1610
self.build_tree_contents([('source/file2/', 'C')])
1611
os.unlink('source/file1')
1612
os.symlink('file2', 'source/file1')
1614
real_source_get_file = source.get_file
1615
def get_file(file_id, path=None):
1616
calls.append(file_id)
1617
return real_source_get_file(file_id, path)
1618
source.get_file = get_file
1620
self.addCleanup(source.unlock)
1621
target = self.make_branch_and_tree('target')
1622
revision_tree = source.basis_tree()
1623
revision_tree.lock_read()
1624
self.addCleanup(revision_tree.unlock)
1625
build_tree(revision_tree, target, source)
1626
self.assertEqual([], calls)
1628
self.addCleanup(target.unlock)
1629
self.assertEqual([], list(target._iter_changes(revision_tree)))
1631
def test_build_tree_accelerator_tree_moved(self):
1632
source = self.make_branch_and_tree('source')
1633
self.build_tree_contents([('source/file1', 'A')])
1634
source.add(['file1'], ['file1-id'])
1635
source.commit('commit files')
1636
source.rename_one('file1', 'file2')
1638
self.addCleanup(source.unlock)
1639
target = self.make_branch_and_tree('target')
1640
revision_tree = source.basis_tree()
1641
revision_tree.lock_read()
1642
self.addCleanup(revision_tree.unlock)
1643
build_tree(revision_tree, target, source)
1645
self.addCleanup(target.unlock)
1646
self.assertEqual([], list(target._iter_changes(revision_tree)))
706
1649
class MockTransform(object):
708
1651
def has_named_child(self, by_parent, parent_id, name):