185
255
transform3.delete_contents(oz_id)
186
256
self.assertEqual(transform3.find_conflicts(),
187
257
[('missing parent', oz_id)])
188
root_id = transform3.trans_id_tree_file_id('TREE_ROOT')
258
root_id = transform3.root
189
259
tip_id = transform3.trans_id_tree_file_id('tip-id')
190
260
transform3.adjust_path('tip', root_id, tip_id)
191
261
transform3.apply()
263
def test_conflict_on_case_insensitive(self):
264
tree = self.make_branch_and_tree('tree')
265
# Don't try this at home, kids!
266
# Force the tree to report that it is case sensitive, for conflict
268
tree.case_sensitive = True
269
transform = TreeTransform(tree)
270
self.addCleanup(transform.finalize)
271
transform.new_file('file', transform.root, 'content')
272
transform.new_file('FiLe', transform.root, 'content')
273
result = transform.find_conflicts()
274
self.assertEqual([], result)
276
# Force the tree to report that it is case insensitive, for conflict
278
tree.case_sensitive = False
279
transform = TreeTransform(tree)
280
self.addCleanup(transform.finalize)
281
transform.new_file('file', transform.root, 'content')
282
transform.new_file('FiLe', transform.root, 'content')
283
result = transform.find_conflicts()
284
self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
286
def test_conflict_on_case_insensitive_existing(self):
287
tree = self.make_branch_and_tree('tree')
288
self.build_tree(['tree/FiLe'])
289
# Don't try this at home, kids!
290
# Force the tree to report that it is case sensitive, for conflict
292
tree.case_sensitive = True
293
transform = TreeTransform(tree)
294
self.addCleanup(transform.finalize)
295
transform.new_file('file', transform.root, 'content')
296
result = transform.find_conflicts()
297
self.assertEqual([], result)
299
# Force the tree to report that it is case insensitive, for conflict
301
tree.case_sensitive = False
302
transform = TreeTransform(tree)
303
self.addCleanup(transform.finalize)
304
transform.new_file('file', transform.root, 'content')
305
result = transform.find_conflicts()
306
self.assertEqual([('duplicate', 'new-1', 'new-2', 'file')], result)
308
def test_resolve_case_insensitive_conflict(self):
309
tree = self.make_branch_and_tree('tree')
310
# Don't try this at home, kids!
311
# Force the tree to report that it is case insensitive, for conflict
313
tree.case_sensitive = False
314
transform = TreeTransform(tree)
315
self.addCleanup(transform.finalize)
316
transform.new_file('file', transform.root, 'content')
317
transform.new_file('FiLe', transform.root, 'content')
318
resolve_conflicts(transform)
320
self.failUnlessExists('tree/file')
321
self.failUnlessExists('tree/FiLe.moved')
323
def test_resolve_checkout_case_conflict(self):
324
tree = self.make_branch_and_tree('tree')
325
# Don't try this at home, kids!
326
# Force the tree to report that it is case insensitive, for conflict
328
tree.case_sensitive = False
329
transform = TreeTransform(tree)
330
self.addCleanup(transform.finalize)
331
transform.new_file('file', transform.root, 'content')
332
transform.new_file('FiLe', transform.root, 'content')
333
resolve_conflicts(transform,
334
pass_func=lambda t, c: resolve_checkout(t, c, []))
336
self.failUnlessExists('tree/file')
337
self.failUnlessExists('tree/FiLe.moved')
339
def test_apply_case_conflict(self):
340
"""Ensure that a transform with case conflicts can always be applied"""
341
tree = self.make_branch_and_tree('tree')
342
transform = TreeTransform(tree)
343
self.addCleanup(transform.finalize)
344
transform.new_file('file', transform.root, 'content')
345
transform.new_file('FiLe', transform.root, 'content')
346
dir = transform.new_directory('dir', transform.root)
347
transform.new_file('dirfile', dir, 'content')
348
transform.new_file('dirFiLe', dir, 'content')
349
resolve_conflicts(transform)
351
self.failUnlessExists('tree/file')
352
if not os.path.exists('tree/FiLe.moved'):
353
self.failUnlessExists('tree/FiLe')
354
self.failUnlessExists('tree/dir/dirfile')
355
if not os.path.exists('tree/dir/dirFiLe.moved'):
356
self.failUnlessExists('tree/dir/dirFiLe')
358
def test_case_insensitive_limbo(self):
359
tree = self.make_branch_and_tree('tree')
360
# Don't try this at home, kids!
361
# Force the tree to report that it is case insensitive
362
tree.case_sensitive = False
363
transform = TreeTransform(tree)
364
self.addCleanup(transform.finalize)
365
dir = transform.new_directory('dir', transform.root)
366
first = transform.new_file('file', dir, 'content')
367
second = transform.new_file('FiLe', dir, 'content')
368
self.assertContainsRe(transform._limbo_name(first), 'new-1/file')
369
self.assertNotContainsRe(transform._limbo_name(second), 'new-1/FiLe')
193
371
def test_add_del(self):
194
372
start, root = self.get_transform()
195
373
start.new_directory('a', root, 'a')
479
747
rename.set_executability(True, myfile)
482
def test_find_interesting(self):
483
create, root = self.get_transform()
485
create.new_file('vfile', root, 'myfile-text', 'myfile-id')
486
create.new_file('uvfile', root, 'othertext')
488
self.assertEqual(find_interesting(wt, wt, ['vfile']),
490
self.assertRaises(NotVersionedError, find_interesting, wt, wt,
750
def test_set_executability_order(self):
751
"""Ensure that executability behaves the same, no matter what order.
753
- create file and set executability simultaneously
754
- create file and set executability afterward
755
- unsetting the executability of a file whose executability has not been
756
declared should throw an exception (this may happen when a
757
merge attempts to create a file with a duplicate ID)
759
transform, root = self.get_transform()
762
self.addCleanup(wt.unlock)
763
transform.new_file('set_on_creation', root, 'Set on creation', 'soc',
765
sac = transform.new_file('set_after_creation', root,
766
'Set after creation', 'sac')
767
transform.set_executability(True, sac)
768
uws = transform.new_file('unset_without_set', root, 'Unset badly',
770
self.assertRaises(KeyError, transform.set_executability, None, uws)
772
self.assertTrue(wt.is_executable('soc'))
773
self.assertTrue(wt.is_executable('sac'))
775
def test_preserve_mode(self):
776
"""File mode is preserved when replacing content"""
777
if sys.platform == 'win32':
778
raise TestSkipped('chmod has no effect on win32')
779
transform, root = self.get_transform()
780
transform.new_file('file1', root, 'contents', 'file1-id', True)
783
self.addCleanup(self.wt.unlock)
784
self.assertTrue(self.wt.is_executable('file1-id'))
785
transform, root = self.get_transform()
786
file1_id = transform.trans_id_tree_file_id('file1-id')
787
transform.delete_contents(file1_id)
788
transform.create_file('contents2', file1_id)
790
self.assertTrue(self.wt.is_executable('file1-id'))
792
def test__set_mode_stats_correctly(self):
793
"""_set_mode stats to determine file mode."""
794
if sys.platform == 'win32':
795
raise TestSkipped('chmod has no effect on win32')
799
def instrumented_stat(path):
800
stat_paths.append(path)
801
return real_stat(path)
803
transform, root = self.get_transform()
805
bar1_id = transform.new_file('bar', root, 'bar contents 1\n',
806
file_id='bar-id-1', executable=False)
809
transform, root = self.get_transform()
810
bar1_id = transform.trans_id_tree_path('bar')
811
bar2_id = transform.trans_id_tree_path('bar2')
813
os.stat = instrumented_stat
814
transform.create_file('bar2 contents\n', bar2_id, mode_id=bar1_id)
819
bar1_abspath = self.wt.abspath('bar')
820
self.assertEqual([bar1_abspath], stat_paths)
822
def test_iter_changes(self):
823
self.wt.set_root_id('eert_toor')
824
transform, root = self.get_transform()
825
transform.new_file('old', root, 'blah', 'id-1', True)
827
transform, root = self.get_transform()
829
self.assertEqual([], list(transform.iter_changes()))
830
old = transform.trans_id_tree_file_id('id-1')
831
transform.unversion_file(old)
832
self.assertEqual([('id-1', ('old', None), False, (True, False),
833
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
834
(True, True))], list(transform.iter_changes()))
835
transform.new_directory('new', root, 'id-1')
836
self.assertEqual([('id-1', ('old', 'new'), True, (True, True),
837
('eert_toor', 'eert_toor'), ('old', 'new'),
838
('file', 'directory'),
839
(True, False))], list(transform.iter_changes()))
843
def test_iter_changes_new(self):
844
self.wt.set_root_id('eert_toor')
845
transform, root = self.get_transform()
846
transform.new_file('old', root, 'blah')
848
transform, root = self.get_transform()
850
old = transform.trans_id_tree_path('old')
851
transform.version_file('id-1', old)
852
self.assertEqual([('id-1', (None, 'old'), False, (False, True),
853
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
854
(False, False))], list(transform.iter_changes()))
858
def test_iter_changes_modifications(self):
859
self.wt.set_root_id('eert_toor')
860
transform, root = self.get_transform()
861
transform.new_file('old', root, 'blah', 'id-1')
862
transform.new_file('new', root, 'blah')
863
transform.new_directory('subdir', root, 'subdir-id')
865
transform, root = self.get_transform()
867
old = transform.trans_id_tree_path('old')
868
subdir = transform.trans_id_tree_file_id('subdir-id')
869
new = transform.trans_id_tree_path('new')
870
self.assertEqual([], list(transform.iter_changes()))
873
transform.delete_contents(old)
874
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
875
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', None),
876
(False, False))], list(transform.iter_changes()))
879
transform.create_file('blah', old)
880
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
881
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
882
(False, False))], list(transform.iter_changes()))
883
transform.cancel_deletion(old)
884
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
885
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
886
(False, False))], list(transform.iter_changes()))
887
transform.cancel_creation(old)
889
# move file_id to a different file
890
self.assertEqual([], list(transform.iter_changes()))
891
transform.unversion_file(old)
892
transform.version_file('id-1', new)
893
transform.adjust_path('old', root, new)
894
self.assertEqual([('id-1', ('old', 'old'), True, (True, True),
895
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
896
(False, False))], list(transform.iter_changes()))
897
transform.cancel_versioning(new)
898
transform._removed_id = set()
901
self.assertEqual([], list(transform.iter_changes()))
902
transform.set_executability(True, old)
903
self.assertEqual([('id-1', ('old', 'old'), False, (True, True),
904
('eert_toor', 'eert_toor'), ('old', 'old'), ('file', 'file'),
905
(False, True))], list(transform.iter_changes()))
906
transform.set_executability(None, old)
909
self.assertEqual([], list(transform.iter_changes()))
910
transform.adjust_path('new', root, old)
911
transform._new_parent = {}
912
self.assertEqual([('id-1', ('old', 'new'), False, (True, True),
913
('eert_toor', 'eert_toor'), ('old', 'new'), ('file', 'file'),
914
(False, False))], list(transform.iter_changes()))
915
transform._new_name = {}
918
self.assertEqual([], list(transform.iter_changes()))
919
transform.adjust_path('new', subdir, old)
920
transform._new_name = {}
921
self.assertEqual([('id-1', ('old', 'subdir/old'), False,
922
(True, True), ('eert_toor', 'subdir-id'), ('old', 'old'),
923
('file', 'file'), (False, False))],
924
list(transform.iter_changes()))
925
transform._new_path = {}
930
def test_iter_changes_modified_bleed(self):
931
self.wt.set_root_id('eert_toor')
932
"""Modified flag should not bleed from one change to another"""
933
# unfortunately, we have no guarantee that file1 (which is modified)
934
# will be applied before file2. And if it's applied after file2, it
935
# obviously can't bleed into file2's change output. But for now, it
937
transform, root = self.get_transform()
938
transform.new_file('file1', root, 'blah', 'id-1')
939
transform.new_file('file2', root, 'blah', 'id-2')
941
transform, root = self.get_transform()
943
transform.delete_contents(transform.trans_id_file_id('id-1'))
944
transform.set_executability(True,
945
transform.trans_id_file_id('id-2'))
946
self.assertEqual([('id-1', (u'file1', u'file1'), True, (True, True),
947
('eert_toor', 'eert_toor'), ('file1', u'file1'),
948
('file', None), (False, False)),
949
('id-2', (u'file2', u'file2'), False, (True, True),
950
('eert_toor', 'eert_toor'), ('file2', u'file2'),
951
('file', 'file'), (False, True))],
952
list(transform.iter_changes()))
956
def test_iter_changes_move_missing(self):
957
"""Test moving ids with no files around"""
958
self.wt.set_root_id('toor_eert')
959
# Need two steps because versioning a non-existant file is a conflict.
960
transform, root = self.get_transform()
961
transform.new_directory('floater', root, 'floater-id')
963
transform, root = self.get_transform()
964
transform.delete_contents(transform.trans_id_tree_path('floater'))
966
transform, root = self.get_transform()
967
floater = transform.trans_id_tree_path('floater')
969
transform.adjust_path('flitter', root, floater)
970
self.assertEqual([('floater-id', ('floater', 'flitter'), False,
971
(True, True), ('toor_eert', 'toor_eert'), ('floater', 'flitter'),
972
(None, None), (False, False))], list(transform.iter_changes()))
976
def test_iter_changes_pointless(self):
977
"""Ensure that no-ops are not treated as modifications"""
978
self.wt.set_root_id('eert_toor')
979
transform, root = self.get_transform()
980
transform.new_file('old', root, 'blah', 'id-1')
981
transform.new_directory('subdir', root, 'subdir-id')
983
transform, root = self.get_transform()
985
old = transform.trans_id_tree_path('old')
986
subdir = transform.trans_id_tree_file_id('subdir-id')
987
self.assertEqual([], list(transform.iter_changes()))
988
transform.delete_contents(subdir)
989
transform.create_directory(subdir)
990
transform.set_executability(False, old)
991
transform.unversion_file(old)
992
transform.version_file('id-1', old)
993
transform.adjust_path('old', root, old)
994
self.assertEqual([], list(transform.iter_changes()))
998
def test_rename_count(self):
999
transform, root = self.get_transform()
1000
transform.new_file('name1', root, 'contents')
1001
self.assertEqual(transform.rename_count, 0)
1003
self.assertEqual(transform.rename_count, 1)
1004
transform2, root = self.get_transform()
1005
transform2.adjust_path('name2', root,
1006
transform2.trans_id_tree_path('name1'))
1007
self.assertEqual(transform2.rename_count, 0)
1009
self.assertEqual(transform2.rename_count, 2)
1011
def test_change_parent(self):
1012
"""Ensure that after we change a parent, the results are still right.
1014
Renames and parent changes on pending transforms can happen as part
1015
of conflict resolution, and are explicitly permitted by the
1018
This test ensures they work correctly with the rename-avoidance
1021
transform, root = self.get_transform()
1022
parent1 = transform.new_directory('parent1', root)
1023
child1 = transform.new_file('child1', parent1, 'contents')
1024
parent2 = transform.new_directory('parent2', root)
1025
transform.adjust_path('child1', parent2, child1)
1027
self.failIfExists(self.wt.abspath('parent1/child1'))
1028
self.failUnlessExists(self.wt.abspath('parent2/child1'))
1029
# rename limbo/new-1 => parent1, rename limbo/new-3 => parent2
1030
# no rename for child1 (counting only renames during apply)
1031
self.failUnlessEqual(2, transform.rename_count)
1033
def test_cancel_parent(self):
1034
"""Cancelling a parent doesn't cause deletion of a non-empty directory
1036
This is like the test_change_parent, except that we cancel the parent
1037
before adjusting the path. The transform must detect that the
1038
directory is non-empty, and move children to safe locations.
1040
transform, root = self.get_transform()
1041
parent1 = transform.new_directory('parent1', root)
1042
child1 = transform.new_file('child1', parent1, 'contents')
1043
child2 = transform.new_file('child2', parent1, 'contents')
1045
transform.cancel_creation(parent1)
1047
self.fail('Failed to move child1 before deleting parent1')
1048
transform.cancel_creation(child2)
1049
transform.create_directory(parent1)
1051
transform.cancel_creation(parent1)
1052
# If the transform incorrectly believes that child2 is still in
1053
# parent1's limbo directory, it will try to rename it and fail
1054
# because was already moved by the first cancel_creation.
1056
self.fail('Transform still thinks child2 is a child of parent1')
1057
parent2 = transform.new_directory('parent2', root)
1058
transform.adjust_path('child1', parent2, child1)
1060
self.failIfExists(self.wt.abspath('parent1'))
1061
self.failUnlessExists(self.wt.abspath('parent2/child1'))
1062
# rename limbo/new-3 => parent2, rename limbo/new-2 => child1
1063
self.failUnlessEqual(2, transform.rename_count)
1065
def test_adjust_and_cancel(self):
1066
"""Make sure adjust_path keeps track of limbo children properly"""
1067
transform, root = self.get_transform()
1068
parent1 = transform.new_directory('parent1', root)
1069
child1 = transform.new_file('child1', parent1, 'contents')
1070
parent2 = transform.new_directory('parent2', root)
1071
transform.adjust_path('child1', parent2, child1)
1072
transform.cancel_creation(child1)
1074
transform.cancel_creation(parent1)
1075
# if the transform thinks child1 is still in parent1's limbo
1076
# directory, it will attempt to move it and fail.
1078
self.fail('Transform still thinks child1 is a child of parent1')
1079
transform.finalize()
1081
def test_noname_contents(self):
1082
"""TreeTransform should permit deferring naming files."""
1083
transform, root = self.get_transform()
1084
parent = transform.trans_id_file_id('parent-id')
1086
transform.create_directory(parent)
1088
self.fail("Can't handle contents with no name")
1089
transform.finalize()
1091
def test_noname_contents_nested(self):
1092
"""TreeTransform should permit deferring naming files."""
1093
transform, root = self.get_transform()
1094
parent = transform.trans_id_file_id('parent-id')
1096
transform.create_directory(parent)
1098
self.fail("Can't handle contents with no name")
1099
child = transform.new_directory('child', parent)
1100
transform.adjust_path('parent', root, parent)
1102
self.failUnlessExists(self.wt.abspath('parent/child'))
1103
self.assertEqual(1, transform.rename_count)
1105
def test_reuse_name(self):
1106
"""Avoid reusing the same limbo name for different files"""
1107
transform, root = self.get_transform()
1108
parent = transform.new_directory('parent', root)
1109
child1 = transform.new_directory('child', parent)
1111
child2 = transform.new_directory('child', parent)
1113
self.fail('Tranform tried to use the same limbo name twice')
1114
transform.adjust_path('child2', parent, child2)
1116
# limbo/new-1 => parent, limbo/new-3 => parent/child2
1117
# child2 is put into top-level limbo because child1 has already
1118
# claimed the direct limbo path when child2 is created. There is no
1119
# advantage in renaming files once they're in top-level limbo, except
1121
self.assertEqual(2, transform.rename_count)
1123
def test_reuse_when_first_moved(self):
1124
"""Don't avoid direct paths when it is safe to use them"""
1125
transform, root = self.get_transform()
1126
parent = transform.new_directory('parent', root)
1127
child1 = transform.new_directory('child', parent)
1128
transform.adjust_path('child1', parent, child1)
1129
child2 = transform.new_directory('child', parent)
1131
# limbo/new-1 => parent
1132
self.assertEqual(1, transform.rename_count)
1134
def test_reuse_after_cancel(self):
1135
"""Don't avoid direct paths when it is safe to use them"""
1136
transform, root = self.get_transform()
1137
parent2 = transform.new_directory('parent2', root)
1138
child1 = transform.new_directory('child1', parent2)
1139
transform.cancel_creation(parent2)
1140
transform.create_directory(parent2)
1141
child2 = transform.new_directory('child1', parent2)
1142
transform.adjust_path('child2', parent2, child1)
1144
# limbo/new-1 => parent2, limbo/new-2 => parent2/child1
1145
self.assertEqual(2, transform.rename_count)
1147
def test_finalize_order(self):
1148
"""Finalize must be done in child-to-parent order"""
1149
transform, root = self.get_transform()
1150
parent = transform.new_directory('parent', root)
1151
child = transform.new_directory('child', parent)
1153
transform.finalize()
1155
self.fail('Tried to remove parent before child1')
1157
def test_cancel_with_cancelled_child_should_succeed(self):
1158
transform, root = self.get_transform()
1159
parent = transform.new_directory('parent', root)
1160
child = transform.new_directory('child', parent)
1161
transform.cancel_creation(child)
1162
transform.cancel_creation(parent)
1163
transform.finalize()
1165
def test_case_insensitive_clash(self):
1166
self.requireFeature(CaseInsensitiveFilesystemFeature)
1168
wt = self.make_branch_and_tree('.')
1169
tt = TreeTransform(wt) # TreeTransform obtains write lock
1171
tt.new_file('foo', tt.root, 'bar')
1172
tt.new_file('Foo', tt.root, 'spam')
1173
# Lie to tt that we've already resolved all conflicts.
1174
tt.apply(no_conflicts=True)
1178
err = self.assertRaises(errors.FileExists, tt_helper)
1179
self.assertContainsRe(str(err),
1180
"^File exists: .+/foo")
1182
def test_two_directories_clash(self):
1184
wt = self.make_branch_and_tree('.')
1185
tt = TreeTransform(wt) # TreeTransform obtains write lock
1187
foo_1 = tt.new_directory('foo', tt.root)
1188
tt.new_directory('bar', foo_1)
1189
foo_2 = tt.new_directory('foo', tt.root)
1190
tt.new_directory('baz', foo_2)
1191
# Lie to tt that we've already resolved all conflicts.
1192
tt.apply(no_conflicts=True)
1196
err = self.assertRaises(errors.FileExists, tt_helper)
1197
self.assertContainsRe(str(err),
1198
"^File exists: .+/foo")
1200
def test_two_directories_clash_finalize(self):
1202
wt = self.make_branch_and_tree('.')
1203
tt = TreeTransform(wt) # TreeTransform obtains write lock
1205
foo_1 = tt.new_directory('foo', tt.root)
1206
tt.new_directory('bar', foo_1)
1207
foo_2 = tt.new_directory('foo', tt.root)
1208
tt.new_directory('baz', foo_2)
1209
# Lie to tt that we've already resolved all conflicts.
1210
tt.apply(no_conflicts=True)
1214
err = self.assertRaises(errors.FileExists, tt_helper)
1215
self.assertContainsRe(str(err),
1216
"^File exists: .+/foo")
1218
def test_file_to_directory(self):
1219
wt = self.make_branch_and_tree('.')
1220
self.build_tree(['foo'])
1222
tt = TreeTransform(wt)
1223
self.addCleanup(tt.finalize)
1224
foo_trans_id = tt.trans_id_tree_path("foo")
1225
tt.delete_contents(foo_trans_id)
1226
tt.create_directory(foo_trans_id)
1227
bar_trans_id = tt.trans_id_tree_path("foo/bar")
1228
tt.create_file(["aa\n"], bar_trans_id)
1229
tt.version_file("bar-1", bar_trans_id)
1231
self.failUnlessExists("foo/bar")
494
1234
class TransformGroup(object):
495
def __init__(self, dirname):
1236
def __init__(self, dirname, root_id):
496
1237
self.name = dirname
497
1238
os.mkdir(dirname)
498
1239
self.wt = BzrDir.create_standalone_workingtree(dirname)
1240
self.wt.set_root_id(root_id)
499
1241
self.b = self.wt.branch
500
1242
self.tt = TreeTransform(self.wt)
501
1243
self.root = self.tt.trans_id_tree_file_id(self.wt.get_root_id())
503
1246
def conflict_text(tree, merge):
504
1247
template = '%s TREE\n%s%s\n%s%s MERGE-SOURCE\n'
505
1248
return template % ('<' * 7, tree, '=' * 7, merge, '>' * 7)
508
1251
class TestTransformMerge(TestCaseInTempDir):
509
1253
def test_text_merge(self):
510
base = TransformGroup("base")
1254
root_id = generate_ids.gen_root_id()
1255
base = TransformGroup("base", root_id)
511
1256
base.tt.new_file('a', base.root, 'a\nb\nc\nd\be\n', 'a')
512
1257
base.tt.new_file('b', base.root, 'b1', 'b')
513
1258
base.tt.new_file('c', base.root, 'c', 'c')
698
1447
a.add(['foo', 'foo/bar', 'foo/baz'])
699
1448
a.commit('initial commit')
700
1449
b = BzrDir.create_standalone_workingtree('b')
701
build_tree(a.basis_tree(), b)
1450
basis = a.basis_tree()
1452
self.addCleanup(basis.unlock)
1453
build_tree(basis, b)
702
1454
self.assertIs(os.path.isdir('b/foo'), True)
703
1455
self.assertEqual(file('b/foo/bar', 'rb').read(), "contents")
704
1456
self.assertEqual(os.readlink('b/foo/baz'), 'a/foo/bar')
1458
def test_build_with_references(self):
1459
tree = self.make_branch_and_tree('source',
1460
format='dirstate-with-subtree')
1461
subtree = self.make_branch_and_tree('source/subtree',
1462
format='dirstate-with-subtree')
1463
tree.add_reference(subtree)
1464
tree.commit('a revision')
1465
tree.branch.create_checkout('target')
1466
self.failUnlessExists('target')
1467
self.failUnlessExists('target/subtree')
1469
def test_file_conflict_handling(self):
1470
"""Ensure that when building trees, conflict handling is done"""
1471
source = self.make_branch_and_tree('source')
1472
target = self.make_branch_and_tree('target')
1473
self.build_tree(['source/file', 'target/file'])
1474
source.add('file', 'new-file')
1475
source.commit('added file')
1476
build_tree(source.basis_tree(), target)
1477
self.assertEqual([DuplicateEntry('Moved existing file to',
1478
'file.moved', 'file', None, 'new-file')],
1480
target2 = self.make_branch_and_tree('target2')
1481
target_file = file('target2/file', 'wb')
1483
source_file = file('source/file', 'rb')
1485
target_file.write(source_file.read())
1490
build_tree(source.basis_tree(), target2)
1491
self.assertEqual([], target2.conflicts())
1493
def test_symlink_conflict_handling(self):
1494
"""Ensure that when building trees, conflict handling is done"""
1495
self.requireFeature(SymlinkFeature)
1496
source = self.make_branch_and_tree('source')
1497
os.symlink('foo', 'source/symlink')
1498
source.add('symlink', 'new-symlink')
1499
source.commit('added file')
1500
target = self.make_branch_and_tree('target')
1501
os.symlink('bar', 'target/symlink')
1502
build_tree(source.basis_tree(), target)
1503
self.assertEqual([DuplicateEntry('Moved existing file to',
1504
'symlink.moved', 'symlink', None, 'new-symlink')],
1506
target = self.make_branch_and_tree('target2')
1507
os.symlink('foo', 'target2/symlink')
1508
build_tree(source.basis_tree(), target)
1509
self.assertEqual([], target.conflicts())
1511
def test_directory_conflict_handling(self):
1512
"""Ensure that when building trees, conflict handling is done"""
1513
source = self.make_branch_and_tree('source')
1514
target = self.make_branch_and_tree('target')
1515
self.build_tree(['source/dir1/', 'source/dir1/file', 'target/dir1/'])
1516
source.add(['dir1', 'dir1/file'], ['new-dir1', 'new-file'])
1517
source.commit('added file')
1518
build_tree(source.basis_tree(), target)
1519
self.assertEqual([], target.conflicts())
1520
self.failUnlessExists('target/dir1/file')
1522
# Ensure contents are merged
1523
target = self.make_branch_and_tree('target2')
1524
self.build_tree(['target2/dir1/', 'target2/dir1/file2'])
1525
build_tree(source.basis_tree(), target)
1526
self.assertEqual([], target.conflicts())
1527
self.failUnlessExists('target2/dir1/file2')
1528
self.failUnlessExists('target2/dir1/file')
1530
# Ensure new contents are suppressed for existing branches
1531
target = self.make_branch_and_tree('target3')
1532
self.make_branch('target3/dir1')
1533
self.build_tree(['target3/dir1/file2'])
1534
build_tree(source.basis_tree(), target)
1535
self.failIfExists('target3/dir1/file')
1536
self.failUnlessExists('target3/dir1/file2')
1537
self.failUnlessExists('target3/dir1.diverted/file')
1538
self.assertEqual([DuplicateEntry('Diverted to',
1539
'dir1.diverted', 'dir1', 'new-dir1', None)],
1542
target = self.make_branch_and_tree('target4')
1543
self.build_tree(['target4/dir1/'])
1544
self.make_branch('target4/dir1/file')
1545
build_tree(source.basis_tree(), target)
1546
self.failUnlessExists('target4/dir1/file')
1547
self.assertEqual('directory', file_kind('target4/dir1/file'))
1548
self.failUnlessExists('target4/dir1/file.diverted')
1549
self.assertEqual([DuplicateEntry('Diverted to',
1550
'dir1/file.diverted', 'dir1/file', 'new-file', None)],
1553
def test_mixed_conflict_handling(self):
1554
"""Ensure that when building trees, conflict handling is done"""
1555
source = self.make_branch_and_tree('source')
1556
target = self.make_branch_and_tree('target')
1557
self.build_tree(['source/name', 'target/name/'])
1558
source.add('name', 'new-name')
1559
source.commit('added file')
1560
build_tree(source.basis_tree(), target)
1561
self.assertEqual([DuplicateEntry('Moved existing file to',
1562
'name.moved', 'name', None, 'new-name')], target.conflicts())
1564
def test_raises_in_populated(self):
1565
source = self.make_branch_and_tree('source')
1566
self.build_tree(['source/name'])
1568
source.commit('added name')
1569
target = self.make_branch_and_tree('target')
1570
self.build_tree(['target/name'])
1572
self.assertRaises(errors.WorkingTreeAlreadyPopulated,
1573
build_tree, source.basis_tree(), target)
1575
def test_build_tree_rename_count(self):
1576
source = self.make_branch_and_tree('source')
1577
self.build_tree(['source/file1', 'source/dir1/'])
1578
source.add(['file1', 'dir1'])
1579
source.commit('add1')
1580
target1 = self.make_branch_and_tree('target1')
1581
transform_result = build_tree(source.basis_tree(), target1)
1582
self.assertEqual(2, transform_result.rename_count)
1584
self.build_tree(['source/dir1/file2'])
1585
source.add(['dir1/file2'])
1586
source.commit('add3')
1587
target2 = self.make_branch_and_tree('target2')
1588
transform_result = build_tree(source.basis_tree(), target2)
1589
# children of non-root directories should not be renamed
1590
self.assertEqual(2, transform_result.rename_count)
1592
def create_ab_tree(self):
1593
"""Create a committed test tree with two files"""
1594
source = self.make_branch_and_tree('source')
1595
self.build_tree_contents([('source/file1', 'A')])
1596
self.build_tree_contents([('source/file2', 'B')])
1597
source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
1598
source.commit('commit files')
1600
self.addCleanup(source.unlock)
1603
def test_build_tree_accelerator_tree(self):
1604
source = self.create_ab_tree()
1605
self.build_tree_contents([('source/file2', 'C')])
1607
real_source_get_file = source.get_file
1608
def get_file(file_id, path=None):
1609
calls.append(file_id)
1610
return real_source_get_file(file_id, path)
1611
source.get_file = get_file
1612
target = self.make_branch_and_tree('target')
1613
revision_tree = source.basis_tree()
1614
revision_tree.lock_read()
1615
self.addCleanup(revision_tree.unlock)
1616
build_tree(revision_tree, target, source)
1617
self.assertEqual(['file1-id'], calls)
1619
self.addCleanup(target.unlock)
1620
self.assertEqual([], list(target.iter_changes(revision_tree)))
1622
def test_build_tree_accelerator_tree_missing_file(self):
1623
source = self.create_ab_tree()
1624
os.unlink('source/file1')
1625
source.remove(['file2'])
1626
target = self.make_branch_and_tree('target')
1627
revision_tree = source.basis_tree()
1628
revision_tree.lock_read()
1629
self.addCleanup(revision_tree.unlock)
1630
build_tree(revision_tree, target, source)
1632
self.addCleanup(target.unlock)
1633
self.assertEqual([], list(target.iter_changes(revision_tree)))
1635
def test_build_tree_accelerator_wrong_kind(self):
1636
self.requireFeature(SymlinkFeature)
1637
source = self.make_branch_and_tree('source')
1638
self.build_tree_contents([('source/file1', '')])
1639
self.build_tree_contents([('source/file2', '')])
1640
source.add(['file1', 'file2'], ['file1-id', 'file2-id'])
1641
source.commit('commit files')
1642
os.unlink('source/file2')
1643
self.build_tree_contents([('source/file2/', 'C')])
1644
os.unlink('source/file1')
1645
os.symlink('file2', 'source/file1')
1647
real_source_get_file = source.get_file
1648
def get_file(file_id, path=None):
1649
calls.append(file_id)
1650
return real_source_get_file(file_id, path)
1651
source.get_file = get_file
1652
target = self.make_branch_and_tree('target')
1653
revision_tree = source.basis_tree()
1654
revision_tree.lock_read()
1655
self.addCleanup(revision_tree.unlock)
1656
build_tree(revision_tree, target, source)
1657
self.assertEqual([], calls)
1659
self.addCleanup(target.unlock)
1660
self.assertEqual([], list(target.iter_changes(revision_tree)))
1662
def test_build_tree_hardlink(self):
1663
self.requireFeature(HardlinkFeature)
1664
source = self.create_ab_tree()
1665
target = self.make_branch_and_tree('target')
1666
revision_tree = source.basis_tree()
1667
revision_tree.lock_read()
1668
self.addCleanup(revision_tree.unlock)
1669
build_tree(revision_tree, target, source, hardlink=True)
1671
self.addCleanup(target.unlock)
1672
self.assertEqual([], list(target.iter_changes(revision_tree)))
1673
source_stat = os.stat('source/file1')
1674
target_stat = os.stat('target/file1')
1675
self.assertEqual(source_stat, target_stat)
1677
# Explicitly disallowing hardlinks should prevent them.
1678
target2 = self.make_branch_and_tree('target2')
1679
build_tree(revision_tree, target2, source, hardlink=False)
1681
self.addCleanup(target2.unlock)
1682
self.assertEqual([], list(target2.iter_changes(revision_tree)))
1683
source_stat = os.stat('source/file1')
1684
target2_stat = os.stat('target2/file1')
1685
self.assertNotEqual(source_stat, target2_stat)
1687
def test_build_tree_accelerator_tree_moved(self):
1688
source = self.make_branch_and_tree('source')
1689
self.build_tree_contents([('source/file1', 'A')])
1690
source.add(['file1'], ['file1-id'])
1691
source.commit('commit files')
1692
source.rename_one('file1', 'file2')
1694
self.addCleanup(source.unlock)
1695
target = self.make_branch_and_tree('target')
1696
revision_tree = source.basis_tree()
1697
revision_tree.lock_read()
1698
self.addCleanup(revision_tree.unlock)
1699
build_tree(revision_tree, target, source)
1701
self.addCleanup(target.unlock)
1702
self.assertEqual([], list(target.iter_changes(revision_tree)))
1704
def test_build_tree_hardlinks_preserve_execute(self):
1705
self.requireFeature(HardlinkFeature)
1706
source = self.create_ab_tree()
1707
tt = TreeTransform(source)
1708
trans_id = tt.trans_id_tree_file_id('file1-id')
1709
tt.set_executability(True, trans_id)
1711
self.assertTrue(source.is_executable('file1-id'))
1712
target = self.make_branch_and_tree('target')
1713
revision_tree = source.basis_tree()
1714
revision_tree.lock_read()
1715
self.addCleanup(revision_tree.unlock)
1716
build_tree(revision_tree, target, source, hardlink=True)
1718
self.addCleanup(target.unlock)
1719
self.assertEqual([], list(target.iter_changes(revision_tree)))
1720
self.assertTrue(source.is_executable('file1-id'))
1722
def test_case_insensitive_build_tree_inventory(self):
1723
source = self.make_branch_and_tree('source')
1724
self.build_tree(['source/file', 'source/FILE'])
1725
source.add(['file', 'FILE'], ['lower-id', 'upper-id'])
1726
source.commit('added files')
1727
# Don't try this at home, kids!
1728
# Force the tree to report that it is case insensitive
1729
target = self.make_branch_and_tree('target')
1730
target.case_sensitive = False
1731
build_tree(source.basis_tree(), target, source, delta_from_tree=True)
1732
self.assertEqual('file.moved', target.id2path('lower-id'))
1733
self.assertEqual('FILE', target.id2path('upper-id'))
706
1736
class MockTransform(object):
708
1738
def has_named_child(self, by_parent, parent_id, name):
732
1764
self.assertEqual(name, 'name.~1~')
733
1765
name = get_backup_name(MockEntry(), {'a':['1', '2', '3']}, 'a', tt)
734
1766
self.assertEqual(name, 'name.~4~')
1769
class TestFileMover(tests.TestCaseWithTransport):
1771
def test_file_mover(self):
1772
self.build_tree(['a/', 'a/b', 'c/', 'c/d'])
1773
mover = _FileMover()
1774
mover.rename('a', 'q')
1775
self.failUnlessExists('q')
1776
self.failIfExists('a')
1777
self.failUnlessExists('q/b')
1778
self.failUnlessExists('c')
1779
self.failUnlessExists('c/d')
1781
def test_pre_delete_rollback(self):
1782
self.build_tree(['a/'])
1783
mover = _FileMover()
1784
mover.pre_delete('a', 'q')
1785
self.failUnlessExists('q')
1786
self.failIfExists('a')
1788
self.failIfExists('q')
1789
self.failUnlessExists('a')
1791
def test_apply_deletions(self):
1792
self.build_tree(['a/', 'b/'])
1793
mover = _FileMover()
1794
mover.pre_delete('a', 'q')
1795
mover.pre_delete('b', 'r')
1796
self.failUnlessExists('q')
1797
self.failUnlessExists('r')
1798
self.failIfExists('a')
1799
self.failIfExists('b')
1800
mover.apply_deletions()
1801
self.failIfExists('q')
1802
self.failIfExists('r')
1803
self.failIfExists('a')
1804
self.failIfExists('b')
1806
def test_file_mover_rollback(self):
1807
self.build_tree(['a/', 'a/b', 'c/', 'c/d/', 'c/e/'])
1808
mover = _FileMover()
1809
mover.rename('c/d', 'c/f')
1810
mover.rename('c/e', 'c/d')
1812
mover.rename('a', 'c')
1813
except errors.FileExists, e:
1815
self.failUnlessExists('a')
1816
self.failUnlessExists('c/d')
1819
class Bogus(Exception):
1823
class TestTransformRollback(tests.TestCaseWithTransport):
1825
class ExceptionFileMover(_FileMover):
1827
def __init__(self, bad_source=None, bad_target=None):
1828
_FileMover.__init__(self)
1829
self.bad_source = bad_source
1830
self.bad_target = bad_target
1832
def rename(self, source, target):
1833
if (self.bad_source is not None and
1834
source.endswith(self.bad_source)):
1836
elif (self.bad_target is not None and
1837
target.endswith(self.bad_target)):
1840
_FileMover.rename(self, source, target)
1842
def test_rollback_rename(self):
1843
tree = self.make_branch_and_tree('.')
1844
self.build_tree(['a/', 'a/b'])
1845
tt = TreeTransform(tree)
1846
self.addCleanup(tt.finalize)
1847
a_id = tt.trans_id_tree_path('a')
1848
tt.adjust_path('c', tt.root, a_id)
1849
tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
1850
self.assertRaises(Bogus, tt.apply,
1851
_mover=self.ExceptionFileMover(bad_source='a'))
1852
self.failUnlessExists('a')
1853
self.failUnlessExists('a/b')
1855
self.failUnlessExists('c')
1856
self.failUnlessExists('c/d')
1858
def test_rollback_rename_into_place(self):
1859
tree = self.make_branch_and_tree('.')
1860
self.build_tree(['a/', 'a/b'])
1861
tt = TreeTransform(tree)
1862
self.addCleanup(tt.finalize)
1863
a_id = tt.trans_id_tree_path('a')
1864
tt.adjust_path('c', tt.root, a_id)
1865
tt.adjust_path('d', a_id, tt.trans_id_tree_path('a/b'))
1866
self.assertRaises(Bogus, tt.apply,
1867
_mover=self.ExceptionFileMover(bad_target='c/d'))
1868
self.failUnlessExists('a')
1869
self.failUnlessExists('a/b')
1871
self.failUnlessExists('c')
1872
self.failUnlessExists('c/d')
1874
def test_rollback_deletion(self):
1875
tree = self.make_branch_and_tree('.')
1876
self.build_tree(['a/', 'a/b'])
1877
tt = TreeTransform(tree)
1878
self.addCleanup(tt.finalize)
1879
a_id = tt.trans_id_tree_path('a')
1880
tt.delete_contents(a_id)
1881
tt.adjust_path('d', tt.root, tt.trans_id_tree_path('a/b'))
1882
self.assertRaises(Bogus, tt.apply,
1883
_mover=self.ExceptionFileMover(bad_target='d'))
1884
self.failUnlessExists('a')
1885
self.failUnlessExists('a/b')
1887
def test_resolve_no_parent(self):
1888
wt = self.make_branch_and_tree('.')
1889
tt = TreeTransform(wt)
1890
self.addCleanup(tt.finalize)
1891
parent = tt.trans_id_file_id('parent-id')
1892
tt.new_file('file', parent, 'Contents')
1893
resolve_conflicts(tt)
1896
class TestTransformPreview(tests.TestCaseWithTransport):
1898
def create_tree(self):
1899
tree = self.make_branch_and_tree('.')
1900
self.build_tree_contents([('a', 'content 1')])
1901
tree.add('a', 'a-id')
1902
tree.commit('rev1', rev_id='rev1')
1903
return tree.branch.repository.revision_tree('rev1')
1905
def get_empty_preview(self):
1906
repository = self.make_repository('repo')
1907
tree = repository.revision_tree(_mod_revision.NULL_REVISION)
1908
preview = TransformPreview(tree)
1909
self.addCleanup(preview.finalize)
1912
def test_transform_preview(self):
1913
revision_tree = self.create_tree()
1914
preview = TransformPreview(revision_tree)
1915
self.addCleanup(preview.finalize)
1917
def test_transform_preview_tree(self):
1918
revision_tree = self.create_tree()
1919
preview = TransformPreview(revision_tree)
1920
self.addCleanup(preview.finalize)
1921
preview.get_preview_tree()
1923
def test_transform_new_file(self):
1924
revision_tree = self.create_tree()
1925
preview = TransformPreview(revision_tree)
1926
self.addCleanup(preview.finalize)
1927
preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
1928
preview_tree = preview.get_preview_tree()
1929
self.assertEqual(preview_tree.kind('file2-id'), 'file')
1931
preview_tree.get_file('file2-id').read(), 'content B\n')
1933
def test_diff_preview_tree(self):
1934
revision_tree = self.create_tree()
1935
preview = TransformPreview(revision_tree)
1936
self.addCleanup(preview.finalize)
1937
preview.new_file('file2', preview.root, 'content B\n', 'file2-id')
1938
preview_tree = preview.get_preview_tree()
1940
show_diff_trees(revision_tree, preview_tree, out)
1941
lines = out.getvalue().splitlines()
1942
self.assertEqual(lines[0], "=== added file 'file2'")
1943
# 3 lines of diff administrivia
1944
self.assertEqual(lines[4], "+content B")
1946
def test_transform_conflicts(self):
1947
revision_tree = self.create_tree()
1948
preview = TransformPreview(revision_tree)
1949
self.addCleanup(preview.finalize)
1950
preview.new_file('a', preview.root, 'content 2')
1951
resolve_conflicts(preview)
1952
trans_id = preview.trans_id_file_id('a-id')
1953
self.assertEqual('a.moved', preview.final_name(trans_id))
1955
def get_tree_and_preview_tree(self):
1956
revision_tree = self.create_tree()
1957
preview = TransformPreview(revision_tree)
1958
self.addCleanup(preview.finalize)
1959
a_trans_id = preview.trans_id_file_id('a-id')
1960
preview.delete_contents(a_trans_id)
1961
preview.create_file('b content', a_trans_id)
1962
preview_tree = preview.get_preview_tree()
1963
return revision_tree, preview_tree
1965
def test_iter_changes(self):
1966
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1967
root = revision_tree.inventory.root.file_id
1968
self.assertEqual([('a-id', ('a', 'a'), True, (True, True),
1969
(root, root), ('a', 'a'), ('file', 'file'),
1971
list(preview_tree.iter_changes(revision_tree)))
1973
def test_wrong_tree_value_error(self):
1974
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1975
e = self.assertRaises(ValueError, preview_tree.iter_changes,
1977
self.assertEqual('from_tree must be transform source tree.', str(e))
1979
def test_include_unchanged_value_error(self):
1980
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1981
e = self.assertRaises(ValueError, preview_tree.iter_changes,
1982
revision_tree, include_unchanged=True)
1983
self.assertEqual('include_unchanged is not supported', str(e))
1985
def test_specific_files(self):
1986
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1987
e = self.assertRaises(ValueError, preview_tree.iter_changes,
1988
revision_tree, specific_files=['pete'])
1989
self.assertEqual('specific_files is not supported', str(e))
1991
def test_want_unversioned_value_error(self):
1992
revision_tree, preview_tree = self.get_tree_and_preview_tree()
1993
e = self.assertRaises(ValueError, preview_tree.iter_changes,
1994
revision_tree, want_unversioned=True)
1995
self.assertEqual('want_unversioned is not supported', str(e))
1997
def test_ignore_extra_trees_no_specific_files(self):
1998
# extra_trees is harmless without specific_files, so we'll silently
1999
# accept it, even though we won't use it.
2000
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2001
preview_tree.iter_changes(revision_tree, extra_trees=[preview_tree])
2003
def test_ignore_require_versioned_no_specific_files(self):
2004
# require_versioned is meaningless without specific_files.
2005
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2006
preview_tree.iter_changes(revision_tree, require_versioned=False)
2008
def test_ignore_pb(self):
2009
# pb could be supported, but TT.iter_changes doesn't support it.
2010
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2011
preview_tree.iter_changes(revision_tree, pb=progress.DummyProgress())
2013
def test_kind(self):
2014
revision_tree = self.create_tree()
2015
preview = TransformPreview(revision_tree)
2016
self.addCleanup(preview.finalize)
2017
preview.new_file('file', preview.root, 'contents', 'file-id')
2018
preview.new_directory('directory', preview.root, 'dir-id')
2019
preview_tree = preview.get_preview_tree()
2020
self.assertEqual('file', preview_tree.kind('file-id'))
2021
self.assertEqual('directory', preview_tree.kind('dir-id'))
2023
def test_get_file_mtime(self):
2024
preview = self.get_empty_preview()
2025
file_trans_id = preview.new_file('file', preview.root, 'contents',
2027
limbo_path = preview._limbo_name(file_trans_id)
2028
preview_tree = preview.get_preview_tree()
2029
self.assertEqual(os.stat(limbo_path).st_mtime,
2030
preview_tree.get_file_mtime('file-id'))
2032
def test_get_file(self):
2033
preview = self.get_empty_preview()
2034
preview.new_file('file', preview.root, 'contents', 'file-id')
2035
preview_tree = preview.get_preview_tree()
2036
tree_file = preview_tree.get_file('file-id')
2038
self.assertEqual('contents', tree_file.read())
2042
def test_get_symlink_target(self):
2043
self.requireFeature(SymlinkFeature)
2044
preview = self.get_empty_preview()
2045
preview.new_symlink('symlink', preview.root, 'target', 'symlink-id')
2046
preview_tree = preview.get_preview_tree()
2047
self.assertEqual('target',
2048
preview_tree.get_symlink_target('symlink-id'))
2050
def test_all_file_ids(self):
2051
tree = self.make_branch_and_tree('tree')
2052
self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2053
tree.add(['a', 'b', 'c'], ['a-id', 'b-id', 'c-id'])
2054
preview = TransformPreview(tree)
2055
self.addCleanup(preview.finalize)
2056
preview.unversion_file(preview.trans_id_file_id('b-id'))
2057
c_trans_id = preview.trans_id_file_id('c-id')
2058
preview.unversion_file(c_trans_id)
2059
preview.version_file('c-id', c_trans_id)
2060
preview_tree = preview.get_preview_tree()
2061
self.assertEqual(set(['a-id', 'c-id', tree.get_root_id()]),
2062
preview_tree.all_file_ids())
2064
def test_path2id_deleted_unchanged(self):
2065
tree = self.make_branch_and_tree('tree')
2066
self.build_tree(['tree/unchanged', 'tree/deleted'])
2067
tree.add(['unchanged', 'deleted'], ['unchanged-id', 'deleted-id'])
2068
preview = TransformPreview(tree)
2069
self.addCleanup(preview.finalize)
2070
preview.unversion_file(preview.trans_id_file_id('deleted-id'))
2071
preview_tree = preview.get_preview_tree()
2072
self.assertEqual('unchanged-id', preview_tree.path2id('unchanged'))
2073
self.assertIs(None, preview_tree.path2id('deleted'))
2075
def test_path2id_created(self):
2076
tree = self.make_branch_and_tree('tree')
2077
self.build_tree(['tree/unchanged'])
2078
tree.add(['unchanged'], ['unchanged-id'])
2079
preview = TransformPreview(tree)
2080
self.addCleanup(preview.finalize)
2081
preview.new_file('new', preview.trans_id_file_id('unchanged-id'),
2082
'contents', 'new-id')
2083
preview_tree = preview.get_preview_tree()
2084
self.assertEqual('new-id', preview_tree.path2id('unchanged/new'))
2086
def test_path2id_moved(self):
2087
tree = self.make_branch_and_tree('tree')
2088
self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
2089
tree.add(['old_parent', 'old_parent/child'],
2090
['old_parent-id', 'child-id'])
2091
preview = TransformPreview(tree)
2092
self.addCleanup(preview.finalize)
2093
new_parent = preview.new_directory('new_parent', preview.root,
2095
preview.adjust_path('child', new_parent,
2096
preview.trans_id_file_id('child-id'))
2097
preview_tree = preview.get_preview_tree()
2098
self.assertIs(None, preview_tree.path2id('old_parent/child'))
2099
self.assertEqual('child-id', preview_tree.path2id('new_parent/child'))
2101
def test_path2id_renamed_parent(self):
2102
tree = self.make_branch_and_tree('tree')
2103
self.build_tree(['tree/old_name/', 'tree/old_name/child'])
2104
tree.add(['old_name', 'old_name/child'],
2105
['parent-id', 'child-id'])
2106
preview = TransformPreview(tree)
2107
self.addCleanup(preview.finalize)
2108
preview.adjust_path('new_name', preview.root,
2109
preview.trans_id_file_id('parent-id'))
2110
preview_tree = preview.get_preview_tree()
2111
self.assertIs(None, preview_tree.path2id('old_name/child'))
2112
self.assertEqual('child-id', preview_tree.path2id('new_name/child'))
2114
def assertMatchingIterEntries(self, tt, specific_file_ids=None):
2115
preview_tree = tt.get_preview_tree()
2116
preview_result = list(preview_tree.iter_entries_by_dir(
2120
actual_result = list(tree.iter_entries_by_dir(specific_file_ids))
2121
self.assertEqual(actual_result, preview_result)
2123
def test_iter_entries_by_dir_new(self):
2124
tree = self.make_branch_and_tree('tree')
2125
tt = TreeTransform(tree)
2126
tt.new_file('new', tt.root, 'contents', 'new-id')
2127
self.assertMatchingIterEntries(tt)
2129
def test_iter_entries_by_dir_deleted(self):
2130
tree = self.make_branch_and_tree('tree')
2131
self.build_tree(['tree/deleted'])
2132
tree.add('deleted', 'deleted-id')
2133
tt = TreeTransform(tree)
2134
tt.delete_contents(tt.trans_id_file_id('deleted-id'))
2135
self.assertMatchingIterEntries(tt)
2137
def test_iter_entries_by_dir_unversioned(self):
2138
tree = self.make_branch_and_tree('tree')
2139
self.build_tree(['tree/removed'])
2140
tree.add('removed', 'removed-id')
2141
tt = TreeTransform(tree)
2142
tt.unversion_file(tt.trans_id_file_id('removed-id'))
2143
self.assertMatchingIterEntries(tt)
2145
def test_iter_entries_by_dir_moved(self):
2146
tree = self.make_branch_and_tree('tree')
2147
self.build_tree(['tree/moved', 'tree/new_parent/'])
2148
tree.add(['moved', 'new_parent'], ['moved-id', 'new_parent-id'])
2149
tt = TreeTransform(tree)
2150
tt.adjust_path('moved', tt.trans_id_file_id('new_parent-id'),
2151
tt.trans_id_file_id('moved-id'))
2152
self.assertMatchingIterEntries(tt)
2154
def test_iter_entries_by_dir_specific_file_ids(self):
2155
tree = self.make_branch_and_tree('tree')
2156
tree.set_root_id('tree-root-id')
2157
self.build_tree(['tree/parent/', 'tree/parent/child'])
2158
tree.add(['parent', 'parent/child'], ['parent-id', 'child-id'])
2159
tt = TreeTransform(tree)
2160
self.assertMatchingIterEntries(tt, ['tree-root-id', 'child-id'])
2162
def test_symlink_content_summary(self):
2163
self.requireFeature(SymlinkFeature)
2164
preview = self.get_empty_preview()
2165
preview.new_symlink('path', preview.root, 'target', 'path-id')
2166
summary = preview.get_preview_tree().path_content_summary('path')
2167
self.assertEqual(('symlink', None, None, 'target'), summary)
2169
def test_missing_content_summary(self):
2170
preview = self.get_empty_preview()
2171
summary = preview.get_preview_tree().path_content_summary('path')
2172
self.assertEqual(('missing', None, None, None), summary)
2174
def test_deleted_content_summary(self):
2175
tree = self.make_branch_and_tree('tree')
2176
self.build_tree(['tree/path/'])
2178
preview = TransformPreview(tree)
2179
self.addCleanup(preview.finalize)
2180
preview.delete_contents(preview.trans_id_tree_path('path'))
2181
summary = preview.get_preview_tree().path_content_summary('path')
2182
self.assertEqual(('missing', None, None, None), summary)
2184
def test_file_content_summary_executable(self):
2185
if not osutils.supports_executable():
2186
raise TestNotApplicable()
2187
preview = self.get_empty_preview()
2188
path_id = preview.new_file('path', preview.root, 'contents', 'path-id')
2189
preview.set_executability(True, path_id)
2190
summary = preview.get_preview_tree().path_content_summary('path')
2191
self.assertEqual(4, len(summary))
2192
self.assertEqual('file', summary[0])
2193
# size must be known
2194
self.assertEqual(len('contents'), summary[1])
2196
self.assertEqual(True, summary[2])
2197
# will not have hash (not cheap to determine)
2198
self.assertIs(None, summary[3])
2200
def test_change_executability(self):
2201
if not osutils.supports_executable():
2202
raise TestNotApplicable()
2203
tree = self.make_branch_and_tree('tree')
2204
self.build_tree(['tree/path'])
2206
preview = TransformPreview(tree)
2207
self.addCleanup(preview.finalize)
2208
path_id = preview.trans_id_tree_path('path')
2209
preview.set_executability(True, path_id)
2210
summary = preview.get_preview_tree().path_content_summary('path')
2211
self.assertEqual(True, summary[2])
2213
def test_file_content_summary_non_exec(self):
2214
preview = self.get_empty_preview()
2215
preview.new_file('path', preview.root, 'contents', 'path-id')
2216
summary = preview.get_preview_tree().path_content_summary('path')
2217
self.assertEqual(4, len(summary))
2218
self.assertEqual('file', summary[0])
2219
# size must be known
2220
self.assertEqual(len('contents'), summary[1])
2222
if osutils.supports_executable():
2223
self.assertEqual(False, summary[2])
2225
self.assertEqual(None, summary[2])
2226
# will not have hash (not cheap to determine)
2227
self.assertIs(None, summary[3])
2229
def test_dir_content_summary(self):
2230
preview = self.get_empty_preview()
2231
preview.new_directory('path', preview.root, 'path-id')
2232
summary = preview.get_preview_tree().path_content_summary('path')
2233
self.assertEqual(('directory', None, None, None), summary)
2235
def test_tree_content_summary(self):
2236
preview = self.get_empty_preview()
2237
path = preview.new_directory('path', preview.root, 'path-id')
2238
preview.set_tree_reference('rev-1', path)
2239
summary = preview.get_preview_tree().path_content_summary('path')
2240
self.assertEqual(4, len(summary))
2241
self.assertEqual('tree-reference', summary[0])
2243
def test_annotate(self):
2244
tree = self.make_branch_and_tree('tree')
2245
self.build_tree_contents([('tree/file', 'a\n')])
2246
tree.add('file', 'file-id')
2247
tree.commit('a', rev_id='one')
2248
self.build_tree_contents([('tree/file', 'a\nb\n')])
2249
preview = TransformPreview(tree)
2250
self.addCleanup(preview.finalize)
2251
file_trans_id = preview.trans_id_file_id('file-id')
2252
preview.delete_contents(file_trans_id)
2253
preview.create_file('a\nb\nc\n', file_trans_id)
2254
preview_tree = preview.get_preview_tree()
2260
annotation = preview_tree.annotate_iter('file-id', 'me:')
2261
self.assertEqual(expected, annotation)
2263
def test_annotate_missing(self):
2264
preview = self.get_empty_preview()
2265
preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2266
preview_tree = preview.get_preview_tree()
2272
annotation = preview_tree.annotate_iter('file-id', 'me:')
2273
self.assertEqual(expected, annotation)
2275
def test_annotate_rename(self):
2276
tree = self.make_branch_and_tree('tree')
2277
self.build_tree_contents([('tree/file', 'a\n')])
2278
tree.add('file', 'file-id')
2279
tree.commit('a', rev_id='one')
2280
preview = TransformPreview(tree)
2281
self.addCleanup(preview.finalize)
2282
file_trans_id = preview.trans_id_file_id('file-id')
2283
preview.adjust_path('newname', preview.root, file_trans_id)
2284
preview_tree = preview.get_preview_tree()
2288
annotation = preview_tree.annotate_iter('file-id', 'me:')
2289
self.assertEqual(expected, annotation)
2291
def test_annotate_deleted(self):
2292
tree = self.make_branch_and_tree('tree')
2293
self.build_tree_contents([('tree/file', 'a\n')])
2294
tree.add('file', 'file-id')
2295
tree.commit('a', rev_id='one')
2296
self.build_tree_contents([('tree/file', 'a\nb\n')])
2297
preview = TransformPreview(tree)
2298
self.addCleanup(preview.finalize)
2299
file_trans_id = preview.trans_id_file_id('file-id')
2300
preview.delete_contents(file_trans_id)
2301
preview_tree = preview.get_preview_tree()
2302
annotation = preview_tree.annotate_iter('file-id', 'me:')
2303
self.assertIs(None, annotation)
2305
def test_stored_kind(self):
2306
preview = self.get_empty_preview()
2307
preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2308
preview_tree = preview.get_preview_tree()
2309
self.assertEqual('file', preview_tree.stored_kind('file-id'))
2311
def test_is_executable(self):
2312
preview = self.get_empty_preview()
2313
preview.new_file('file', preview.root, 'a\nb\nc\n', 'file-id')
2314
preview.set_executability(True, preview.trans_id_file_id('file-id'))
2315
preview_tree = preview.get_preview_tree()
2316
self.assertEqual(True, preview_tree.is_executable('file-id'))
2318
def test_get_set_parent_ids(self):
2319
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2320
self.assertEqual([], preview_tree.get_parent_ids())
2321
preview_tree.set_parent_ids(['rev-1'])
2322
self.assertEqual(['rev-1'], preview_tree.get_parent_ids())
2324
def test_plan_file_merge(self):
2325
work_a = self.make_branch_and_tree('wta')
2326
self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2327
work_a.add('file', 'file-id')
2328
base_id = work_a.commit('base version')
2329
tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2330
preview = TransformPreview(work_a)
2331
self.addCleanup(preview.finalize)
2332
trans_id = preview.trans_id_file_id('file-id')
2333
preview.delete_contents(trans_id)
2334
preview.create_file('b\nc\nd\ne\n', trans_id)
2335
self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2336
tree_a = preview.get_preview_tree()
2337
tree_a.set_parent_ids([base_id])
2339
('killed-a', 'a\n'),
2340
('killed-b', 'b\n'),
2341
('unchanged', 'c\n'),
2342
('unchanged', 'd\n'),
2345
], list(tree_a.plan_file_merge('file-id', tree_b)))
2347
def test_plan_file_merge_revision_tree(self):
2348
work_a = self.make_branch_and_tree('wta')
2349
self.build_tree_contents([('wta/file', 'a\nb\nc\nd\n')])
2350
work_a.add('file', 'file-id')
2351
base_id = work_a.commit('base version')
2352
tree_b = work_a.bzrdir.sprout('wtb').open_workingtree()
2353
preview = TransformPreview(work_a.basis_tree())
2354
self.addCleanup(preview.finalize)
2355
trans_id = preview.trans_id_file_id('file-id')
2356
preview.delete_contents(trans_id)
2357
preview.create_file('b\nc\nd\ne\n', trans_id)
2358
self.build_tree_contents([('wtb/file', 'a\nc\nd\nf\n')])
2359
tree_a = preview.get_preview_tree()
2360
tree_a.set_parent_ids([base_id])
2362
('killed-a', 'a\n'),
2363
('killed-b', 'b\n'),
2364
('unchanged', 'c\n'),
2365
('unchanged', 'd\n'),
2368
], list(tree_a.plan_file_merge('file-id', tree_b)))