99
100
self.wt = self.make_branch_and_tree('.', format='development-subtree')
102
def get_transform(self):
103
104
transform = TreeTransform(self.wt)
104
105
self.addCleanup(transform.finalize)
105
106
return transform, transform.root
107
def get_transform_for_sha1_test(self):
108
trans, root = self.get_transform()
108
def transform_for_sha1_test(self):
109
trans, root = self.transform()
109
110
self.wt.lock_tree_write()
110
111
self.addCleanup(self.wt.unlock)
111
112
contents = [b'just some content\n']
115
116
return trans, root, contents, sha1
117
118
def test_existing_limbo(self):
118
transform, root = self.get_transform()
119
transform, root = self.transform()
119
120
limbo_name = transform._limbodir
120
121
deletion_path = transform._deletiondir
121
122
os.mkdir(pathjoin(limbo_name, 'hehe'))
122
123
self.assertRaises(ImmortalLimbo, transform.apply)
123
124
self.assertRaises(LockError, self.wt.unlock)
124
self.assertRaises(ExistingLimbo, self.get_transform)
125
self.assertRaises(ExistingLimbo, self.transform)
125
126
self.assertRaises(LockError, self.wt.unlock)
126
127
os.rmdir(pathjoin(limbo_name, 'hehe'))
127
128
os.rmdir(limbo_name)
128
129
os.rmdir(deletion_path)
129
transform, root = self.get_transform()
130
transform, root = self.transform()
130
131
transform.apply()
132
133
def test_existing_pending_deletion(self):
133
transform, root = self.get_transform()
134
transform, root = self.transform()
134
135
deletion_path = self._limbodir = urlutils.local_path_from_url(
135
136
transform._tree._transport.abspath('pending-deletion'))
136
137
os.mkdir(pathjoin(deletion_path, 'blocking-directory'))
137
138
self.assertRaises(ImmortalPendingDeletion, transform.apply)
138
139
self.assertRaises(LockError, self.wt.unlock)
139
self.assertRaises(ExistingPendingDeletion, self.get_transform)
140
self.assertRaises(ExistingPendingDeletion, self.transform)
141
142
def test_build(self):
142
transform, root = self.get_transform()
143
transform, root = self.transform()
143
144
self.wt.lock_tree_write()
144
145
self.addCleanup(self.wt.unlock)
145
146
self.assertIs(transform.get_tree_parent(root), ROOT_PARENT)
184
185
transform.finalize()
186
187
def test_apply_informs_tree_of_observed_sha1(self):
187
trans, root, contents, sha1 = self.get_transform_for_sha1_test()
188
trans, root, contents, sha1 = self.transform_for_sha1_test()
188
189
trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
201
202
def test_create_file_caches_sha1(self):
202
trans, root, contents, sha1 = self.get_transform_for_sha1_test()
203
trans, root, contents, sha1 = self.transform_for_sha1_test()
203
204
trans_id = trans.create_path('file1', root)
204
205
trans.create_file(contents, trans_id, sha1=sha1)
205
206
st_val = osutils.lstat(trans._limbo_name(trans_id))
208
209
self.assertEqualStat(o_st_val, st_val)
210
211
def test__apply_insertions_updates_sha1(self):
211
trans, root, contents, sha1 = self.get_transform_for_sha1_test()
212
trans, root, contents, sha1 = self.transform_for_sha1_test()
212
213
trans_id = trans.create_path('file1', root)
213
214
trans.create_file(contents, trans_id, sha1=sha1)
214
215
st_val = osutils.lstat(trans._limbo_name(trans_id))
229
230
self.assertNotEqual(st_val.st_mtime, new_st_val.st_mtime)
231
232
def test_new_file_caches_sha1(self):
232
trans, root, contents, sha1 = self.get_transform_for_sha1_test()
233
trans, root, contents, sha1 = self.transform_for_sha1_test()
233
234
trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
235
236
st_val = osutils.lstat(trans._limbo_name(trans_id))
238
239
self.assertEqualStat(o_st_val, st_val)
240
241
def test_cancel_creation_removes_observed_sha1(self):
241
trans, root, contents, sha1 = self.get_transform_for_sha1_test()
242
trans, root, contents, sha1 = self.transform_for_sha1_test()
242
243
trans_id = trans.new_file('file1', root, contents, file_id=b'file1-id',
244
245
self.assertTrue(trans_id in trans._observed_sha1s)
246
247
self.assertFalse(trans_id in trans._observed_sha1s)
248
249
def test_create_files_same_timestamp(self):
249
transform, root = self.get_transform()
250
transform, root = self.transform()
250
251
self.wt.lock_tree_write()
251
252
self.addCleanup(self.wt.unlock)
252
253
# Roll back the clock, so that we know everything is being set to the
270
271
self.assertEqual(st1.st_mtime, st2.st_mtime)
272
273
def test_change_root_id(self):
273
transform, root = self.get_transform()
274
transform, root = self.transform()
274
275
self.assertNotEqual(b'new-root-id', self.wt.path2id(''))
275
276
transform.new_directory('', ROOT_PARENT, b'new-root-id')
276
277
transform.delete_contents(root)
280
281
self.assertEqual(b'new-root-id', self.wt.path2id(''))
282
283
def test_change_root_id_add_files(self):
283
transform, root = self.get_transform()
284
transform, root = self.transform()
284
285
self.assertNotEqual(b'new-root-id', self.wt.path2id(''))
285
286
new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
286
287
transform.new_file('file', new_trans_id, [b'new-contents\n'],
294
295
self.assertFileEqual(b'new-contents\n', self.wt.abspath('file'))
296
297
def test_add_two_roots(self):
297
transform, root = self.get_transform()
298
transform, root = self.transform()
298
299
transform.new_directory('', ROOT_PARENT, b'new-root-id')
299
300
transform.new_directory('', ROOT_PARENT, b'alt-root-id')
300
301
self.assertRaises(ValueError, transform.fixup_new_roots)
302
303
def test_retain_existing_root(self):
303
tt, root = self.get_transform()
304
tt, root = self.transform()
305
306
tt.new_directory('', ROOT_PARENT, b'new-root-id')
306
307
tt.fixup_new_roots()
307
308
self.assertNotEqual(b'new-root-id', tt.final_file_id(tt.root))
309
310
def test_retain_existing_root_added_file(self):
310
tt, root = self.get_transform()
311
tt, root = self.transform()
311
312
new_trans_id = tt.new_directory('', ROOT_PARENT, b'new-root-id')
312
313
child = tt.new_directory('child', new_trans_id, b'child-id')
313
314
tt.fixup_new_roots()
314
315
self.assertEqual(tt.root, tt.final_parent(child))
316
317
def test_add_unversioned_root(self):
317
transform, root = self.get_transform()
318
transform, root = self.transform()
318
319
transform.new_directory('', ROOT_PARENT, None)
319
320
transform.delete_contents(transform.root)
320
321
transform.fixup_new_roots()
321
322
self.assertNotIn(transform.root, transform._new_id)
323
324
def test_remove_root_fixup(self):
324
transform, root = self.get_transform()
325
transform, root = self.transform()
325
326
old_root_id = self.wt.path2id('')
326
327
self.assertNotEqual(b'new-root-id', old_root_id)
327
328
transform.delete_contents(root)
330
331
transform.apply()
331
332
self.assertEqual(old_root_id, self.wt.path2id(''))
333
transform, root = self.get_transform()
334
transform, root = self.transform()
334
335
transform.new_directory('', ROOT_PARENT, b'new-root-id')
335
336
transform.new_directory('', ROOT_PARENT, b'alt-root-id')
336
337
self.assertRaises(ValueError, transform.fixup_new_roots)
338
339
def test_fixup_new_roots_permits_empty_tree(self):
339
transform, root = self.get_transform()
340
transform, root = self.transform()
340
341
transform.delete_contents(root)
341
342
transform.unversion_file(root)
342
343
transform.fixup_new_roots()
346
347
def test_apply_retains_root_directory(self):
347
348
# Do not attempt to delete the physical root directory, because that
349
transform, root = self.get_transform()
350
transform, root = self.transform()
351
352
transform.delete_contents(root)
352
353
e = self.assertRaises(AssertionError, self.assertRaises,
355
356
self.assertContainsRe('TransformRenameFailed not raised', str(e))
357
358
def test_apply_retains_file_id(self):
358
transform, root = self.get_transform()
359
transform, root = self.transform()
359
360
old_root_id = transform.tree_file_id(root)
360
361
transform.unversion_file(root)
361
362
transform.apply()
364
365
def test_hardlink(self):
365
366
self.requireFeature(HardlinkFeature)
366
transform, root = self.get_transform()
367
transform, root = self.transform()
367
368
transform.new_file('file1', root, [b'contents'])
368
369
transform.apply()
369
370
target = self.make_branch_and_tree('target')
370
target_transform = TreeTransform(target)
371
trans_id = target_transform.create_path('file1', target_transform.root)
372
target_transform.create_hardlink(self.wt.abspath('file1'), trans_id)
373
target_transform.apply()
371
tartransform = TreeTransform(target)
372
trans_id = tartransform.create_path('file1', tartransform.root)
373
tartransform.create_hardlink(self.wt.abspath('file1'), trans_id)
374
375
self.assertPathExists('target/file1')
375
376
source_stat = os.stat(self.wt.abspath('file1'))
376
377
target_stat = os.stat('target/file1')
377
378
self.assertEqual(source_stat, target_stat)
379
380
def test_convenience(self):
380
transform, root = self.get_transform()
381
transform, root = self.transform()
381
382
self.wt.lock_tree_write()
382
383
self.addCleanup(self.wt.unlock)
383
384
transform.new_file('name', root, [b'contents'], b'my_pretties', True)
402
403
self.assertIs(self.wt.is_executable('oz/dorothy/toto'), False)
404
405
def test_tree_reference(self):
405
transform, root = self.get_transform()
406
transform, root = self.transform()
406
407
tree = transform._tree
407
408
trans_id = transform.new_directory('reference', root, b'subtree-id')
408
409
transform.set_tree_reference(b'subtree-revision', trans_id)
414
415
tree.root_inventory.get_entry(b'subtree-id').reference_revision)
416
417
def test_conflicts(self):
417
transform, root = self.get_transform()
418
transform, root = self.transform()
418
419
trans_id = transform.new_file('name', root, [b'contents'],
420
421
self.assertEqual(len(transform.find_conflicts()), 0)
464
465
self.assertEqual(self.wt.path2id('name'), b'my_pretties')
465
466
with open(self.wt.abspath('name'), 'rb') as f:
466
467
self.assertEqual(b'contents', f.read())
467
transform2, root = self.get_transform()
468
transform2, root = self.transform()
468
469
oz_id = transform2.trans_id_tree_path('oz')
469
470
newtip = transform2.new_file('tip', oz_id, [b'other'], b'tip-id')
470
471
result = transform2.find_conflicts()
609
610
transform._limbo_name(bar_id))
611
612
def test_add_del(self):
612
start, root = self.get_transform()
613
start, root = self.transform()
613
614
start.new_directory('a', root, b'a')
615
transform, root = self.get_transform()
616
transform, root = self.transform()
616
617
transform.delete_versioned(transform.trans_id_tree_path('a'))
617
618
transform.new_directory('a', root, b'a')
618
619
transform.apply()
620
621
def test_unversioning(self):
621
create_tree, root = self.get_transform()
622
create_tree, root = self.transform()
622
623
parent_id = create_tree.new_directory('parent', root, b'parent-id')
623
624
create_tree.new_file('child', parent_id, [b'child'], b'child-id')
624
625
create_tree.apply()
688
689
mfile2_path = self.wt.abspath(pathjoin('new_directory', 'mfile2'))
690
691
def test_both_rename(self):
691
create_tree, root = self.get_transform()
692
create_tree, root = self.transform()
692
693
newdir = create_tree.new_directory('selftest', root, b'selftest-id')
693
694
create_tree.new_file('blackbox.py', newdir, [
694
695
b'hello1'], b'blackbox-id')
695
696
create_tree.apply()
696
mangle_tree, root = self.get_transform()
697
mangle_tree, root = self.transform()
697
698
selftest = mangle_tree.trans_id_tree_path('selftest')
698
699
blackbox = mangle_tree.trans_id_tree_path('selftest/blackbox.py')
699
700
mangle_tree.adjust_path('test', root, selftest)
702
703
mangle_tree.apply()
704
705
def test_both_rename2(self):
705
create_tree, root = self.get_transform()
706
create_tree, root = self.transform()
706
707
breezy = create_tree.new_directory('breezy', root, b'breezy-id')
707
708
tests = create_tree.new_directory('tests', breezy, b'tests-id')
708
709
blackbox = create_tree.new_directory('blackbox', tests, b'blackbox-id')
709
710
create_tree.new_file('test_too_much.py', blackbox, [b'hello1'],
710
711
b'test_too_much-id')
711
712
create_tree.apply()
712
mangle_tree, root = self.get_transform()
713
mangle_tree, root = self.transform()
713
714
breezy = mangle_tree.trans_id_tree_path('breezy')
714
715
tests = mangle_tree.trans_id_tree_path('breezy/tests')
715
716
test_too_much = mangle_tree.trans_id_tree_path(
720
721
mangle_tree.apply()
722
723
def test_both_rename3(self):
723
create_tree, root = self.get_transform()
724
create_tree, root = self.transform()
724
725
tests = create_tree.new_directory('tests', root, b'tests-id')
725
726
create_tree.new_file('test_too_much.py', tests, [b'hello1'],
726
727
b'test_too_much-id')
727
728
create_tree.apply()
728
mangle_tree, root = self.get_transform()
729
mangle_tree, root = self.transform()
729
730
tests = mangle_tree.trans_id_tree_path('tests')
730
731
test_too_much = mangle_tree.trans_id_tree_path(
731
732
'tests/test_too_much.py')
735
736
mangle_tree.apply()
737
738
def test_move_dangling_ie(self):
738
create_tree, root = self.get_transform()
739
create_tree, root = self.transform()
740
741
root = create_tree.root
741
742
create_tree.new_file('name1', root, [b'hello1'], b'name1')
742
743
create_tree.apply()
743
delete_contents, root = self.get_transform()
744
delete_contents, root = self.transform()
744
745
file = delete_contents.trans_id_tree_path('name1')
745
746
delete_contents.delete_contents(file)
746
747
delete_contents.apply()
747
move_id, root = self.get_transform()
748
move_id, root = self.transform()
748
749
name1 = move_id.trans_id_tree_path('name1')
749
750
newdir = move_id.new_directory('dir', root, b'newdir')
750
751
move_id.adjust_path('name2', newdir, name1)
753
754
def test_replace_dangling_ie(self):
754
create_tree, root = self.get_transform()
755
create_tree, root = self.transform()
756
757
root = create_tree.root
757
758
create_tree.new_file('name1', root, [b'hello1'], b'name1')
780
781
self.requireFeature(SymlinkFeature)
781
transform, root = self.get_transform()
782
transform, root = self.transform()
782
783
oz_id = transform.new_directory('oz', root, b'oz-id')
783
784
transform.new_symlink(link_name1, oz_id, link_target1, b'wizard-id')
784
785
wiz_id = transform.create_path(link_name2, oz_id)
825
826
os.symlink = os_symlink
827
828
def get_conflicted(self):
828
create, root = self.get_transform()
829
create, root = self.transform()
829
830
create.new_file('dorothy', root, [b'dorothy'], b'dorothy-id')
830
831
oz = create.new_directory('oz', root, b'oz-id')
831
832
create.new_directory('emeraldcity', oz, b'emerald-id')
833
conflicts, root = self.get_transform()
834
conflicts, root = self.transform()
834
835
# set up duplicate entry, duplicate id
835
836
new_dorothy = conflicts.new_file('dorothy', root, [b'dorothy'],
916
917
' oz/emeraldcity. Cancelled move.')
918
919
def prepare_wrong_parent_kind(self):
919
tt, root = self.get_transform()
920
tt, root = self.transform()
920
921
tt.new_file('parent', root, [b'contents'], b'parent-id')
922
tt, root = self.get_transform()
923
tt, root = self.transform()
923
924
parent_id = tt.trans_id_file_id(b'parent-id')
924
925
tt.new_file('child,', parent_id, [b'contents2'], b'file-id')
941
942
self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
943
944
def test_resolve_conflicts_wrong_new_parent_kind(self):
944
tt, root = self.get_transform()
945
tt, root = self.transform()
945
946
parent_id = tt.new_directory('parent', root, b'parent-id')
946
947
tt.new_file('child,', parent_id, [b'contents2'], b'file-id')
948
tt, root = self.get_transform()
949
tt, root = self.transform()
949
950
parent_id = tt.trans_id_file_id(b'parent-id')
950
951
tt.delete_contents(parent_id)
951
952
tt.create_file([b'contents'], parent_id)
957
958
self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
959
960
def test_resolve_conflicts_wrong_parent_kind_unversioned(self):
960
tt, root = self.get_transform()
961
tt, root = self.transform()
961
962
parent_id = tt.new_directory('parent', root)
962
963
tt.new_file('child,', parent_id, [b'contents2'])
964
tt, root = self.get_transform()
965
tt, root = self.transform()
965
966
parent_id = tt.trans_id_tree_path('parent')
966
967
tt.delete_contents(parent_id)
967
968
tt.create_file([b'contents'], parent_id)
986
987
self.assertRaises(NoFinalPath, tt.apply)
988
989
def test_moving_versioned_directories(self):
989
create, root = self.get_transform()
990
create, root = self.transform()
990
991
kansas = create.new_directory('kansas', root, b'kansas-id')
991
992
create.new_directory('house', kansas, b'house-id')
992
993
create.new_directory('oz', root, b'oz-id')
994
cyclone, root = self.get_transform()
995
cyclone, root = self.transform()
995
996
oz = cyclone.trans_id_tree_path('oz')
996
997
house = cyclone.trans_id_tree_path('house')
997
998
cyclone.adjust_path('house', oz, house)
1000
1001
def test_moving_root(self):
1001
create, root = self.get_transform()
1002
create, root = self.transform()
1002
1003
fun = create.new_directory('fun', root, b'fun-id')
1003
1004
create.new_directory('sun', root, b'sun-id')
1004
1005
create.new_directory('moon', root, b'moon')
1006
transform, root = self.get_transform()
1007
transform, root = self.transform()
1007
1008
transform.adjust_root_path('oldroot', fun)
1008
1009
new_root = transform.trans_id_tree_path('')
1009
1010
transform.version_file(b'new-root', new_root)
1010
1011
transform.apply()
1012
1013
def test_renames(self):
1013
create, root = self.get_transform()
1014
create, root = self.transform()
1014
1015
old = create.new_directory('old-parent', root, b'old-id')
1015
1016
intermediate = create.new_directory('intermediate', old, b'im-id')
1016
1017
myfile = create.new_file('myfile', intermediate, [b'myfile-text'],
1019
rename, root = self.get_transform()
1020
rename, root = self.transform()
1020
1021
old = rename.trans_id_file_id(b'old-id')
1021
1022
rename.adjust_path('new', root, old)
1022
1023
myfile = rename.trans_id_file_id(b'myfile-id')
1026
1027
def test_rename_fails(self):
1027
1028
self.requireFeature(features.not_running_as_root)
1028
1029
# see https://bugs.launchpad.net/bzr/+bug/491763
1029
create, root_id = self.get_transform()
1030
create, root_id = self.transform()
1030
1031
create.new_directory('first-dir', root_id, b'first-id')
1031
1032
create.new_file('myfile', root_id, [b'myfile-text'], b'myfile-id')
1040
1041
self.skipTest("Can't force a permissions error on rename")
1041
1042
# now transform to rename
1042
rename_transform, root_id = self.get_transform()
1043
rename_transform, root_id = self.transform()
1043
1044
file_trans_id = rename_transform.trans_id_file_id(b'myfile-id')
1044
1045
dir_id = rename_transform.trans_id_file_id(b'first-id')
1045
1046
rename_transform.adjust_path('newname', dir_id, file_trans_id)
1090
1091
"""File mode is preserved when replacing content"""
1091
1092
if sys.platform == 'win32':
1092
1093
raise TestSkipped('chmod has no effect on win32')
1093
transform, root = self.get_transform()
1094
transform, root = self.transform()
1094
1095
transform.new_file('file1', root, [b'contents'], b'file1-id', True)
1095
1096
transform.apply()
1096
1097
self.wt.lock_write()
1097
1098
self.addCleanup(self.wt.unlock)
1098
1099
self.assertTrue(self.wt.is_executable('file1'))
1099
transform, root = self.get_transform()
1100
transform, root = self.transform()
1100
1101
file1_id = transform.trans_id_tree_path('file1')
1101
1102
transform.delete_contents(file1_id)
1102
1103
transform.create_file([b'contents2'], file1_id)
1115
1116
stat_paths.append(path)
1116
1117
return real_stat(path)
1118
transform, root = self.get_transform()
1119
transform, root = self.transform()
1120
1121
bar1_id = transform.new_file('bar', root, [b'bar contents 1\n'],
1121
1122
file_id=b'bar-id-1', executable=False)
1122
1123
transform.apply()
1124
transform, root = self.get_transform()
1125
transform, root = self.transform()
1125
1126
bar1_id = transform.trans_id_tree_path('bar')
1126
1127
bar2_id = transform.trans_id_tree_path('bar2')
1138
1139
def test_iter_changes(self):
1139
1140
self.wt.set_root_id(b'eert_toor')
1140
transform, root = self.get_transform()
1141
transform, root = self.transform()
1141
1142
transform.new_file('old', root, [b'blah'], b'id-1', True)
1142
1143
transform.apply()
1143
transform, root = self.get_transform()
1144
transform, root = self.transform()
1145
1146
self.assertEqual([], list(transform.iter_changes()))
1146
1147
old = transform.trans_id_tree_path('old')
1162
1163
def test_iter_changes_new(self):
1163
1164
self.wt.set_root_id(b'eert_toor')
1164
transform, root = self.get_transform()
1165
transform, root = self.transform()
1165
1166
transform.new_file('old', root, [b'blah'])
1166
1167
transform.apply()
1167
transform, root = self.get_transform()
1168
transform, root = self.transform()
1169
1170
old = transform.trans_id_tree_path('old')
1170
1171
transform.version_file(b'id-1', old)
1179
1180
def test_iter_changes_modifications(self):
1180
1181
self.wt.set_root_id(b'eert_toor')
1181
transform, root = self.get_transform()
1182
transform, root = self.transform()
1182
1183
transform.new_file('old', root, [b'blah'], b'id-1')
1183
1184
transform.new_file('new', root, [b'blah'])
1184
1185
transform.new_directory('subdir', root, b'subdir-id')
1185
1186
transform.apply()
1186
transform, root = self.get_transform()
1187
transform, root = self.transform()
1188
1189
old = transform.trans_id_tree_path('old')
1189
1190
subdir = transform.trans_id_tree_path('subdir')
1268
1269
# will be applied before file2. And if it's applied after file2, it
1269
1270
# obviously can't bleed into file2's change output. But for now, it
1271
transform, root = self.get_transform()
1272
transform, root = self.transform()
1272
1273
transform.new_file('file1', root, [b'blah'], b'id-1')
1273
1274
transform.new_file('file2', root, [b'blah'], b'id-2')
1274
1275
transform.apply()
1275
transform, root = self.get_transform()
1276
transform, root = self.transform()
1277
1278
transform.delete_contents(transform.trans_id_file_id(b'id-1'))
1278
1279
transform.set_executability(True,
1292
1293
"""Test moving ids with no files around"""
1293
1294
self.wt.set_root_id(b'toor_eert')
1294
1295
# Need two steps because versioning a non-existant file is a conflict.
1295
transform, root = self.get_transform()
1296
transform, root = self.transform()
1296
1297
transform.new_directory('floater', root, b'floater-id')
1297
1298
transform.apply()
1298
transform, root = self.get_transform()
1299
transform, root = self.transform()
1299
1300
transform.delete_contents(transform.trans_id_tree_path('floater'))
1300
1301
transform.apply()
1301
transform, root = self.get_transform()
1302
transform, root = self.transform()
1302
1303
floater = transform.trans_id_tree_path('floater')
1304
1305
transform.adjust_path('flitter', root, floater)
1314
1315
def test_iter_changes_pointless(self):
1315
1316
"""Ensure that no-ops are not treated as modifications"""
1316
1317
self.wt.set_root_id(b'eert_toor')
1317
transform, root = self.get_transform()
1318
transform, root = self.transform()
1318
1319
transform.new_file('old', root, [b'blah'], b'id-1')
1319
1320
transform.new_directory('subdir', root, b'subdir-id')
1320
1321
transform.apply()
1321
transform, root = self.get_transform()
1322
transform, root = self.transform()
1323
1324
old = transform.trans_id_tree_path('old')
1324
1325
subdir = transform.trans_id_tree_path('subdir')
1334
1335
transform.finalize()
1336
1337
def test_rename_count(self):
1337
transform, root = self.get_transform()
1338
transform, root = self.transform()
1338
1339
transform.new_file('name1', root, [b'contents'])
1339
1340
self.assertEqual(transform.rename_count, 0)
1340
1341
transform.apply()
1341
1342
self.assertEqual(transform.rename_count, 1)
1342
transform2, root = self.get_transform()
1343
transform2, root = self.transform()
1343
1344
transform2.adjust_path('name2', root,
1344
1345
transform2.trans_id_tree_path('name1'))
1345
1346
self.assertEqual(transform2.rename_count, 0)
1356
1357
This test ensures they work correctly with the rename-avoidance
1359
transform, root = self.get_transform()
1360
transform, root = self.transform()
1360
1361
parent1 = transform.new_directory('parent1', root)
1361
1362
child1 = transform.new_file('child1', parent1, [b'contents'])
1362
1363
parent2 = transform.new_directory('parent2', root)
1375
1376
before adjusting the path. The transform must detect that the
1376
1377
directory is non-empty, and move children to safe locations.
1378
transform, root = self.get_transform()
1379
transform, root = self.transform()
1379
1380
parent1 = transform.new_directory('parent1', root)
1380
1381
child1 = transform.new_file('child1', parent1, [b'contents'])
1381
1382
child2 = transform.new_file('child2', parent1, [b'contents'])
1403
1404
def test_adjust_and_cancel(self):
1404
1405
"""Make sure adjust_path keeps track of limbo children properly"""
1405
transform, root = self.get_transform()
1406
transform, root = self.transform()
1406
1407
parent1 = transform.new_directory('parent1', root)
1407
1408
child1 = transform.new_file('child1', parent1, [b'contents'])
1408
1409
parent2 = transform.new_directory('parent2', root)
1419
1420
def test_noname_contents(self):
1420
1421
"""TreeTransform should permit deferring naming files."""
1421
transform, root = self.get_transform()
1422
transform, root = self.transform()
1422
1423
parent = transform.trans_id_file_id(b'parent-id')
1424
1425
transform.create_directory(parent)
1429
1430
def test_noname_contents_nested(self):
1430
1431
"""TreeTransform should permit deferring naming files."""
1431
transform, root = self.get_transform()
1432
transform, root = self.transform()
1432
1433
parent = transform.trans_id_file_id(b'parent-id')
1434
1435
transform.create_directory(parent)
1443
1444
def test_reuse_name(self):
1444
1445
"""Avoid reusing the same limbo name for different files"""
1445
transform, root = self.get_transform()
1446
transform, root = self.transform()
1446
1447
parent = transform.new_directory('parent', root)
1447
1448
transform.new_directory('child', parent)
1461
1462
def test_reuse_when_first_moved(self):
1462
1463
"""Don't avoid direct paths when it is safe to use them"""
1463
transform, root = self.get_transform()
1464
transform, root = self.transform()
1464
1465
parent = transform.new_directory('parent', root)
1465
1466
child1 = transform.new_directory('child', parent)
1466
1467
transform.adjust_path('child1', parent, child1)
1472
1473
def test_reuse_after_cancel(self):
1473
1474
"""Don't avoid direct paths when it is safe to use them"""
1474
transform, root = self.get_transform()
1475
transform, root = self.transform()
1475
1476
parent2 = transform.new_directory('parent2', root)
1476
1477
child1 = transform.new_directory('child1', parent2)
1477
1478
transform.cancel_creation(parent2)
1485
1486
def test_finalize_order(self):
1486
1487
"""Finalize must be done in child-to-parent order"""
1487
transform, root = self.get_transform()
1488
transform, root = self.transform()
1488
1489
parent = transform.new_directory('parent', root)
1489
1490
transform.new_directory('child', parent)
1493
1494
self.fail('Tried to remove parent before child1')
1495
1496
def test_cancel_with_cancelled_child_should_succeed(self):
1496
transform, root = self.get_transform()
1497
transform, root = self.transform()
1497
1498
parent = transform.new_directory('parent', root)
1498
1499
child = transform.new_directory('child', parent)
1499
1500
transform.cancel_creation(child)
1656
1657
self.assertEqual(wt.kind("foo"), "file")
1658
1659
def test_no_final_path(self):
1659
transform, root = self.get_transform()
1660
transform, root = self.transform()
1660
1661
trans_id = transform.trans_id_file_id(b'foo')
1661
1662
transform.create_file([b'bar'], trans_id)
1662
1663
transform.cancel_creation(trans_id)
1723
1724
tree = self.make_branch_and_tree('tree')
1724
1725
self.build_tree(['tree/foo'])
1725
1726
tree.add('foo', b'foo-id')
1726
with TransformPreview(tree) as tt:
1727
with tree.preview_transform() as tt:
1727
1728
self.assertEqual([], tt._inventory_altered())
1729
1730
def test_inventory_altered_changed_parent_id(self):
1730
1731
tree = self.make_branch_and_tree('tree')
1731
1732
self.build_tree(['tree/foo'])
1732
1733
tree.add('foo', b'foo-id')
1733
with TransformPreview(tree) as tt:
1734
with tree.preview_transform() as tt:
1734
1735
tt.unversion_file(tt.root)
1735
1736
tt.version_file(b'new-id', tt.root)
1736
1737
foo_trans_id = tt.trans_id_tree_path('foo')
1742
1743
tree = self.make_branch_and_tree('tree')
1743
1744
self.build_tree(['tree/foo'])
1744
1745
tree.add('foo', b'foo-id')
1745
with TransformPreview(tree) as tt:
1746
with tree.preview_transform() as tt:
1746
1747
tt.unversion_file(tt.root)
1747
1748
tt.version_file(tree.path2id(''), tt.root)
1748
1749
tt.trans_id_tree_path('foo')
2363
2364
branch = self.get_branch()
2364
2365
basis = branch.repository.revision_tree(
2365
2366
_mod_revision.NULL_REVISION)
2366
tt = TransformPreview(basis)
2367
tt = basis.preview_transform()
2367
2368
self.addCleanup(tt.finalize)
2368
2369
e = self.assertRaises(ValueError, tt.commit, branch, '')
2369
2370
self.assertEqual('TreeTransform not based on branch basis: null:',
2386
2387
branch = self.make_branch('branch')
2387
2388
branch.lock_write()
2388
2389
self.addCleanup(branch.unlock)
2389
tt = TransformPreview(branch.basis_tree())
2390
tt = branch.basis_tree().preview_transform()
2390
2391
self.addCleanup(tt.finalize)
2391
2392
tt.new_directory('', ROOT_PARENT, b'TREE_ROOT')
2392
2393
tt.commit(branch, 'my message')
2398
2399
branch = self.make_branch('branch')
2399
2400
branch.lock_write()
2400
2401
self.addCleanup(branch.unlock)
2401
tt = TransformPreview(branch.basis_tree())
2402
tt = branch.basis_tree().preview_transform()
2402
2403
self.addCleanup(tt.finalize)
2403
2404
e = self.assertRaises(ValueError, tt.commit, branch,
2404
2405
'my message', [b'rev1b-id'])
2431
2432
branch, tt = self.get_branch_and_transform()
2432
2433
tt.new_file('file', tt.root, [b'contents'], b'file-id')
2433
2434
tt.commit(branch, 'message', strict=True)
2434
tt = TransformPreview(branch.basis_tree())
2435
tt = branch.basis_tree().preview_transform()
2435
2436
self.addCleanup(tt.finalize)
2436
2437
trans_id = tt.trans_id_file_id(b'file-id')
2437
2438
tt.delete_contents(trans_id)
2788
2789
def get_empty_preview(self):
2789
2790
repository = self.make_repository('repo')
2790
2791
tree = repository.revision_tree(_mod_revision.NULL_REVISION)
2791
preview = TransformPreview(tree)
2792
preview = tree.preview_transform()
2792
2793
self.addCleanup(preview.finalize)
2795
2796
def test_transform_preview(self):
2796
2797
revision_tree = self.create_tree()
2797
preview = TransformPreview(revision_tree)
2798
preview = revision_tree.preview_transform()
2798
2799
self.addCleanup(preview.finalize)
2800
2801
def test_transform_preview_tree(self):
2801
2802
revision_tree = self.create_tree()
2802
preview = TransformPreview(revision_tree)
2803
preview = revision_tree.preview_transform()
2803
2804
self.addCleanup(preview.finalize)
2804
2805
preview.get_preview_tree()
2806
2807
def test_transform_new_file(self):
2807
2808
revision_tree = self.create_tree()
2808
preview = TransformPreview(revision_tree)
2809
preview = revision_tree.preview_transform()
2809
2810
self.addCleanup(preview.finalize)
2810
2811
preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
2811
2812
preview_tree = preview.get_preview_tree()
2816
2817
def test_diff_preview_tree(self):
2817
2818
revision_tree = self.create_tree()
2818
preview = TransformPreview(revision_tree)
2819
preview = revision_tree.preview_transform()
2819
2820
self.addCleanup(preview.finalize)
2820
2821
preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
2821
2822
preview_tree = preview.get_preview_tree()
2836
2837
tree.add('foo', b'foo-id')
2837
2838
tree.commit('rev1', rev_id=b'rev1')
2838
2839
revision_tree = tree.branch.repository.revision_tree(b'rev1')
2839
preview = TransformPreview(revision_tree)
2840
preview = revision_tree.preview_transform()
2840
2841
self.addCleanup(preview.finalize)
2841
2842
preview.delete_versioned(preview.trans_id_tree_path('foo'))
2842
2843
preview_tree = preview.get_preview_tree()
2857
2858
def test_transform_conflicts(self):
2858
2859
revision_tree = self.create_tree()
2859
preview = TransformPreview(revision_tree)
2860
preview = revision_tree.preview_transform()
2860
2861
self.addCleanup(preview.finalize)
2861
2862
preview.new_file('a', preview.root, [b'content 2'])
2862
2863
resolve_conflicts(preview)
2866
2867
def get_tree_and_preview_tree(self):
2867
2868
revision_tree = self.create_tree()
2868
preview = TransformPreview(revision_tree)
2869
preview = revision_tree.preview_transform()
2869
2870
self.addCleanup(preview.finalize)
2870
2871
a_trans_id = preview.trans_id_file_id(b'a-id')
2871
2872
preview.delete_contents(a_trans_id)
2918
2919
def test_kind(self):
2919
2920
revision_tree = self.create_tree()
2920
preview = TransformPreview(revision_tree)
2921
preview = revision_tree.preview_transform()
2921
2922
self.addCleanup(preview.finalize)
2922
2923
preview.new_file('file', preview.root, [b'contents'], b'file-id')
2923
2924
preview.new_directory('directory', preview.root, b'dir-id')
2938
2939
work_tree = self.make_branch_and_tree('tree')
2939
2940
self.build_tree(['tree/file'])
2940
2941
work_tree.add('file', b'file-id')
2941
preview = TransformPreview(work_tree)
2942
preview = work_tree.preview_transform()
2942
2943
self.addCleanup(preview.finalize)
2943
2944
file_trans_id = preview.trans_id_tree_path('file')
2944
2945
preview.adjust_path('renamed', preview.root, file_trans_id)
2950
2951
work_tree = self.make_branch_and_tree('tree')
2951
2952
self.build_tree_contents([('tree/old', b'old')])
2952
2953
work_tree.add('old', b'old-id')
2953
preview = TransformPreview(work_tree)
2954
preview = work_tree.preview_transform()
2954
2955
self.addCleanup(preview.finalize)
2955
2956
preview.new_file('name', preview.root, [b'contents'], b'new-id',
2977
2978
tree = self.make_branch_and_tree('tree')
2978
2979
self.build_tree(['tree/a', 'tree/b', 'tree/c'])
2979
2980
tree.add(['a', 'b', 'c'], [b'a-id', b'b-id', b'c-id'])
2980
preview = TransformPreview(tree)
2981
preview = tree.preview_transform()
2981
2982
self.addCleanup(preview.finalize)
2982
2983
preview.unversion_file(preview.trans_id_file_id(b'b-id'))
2983
2984
c_trans_id = preview.trans_id_file_id(b'c-id')
2991
2992
tree = self.make_branch_and_tree('tree')
2992
2993
self.build_tree(['tree/unchanged', 'tree/deleted'])
2993
2994
tree.add(['unchanged', 'deleted'], [b'unchanged-id', b'deleted-id'])
2994
preview = TransformPreview(tree)
2995
preview = tree.preview_transform()
2995
2996
self.addCleanup(preview.finalize)
2996
2997
preview.unversion_file(preview.trans_id_file_id(b'deleted-id'))
2997
2998
preview_tree = preview.get_preview_tree()
3002
3003
tree = self.make_branch_and_tree('tree')
3003
3004
self.build_tree(['tree/unchanged'])
3004
3005
tree.add(['unchanged'], [b'unchanged-id'])
3005
preview = TransformPreview(tree)
3006
preview = tree.preview_transform()
3006
3007
self.addCleanup(preview.finalize)
3007
3008
preview.new_file('new', preview.trans_id_file_id(b'unchanged-id'),
3008
3009
[b'contents'], b'new-id')
3014
3015
self.build_tree(['tree/old_parent/', 'tree/old_parent/child'])
3015
3016
tree.add(['old_parent', 'old_parent/child'],
3016
3017
[b'old_parent-id', b'child-id'])
3017
preview = TransformPreview(tree)
3018
preview = tree.preview_transform()
3018
3019
self.addCleanup(preview.finalize)
3019
3020
new_parent = preview.new_directory('new_parent', preview.root,
3020
3021
b'new_parent-id')
3029
3030
self.build_tree(['tree/old_name/', 'tree/old_name/child'])
3030
3031
tree.add(['old_name', 'old_name/child'],
3031
3032
[b'parent-id', b'child-id'])
3032
preview = TransformPreview(tree)
3033
preview = tree.preview_transform()
3033
3034
self.addCleanup(preview.finalize)
3034
3035
preview.adjust_path('new_name', preview.root,
3035
3036
preview.trans_id_file_id(b'parent-id'))
3102
3103
tree = self.make_branch_and_tree('tree')
3103
3104
self.build_tree(['tree/path/'])
3104
3105
tree.add('path')
3105
preview = TransformPreview(tree)
3106
preview = tree.preview_transform()
3106
3107
self.addCleanup(preview.finalize)
3107
3108
preview.delete_contents(preview.trans_id_tree_path('path'))
3108
3109
summary = preview.get_preview_tree().path_content_summary('path')
3127
3128
tree = self.make_branch_and_tree('tree')
3128
3129
self.build_tree(['tree/path'])
3129
3130
tree.add('path')
3130
preview = TransformPreview(tree)
3131
preview = tree.preview_transform()
3131
3132
self.addCleanup(preview.finalize)
3132
3133
path_id = preview.trans_id_tree_path('path')
3133
3134
preview.set_executability(True, path_id)
3167
3168
tree.add('file', b'file-id')
3168
3169
tree.commit('a', rev_id=b'one')
3169
3170
self.build_tree_contents([('tree/file', b'a\nb\n')])
3170
preview = TransformPreview(tree)
3171
preview = tree.preview_transform()
3171
3172
self.addCleanup(preview.finalize)
3172
3173
file_trans_id = preview.trans_id_file_id(b'file-id')
3173
3174
preview.delete_contents(file_trans_id)
3200
3201
self.build_tree_contents([('tree/file', b'a\n')])
3201
3202
tree.add('file', b'file-id')
3202
3203
tree.commit('a', rev_id=b'one')
3203
preview = TransformPreview(tree)
3204
preview = tree.preview_transform()
3204
3205
self.addCleanup(preview.finalize)
3205
3206
file_trans_id = preview.trans_id_file_id(b'file-id')
3206
3207
preview.adjust_path('newname', preview.root, file_trans_id)
3218
3219
tree.add('file', b'file-id')
3219
3220
tree.commit('a', rev_id=b'one')
3220
3221
self.build_tree_contents([('tree/file', b'a\nb\n')])
3221
preview = TransformPreview(tree)
3222
preview = tree.preview_transform()
3222
3223
self.addCleanup(preview.finalize)
3223
3224
file_trans_id = preview.trans_id_file_id(b'file-id')
3224
3225
preview.delete_contents(file_trans_id)
3252
3253
work_a.add('file', b'file-id')
3253
3254
base_id = work_a.commit('base version')
3254
3255
tree_b = work_a.controldir.sprout('wtb').open_workingtree()
3255
preview = TransformPreview(work_a)
3256
preview = work_a.preview_transform()
3256
3257
self.addCleanup(preview.finalize)
3257
3258
trans_id = preview.trans_id_file_id(b'file-id')
3258
3259
preview.delete_contents(trans_id)
3275
3276
work_a.add('file', b'file-id')
3276
3277
base_id = work_a.commit('base version')
3277
3278
tree_b = work_a.controldir.sprout('wtb').open_workingtree()
3278
preview = TransformPreview(work_a.basis_tree())
3279
preview = work_a.basis_tree().preview_transform()
3279
3280
self.addCleanup(preview.finalize)
3280
3281
trans_id = preview.trans_id_file_id(b'file-id')
3281
3282
preview.delete_contents(trans_id)
3308
3309
self.build_tree(['tree/removed-file', 'tree/existing-file',
3309
3310
'tree/not-removed-file'])
3310
3311
work_tree.add(['removed-file', 'not-removed-file'])
3311
preview = TransformPreview(work_tree)
3312
preview = work_tree.preview_transform()
3312
3313
self.addCleanup(preview.finalize)
3313
3314
preview.new_file('new-file', preview.root, [b'contents'])
3314
3315
preview.new_file('new-versioned-file', preview.root, [b'contents'],
3330
3331
self.addCleanup(child_tree.unlock)
3331
3332
work_tree.lock_write()
3332
3333
self.addCleanup(work_tree.unlock)
3333
preview = TransformPreview(work_tree)
3334
preview = work_tree.preview_transform()
3334
3335
self.addCleanup(preview.finalize)
3335
3336
file_trans_id = preview.trans_id_file_id(b'file-id')
3336
3337
preview.delete_contents(file_trans_id)
3351
3352
def test_merge_preview_into_workingtree(self):
3352
3353
tree = self.make_branch_and_tree('tree')
3353
3354
tree.set_root_id(b'TREE_ROOT')
3354
tt = TransformPreview(tree)
3355
tt = tree.preview_transform()
3355
3356
self.addCleanup(tt.finalize)
3356
3357
tt.new_file('name', tt.root, [b'content'], b'file-id')
3357
3358
tree2 = self.make_branch_and_tree('tree2')
3366
3367
self.build_tree_contents([('tree/foo', b'bar')])
3367
3368
tree.add('foo', b'foo-id')
3368
3369
tree.commit('foo')
3369
tt = TransformPreview(tree)
3370
tt = tree.preview_transform()
3370
3371
self.addCleanup(tt.finalize)
3371
3372
trans_id = tt.trans_id_file_id(b'foo-id')
3372
3373
tt.delete_contents(trans_id)
3381
3382
def test_has_filename(self):
3382
3383
wt = self.make_branch_and_tree('tree')
3383
3384
self.build_tree(['tree/unmodified', 'tree/removed', 'tree/modified'])
3384
tt = TransformPreview(wt)
3385
tt = wt.preview_transform()
3385
3386
removed_id = tt.trans_id_tree_path('removed')
3386
3387
tt.delete_contents(removed_id)
3387
3388
tt.new_file('new', tt.root, [b'contents'])
3399
3400
def test_is_executable(self):
3400
3401
tree = self.make_branch_and_tree('tree')
3401
preview = TransformPreview(tree)
3402
preview = tree.preview_transform()
3402
3403
self.addCleanup(preview.finalize)
3403
3404
preview.new_file('foo', preview.root, [b'bar'], b'baz-id')
3404
3405
preview_tree = preview.get_preview_tree()
3409
3410
rev_id = tree.commit('rev1')
3410
3411
tree.branch.lock_write()
3411
3412
self.addCleanup(tree.branch.unlock)
3412
tt = TransformPreview(tree)
3413
tt = tree.preview_transform()
3413
3414
tt.new_file('file', tt.root, [b'contents'], b'file_id')
3414
3415
self.addCleanup(tt.finalize)
3415
3416
preview = tt.get_preview_tree()
3425
3426
self.requireFeature(features.UnicodeFilenameFeature)
3426
3427
branch = self.make_branch('any')
3427
3428
tree = branch.repository.revision_tree(_mod_revision.NULL_REVISION)
3428
tt = TransformPreview(tree)
3429
tt = tree.preview_transform()
3429
3430
self.addCleanup(tt.finalize)
3430
3431
foo_id = tt.new_directory('', ROOT_PARENT)
3431
3432
bar_id = tt.new_file(u'\u1234bar', foo_id, [b'contents'])
3710
3711
def test_no_orphan_for_transform_preview(self):
3711
3712
tree = self.make_branch_and_tree('tree')
3712
tt = transform.TransformPreview(tree)
3713
tt = tree.preview_transform()
3713
3714
self.addCleanup(tt.finalize)
3714
3715
self.assertRaises(NotImplementedError, tt.new_orphan, 'foo', 'bar')
3817
3818
calls.append((tree, tt))
3818
3819
MutableTree.hooks.install_named_hook(
3819
3820
'pre_transform', record_pre_transform, "Pre transform")
3820
transform, root = self.get_transform()
3821
transform, root = self.transform()
3821
3822
old_root_id = transform.tree_file_id(root)
3822
3823
transform.apply()
3823
3824
self.assertEqual(old_root_id, self.wt.path2id(''))
3830
3831
calls.append((tree, tt))
3831
3832
MutableTree.hooks.install_named_hook(
3832
3833
'post_transform', record_post_transform, "Post transform")
3833
transform, root = self.get_transform()
3834
transform, root = self.transform()
3834
3835
old_root_id = transform.tree_file_id(root)
3835
3836
transform.apply()
3836
3837
self.assertEqual(old_root_id, self.wt.path2id(''))