187
189
orig = self.wt._observed_sha1
188
191
def _observed_sha1(*args):
189
192
calls.append(args)
191
194
self.wt._observed_sha1 = _observed_sha1
193
self.assertEqual([(None, 'file1', trans._observed_sha1s[trans_id])],
196
self.assertEqual([('file1', trans._observed_sha1s[trans_id])],
196
199
def test_create_file_caches_sha1(self):
258
261
fo, st2 = self.wt.get_file_with_stat('two', filtered=False)
260
263
# We only guarantee 2s resolution
261
self.assertTrue(abs(creation_mtime - st1.st_mtime) < 2.0,
265
abs(creation_mtime - st1.st_mtime) < 2.0,
262
266
"%s != %s within 2 seconds" % (creation_mtime, st1.st_mtime))
263
267
# But if we have more than that, all files should get the same result
264
268
self.assertEqual(st1.st_mtime, st2.st_mtime)
290
294
def test_add_two_roots(self):
291
295
transform, root = self.get_transform()
292
new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
293
new_trans_id = transform.new_directory('', ROOT_PARENT, b'alt-root-id')
296
transform.new_directory('', ROOT_PARENT, b'new-root-id')
297
transform.new_directory('', ROOT_PARENT, b'alt-root-id')
294
298
self.assertRaises(ValueError, transform.fixup_new_roots)
296
300
def test_retain_existing_root(self):
310
314
def test_add_unversioned_root(self):
311
315
transform, root = self.get_transform()
312
new_trans_id = transform.new_directory('', ROOT_PARENT, None)
316
transform.new_directory('', ROOT_PARENT, None)
313
317
transform.delete_contents(transform.root)
314
318
transform.fixup_new_roots()
315
319
self.assertNotIn(transform.root, transform._new_id)
325
329
self.assertEqual(old_root_id, self.wt.get_root_id())
327
331
transform, root = self.get_transform()
328
new_trans_id = transform.new_directory('', ROOT_PARENT, b'new-root-id')
329
new_trans_id = transform.new_directory('', ROOT_PARENT, b'alt-root-id')
332
transform.new_directory('', ROOT_PARENT, b'new-root-id')
333
transform.new_directory('', ROOT_PARENT, b'alt-root-id')
330
334
self.assertRaises(ValueError, transform.fixup_new_roots)
332
336
def test_fixup_new_roots_permits_empty_tree(self):
374
378
transform, root = self.get_transform()
375
379
self.wt.lock_tree_write()
376
380
self.addCleanup(self.wt.unlock)
377
trans_id = transform.new_file('name', root, [b'contents'],
378
b'my_pretties', True)
381
transform.new_file('name', root, [b'contents'], b'my_pretties', True)
379
382
oz = transform.new_directory('oz', root, b'oz-id')
380
383
dorothy = transform.new_directory('dorothy', oz, b'dorothy-id')
381
toto = transform.new_file('toto', dorothy, [b'toto-contents'],
384
transform.new_file('toto', dorothy, [b'toto-contents'], b'toto-id',
384
387
self.assertEqual(len(transform.find_conflicts()), 0)
385
388
transform.apply()
404
407
transform.apply()
406
409
self.addCleanup(tree.unlock)
407
self.assertEqual(b'subtree-revision',
408
tree.root_inventory.get_entry(b'subtree-id').reference_revision)
412
tree.root_inventory.get_entry(b'subtree-id').reference_revision)
410
414
def test_conflicts(self):
411
415
transform, root = self.get_transform()
641
645
mangle_tree, root = self.get_transform()
642
646
root = mangle_tree.root
644
648
name1 = mangle_tree.trans_id_tree_path('name1')
645
649
name2 = mangle_tree.trans_id_tree_path('name2')
646
650
mangle_tree.adjust_path('name2', root, name1)
647
651
mangle_tree.adjust_path('name1', root, name2)
649
#tests for deleting parent directories
653
# tests for deleting parent directories
650
654
ddir = mangle_tree.trans_id_tree_path('dying_directory')
651
655
mangle_tree.delete_contents(ddir)
652
656
dfile = mangle_tree.trans_id_tree_path('dying_directory/dying_file')
655
659
mfile = mangle_tree.trans_id_tree_path('dying_directory/moving_file')
656
660
mangle_tree.adjust_path('mfile', root, mfile)
658
#tests for adding parent directories
662
# tests for adding parent directories
659
663
newdir = mangle_tree.new_directory('new_directory', root, b'newdir')
660
664
mfile2 = mangle_tree.trans_id_tree_path('moving_file2')
661
665
mangle_tree.adjust_path('mfile2', newdir, mfile2)
684
688
def test_both_rename(self):
685
689
create_tree, root = self.get_transform()
686
690
newdir = create_tree.new_directory('selftest', root, b'selftest-id')
687
create_tree.new_file('blackbox.py', newdir, [b'hello1'], b'blackbox-id')
691
create_tree.new_file('blackbox.py', newdir, [
692
b'hello1'], b'blackbox-id')
688
693
create_tree.apply()
689
694
mangle_tree, root = self.get_transform()
690
695
selftest = mangle_tree.trans_id_tree_path('selftest')
705
710
mangle_tree, root = self.get_transform()
706
711
breezy = mangle_tree.trans_id_tree_path('breezy')
707
712
tests = mangle_tree.trans_id_tree_path('breezy/tests')
708
test_too_much = mangle_tree.trans_id_tree_path('breezy/tests/blackbox/test_too_much.py')
713
test_too_much = mangle_tree.trans_id_tree_path(
714
'breezy/tests/blackbox/test_too_much.py')
709
715
mangle_tree.adjust_path('selftest', breezy, tests)
710
716
mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
711
717
mangle_tree.set_executability(True, test_too_much)
719
725
create_tree.apply()
720
726
mangle_tree, root = self.get_transform()
721
727
tests = mangle_tree.trans_id_tree_path('tests')
722
test_too_much = mangle_tree.trans_id_tree_path('tests/test_too_much.py')
728
test_too_much = mangle_tree.trans_id_tree_path(
729
'tests/test_too_much.py')
723
730
mangle_tree.adjust_path('selftest', root, tests)
724
731
mangle_tree.adjust_path('blackbox.py', tests, test_too_much)
725
732
mangle_tree.set_executability(True, test_too_much)
765
772
def _test_symlinks(self, link_name1, link_target1,
766
773
link_name2, link_target2):
768
def ozpath(p): return 'oz/' + p
770
778
self.requireFeature(SymlinkFeature)
771
779
transform, root = self.get_transform()
772
780
oz_id = transform.new_directory('oz', root, b'oz-id')
773
wizard = transform.new_symlink(link_name1, oz_id, link_target1,
781
transform.new_symlink(link_name1, oz_id, link_target1, b'wizard-id')
775
782
wiz_id = transform.create_path(link_name2, oz_id)
776
783
transform.create_symlink(link_target2, wiz_id)
777
784
transform.version_file(b'wiz-id2', wiz_id)
873
880
b'munchkincity-id')
874
881
unversioned_parent2 = UnversionedParent('Versioned directory', 'oz',
876
883
self.assertEqual(cooked_conflicts[3], unversioned_parent)
877
parent_loop = ParentLoop('Cancelled move', 'oz/emeraldcity',
878
'oz/emeraldcity', b'emerald-id', b'emerald-id')
884
parent_loop = ParentLoop(
885
'Cancelled move', 'oz/emeraldcity',
886
'oz/emeraldcity', b'emerald-id', b'emerald-id')
879
887
self.assertEqual(cooked_conflicts[4], deleted_parent)
880
888
self.assertEqual(cooked_conflicts[5], unversioned_parent2)
881
889
self.assertEqual(cooked_conflicts[6], parent_loop)
900
908
self.assertEqual(conflicts_s[3], 'Conflict because munchkincity is not'
901
909
' versioned, but has versioned'
902
910
' children. Versioned directory.')
903
self.assertEqualDiff(conflicts_s[4], "Conflict: can't delete oz because it"
904
" is not empty. Not deleting.")
911
self.assertEqualDiff(
912
conflicts_s[4], "Conflict: can't delete oz because it"
913
" is not empty. Not deleting.")
905
914
self.assertEqual(conflicts_s[5], 'Conflict because oz is not'
906
915
' versioned, but has versioned'
907
916
' children. Versioned directory.')
925
934
tt = self.prepare_wrong_parent_kind()
926
935
raw_conflicts = resolve_conflicts(tt)
927
936
self.assertEqual({('non-directory parent', 'Created directory',
928
'new-3')}, raw_conflicts)
937
'new-3')}, raw_conflicts)
929
938
cooked_conflicts = cook_conflicts(raw_conflicts, tt)
930
939
self.assertEqual([NonDirectoryParent('Created directory', 'parent.new',
931
b'parent-id')], cooked_conflicts)
940
b'parent-id')], cooked_conflicts)
933
942
self.assertFalse(self.wt.is_versioned('parent'))
934
943
self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
944
953
tt.create_file([b'contents'], parent_id)
945
954
raw_conflicts = resolve_conflicts(tt)
946
955
self.assertEqual({('non-directory parent', 'Created directory',
947
'new-3')}, raw_conflicts)
956
'new-3')}, raw_conflicts)
949
958
self.assertFalse(self.wt.is_versioned('parent'))
950
959
self.assertEqual(b'parent-id', self.wt.path2id('parent.new'))
1020
1029
self.requireFeature(features.not_running_as_root)
1021
1030
# see https://bugs.launchpad.net/bzr/+bug/491763
1022
1031
create, root_id = self.get_transform()
1023
first_dir = create.new_directory('first-dir', root_id, b'first-id')
1024
myfile = create.new_file('myfile', root_id, [b'myfile-text'],
1032
create.new_directory('first-dir', root_id, b'first-id')
1033
create.new_file('myfile', root_id, [b'myfile-text'], b'myfile-id')
1027
1035
if os.name == "posix" and sys.platform != "cygwin":
1028
1036
# posix filesystems fail on renaming if the readonly bit is set
1038
1046
dir_id = rename_transform.trans_id_file_id(b'first-id')
1039
1047
rename_transform.adjust_path('newname', dir_id, file_trans_id)
1040
1048
e = self.assertRaises(errors.TransformRenameFailed,
1041
rename_transform.apply)
1042
# On nix looks like:
1049
rename_transform.apply)
1050
# On nix looks like:
1043
1051
# "Failed to rename .../work/.bzr/checkout/limbo/new-1
1044
1052
# to .../first-dir/newname: [Errno 13] Permission denied"
1045
1053
# On windows looks like:
1046
# "Failed to rename .../work/myfile to
1054
# "Failed to rename .../work/myfile to
1047
1055
# .../work/.bzr/checkout/limbo/new-1: [Errno 13] Permission denied"
1048
1056
# This test isn't concerned with exactly what the error looks like,
1049
1057
# and the strerror will vary across OS and locales, but the assert
1067
1076
wt = transform._tree
1069
1078
self.addCleanup(wt.unlock)
1070
transform.new_file('set_on_creation', root, [b'Set on creation'], b'soc',
1079
transform.new_file('set_on_creation', root, [b'Set on creation'],
1072
1081
sac = transform.new_file('set_after_creation', root,
1073
1082
[b'Set after creation'], b'sac')
1074
1083
transform.set_executability(True, sac)
1137
1148
old = transform.trans_id_tree_path('old')
1138
1149
transform.unversion_file(old)
1139
1150
self.assertEqual([(b'id-1', ('old', None), False, (True, False),
1140
(b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
1141
(True, True))], list(transform.iter_changes()))
1151
(b'eert_toor', b'eert_toor'),
1152
('old', 'old'), ('file', 'file'),
1153
(True, True))], list(transform.iter_changes()))
1142
1154
transform.new_directory('new', root, b'id-1')
1143
1155
self.assertEqual([(b'id-1', ('old', 'new'), True, (True, True),
1144
(b'eert_toor', b'eert_toor'), ('old', 'new'),
1145
('file', 'directory'),
1146
(True, False))], list(transform.iter_changes()))
1156
(b'eert_toor', b'eert_toor'), ('old', 'new'),
1157
('file', 'directory'),
1158
(True, False))], list(transform.iter_changes()))
1148
1160
transform.finalize()
1157
1169
old = transform.trans_id_tree_path('old')
1158
1170
transform.version_file(b'id-1', old)
1159
1171
self.assertEqual([(b'id-1', (None, 'old'), False, (False, True),
1160
(b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
1161
(False, False))], list(transform.iter_changes()))
1172
(b'eert_toor', b'eert_toor'),
1173
('old', 'old'), ('file', 'file'),
1175
list(transform.iter_changes()))
1163
1177
transform.finalize()
1176
1190
new = transform.trans_id_tree_path('new')
1177
1191
self.assertEqual([], list(transform.iter_changes()))
1180
1194
transform.delete_contents(old)
1181
1195
self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1182
(b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', None),
1183
(False, False))], list(transform.iter_changes()))
1196
(b'eert_toor', b'eert_toor'),
1197
('old', 'old'), ('file', None),
1199
list(transform.iter_changes()))
1186
1202
transform.create_file([b'blah'], old)
1187
1203
self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1188
(b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
1189
(False, False))], list(transform.iter_changes()))
1204
(b'eert_toor', b'eert_toor'),
1205
('old', 'old'), ('file', 'file'),
1207
list(transform.iter_changes()))
1190
1208
transform.cancel_deletion(old)
1191
1209
self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1192
(b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
1193
(False, False))], list(transform.iter_changes()))
1210
(b'eert_toor', b'eert_toor'),
1211
('old', 'old'), ('file', 'file'),
1213
list(transform.iter_changes()))
1194
1214
transform.cancel_creation(old)
1196
1216
# move file_id to a different file
1199
1219
transform.version_file(b'id-1', new)
1200
1220
transform.adjust_path('old', root, new)
1201
1221
self.assertEqual([(b'id-1', ('old', 'old'), True, (True, True),
1202
(b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
1203
(False, False))], list(transform.iter_changes()))
1222
(b'eert_toor', b'eert_toor'),
1223
('old', 'old'), ('file', 'file'),
1225
list(transform.iter_changes()))
1204
1226
transform.cancel_versioning(new)
1205
1227
transform._removed_id = set()
1208
1230
self.assertEqual([], list(transform.iter_changes()))
1209
1231
transform.set_executability(True, old)
1210
1232
self.assertEqual([(b'id-1', ('old', 'old'), False, (True, True),
1211
(b'eert_toor', b'eert_toor'), ('old', 'old'), ('file', 'file'),
1212
(False, True))], list(transform.iter_changes()))
1233
(b'eert_toor', b'eert_toor'),
1234
('old', 'old'), ('file', 'file'),
1236
list(transform.iter_changes()))
1213
1237
transform.set_executability(None, old)
1217
1241
transform.adjust_path('new', root, old)
1218
1242
transform._new_parent = {}
1219
1243
self.assertEqual([(b'id-1', ('old', 'new'), False, (True, True),
1220
(b'eert_toor', b'eert_toor'), ('old', 'new'), ('file', 'file'),
1221
(False, False))], list(transform.iter_changes()))
1244
(b'eert_toor', b'eert_toor'),
1245
('old', 'new'), ('file', 'file'),
1247
list(transform.iter_changes()))
1222
1248
transform._new_name = {}
1224
1250
# parent directory
1226
1252
transform.adjust_path('new', subdir, old)
1227
1253
transform._new_name = {}
1228
1254
self.assertEqual([(b'id-1', ('old', 'subdir/old'), False,
1229
(True, True), (b'eert_toor', b'subdir-id'), ('old', 'old'),
1230
('file', 'file'), (False, False))],
1231
list(transform.iter_changes()))
1255
(True, True), (b'eert_toor',
1256
b'subdir-id'), ('old', 'old'),
1257
('file', 'file'), (False, False))],
1258
list(transform.iter_changes()))
1232
1259
transform._new_path = {}
1250
1277
transform.delete_contents(transform.trans_id_file_id(b'id-1'))
1251
1278
transform.set_executability(True,
1252
transform.trans_id_file_id(b'id-2'))
1253
self.assertEqual([(b'id-1', (u'file1', u'file1'), True, (True, True),
1254
(b'eert_toor', b'eert_toor'), ('file1', u'file1'),
1255
('file', None), (False, False)),
1256
(b'id-2', (u'file2', u'file2'), False, (True, True),
1257
(b'eert_toor', b'eert_toor'), ('file2', u'file2'),
1258
('file', 'file'), (False, True))],
1279
transform.trans_id_file_id(b'id-2'))
1281
[(b'id-1', (u'file1', u'file1'), True, (True, True),
1282
(b'eert_toor', b'eert_toor'), ('file1', u'file1'),
1283
('file', None), (False, False)),
1284
(b'id-2', (u'file2', u'file2'), False, (True, True),
1285
(b'eert_toor', b'eert_toor'), ('file2', u'file2'),
1286
('file', 'file'), (False, True))],
1259
1287
list(transform.iter_changes()))
1261
1289
transform.finalize()
1276
1304
transform.adjust_path('flitter', root, floater)
1277
1305
self.assertEqual([(b'floater-id', ('floater', 'flitter'), False,
1278
(True, True), (b'toor_eert', b'toor_eert'), ('floater', 'flitter'),
1279
(None, None), (False, False))], list(transform.iter_changes()))
1307
(b'toor_eert', b'toor_eert'),
1308
('floater', 'flitter'),
1309
(None, None), (False, False))],
1310
list(transform.iter_changes()))
1281
1312
transform.finalize()
1403
1434
transform.create_directory(parent)
1404
1435
except KeyError:
1405
1436
self.fail("Can't handle contents with no name")
1406
child = transform.new_directory('child', parent)
1437
transform.new_directory('child', parent)
1407
1438
transform.adjust_path('parent', root, parent)
1408
1439
transform.apply()
1409
1440
self.assertPathExists(self.wt.abspath('parent/child'))
1413
1444
"""Avoid reusing the same limbo name for different files"""
1414
1445
transform, root = self.get_transform()
1415
1446
parent = transform.new_directory('parent', root)
1416
child1 = transform.new_directory('child', parent)
1447
transform.new_directory('child', parent)
1418
1449
child2 = transform.new_directory('child', parent)
1419
1450
except OSError:
1433
1464
parent = transform.new_directory('parent', root)
1434
1465
child1 = transform.new_directory('child', parent)
1435
1466
transform.adjust_path('child1', parent, child1)
1436
child2 = transform.new_directory('child', parent)
1467
transform.new_directory('child', parent)
1437
1468
transform.apply()
1438
1469
# limbo/new-1 => parent
1439
1470
self.assertEqual(1, transform.rename_count)
1445
1476
child1 = transform.new_directory('child1', parent2)
1446
1477
transform.cancel_creation(parent2)
1447
1478
transform.create_directory(parent2)
1448
child2 = transform.new_directory('child1', parent2)
1479
transform.new_directory('child1', parent2)
1449
1480
transform.adjust_path('child2', parent2, child1)
1450
1481
transform.apply()
1451
1482
# limbo/new-1 => parent2, limbo/new-2 => parent2/child1
1630
1661
def test_create_from_tree_bytes(self):
1631
1662
"""Provided lines are used instead of tree content."""
1632
1663
tree1 = self.make_branch_and_tree('tree1')
1633
self.build_tree_contents([('tree1/foo', b'bar'),])
1664
self.build_tree_contents([('tree1/foo', b'bar'), ])
1634
1665
tree1.add('foo', b'foo-id')
1635
1666
tree2 = self.make_branch_and_tree('tree2')
1636
1667
tt = TreeTransform(tree2)
1774
1805
merge_modified = this.wt.merge_modified()
1775
1806
self.assertSubset(merge_modified, modified)
1776
1807
self.assertEqual(len(merge_modified), len(modified))
1777
with open(this.wt.abspath(this.wt.id2path(b'a')), 'wb') as f: f.write(b'booga')
1808
with open(this.wt.abspath(this.wt.id2path(b'a')), 'wb') as f:
1778
1810
modified.pop(0)
1779
1811
merge_modified = this.wt.merge_modified()
1780
1812
self.assertSubset(merge_modified, modified)
1800
1832
for link, target in (('e', e_target), ('f', f_target),
1801
1833
('g', g_target), ('h', h_target)):
1802
1834
if target is not None:
1803
tg.tt.new_symlink(link, tg.root, target, link.encode('ascii'))
1835
tg.tt.new_symlink(link, tg.root, target,
1836
link.encode('ascii'))
1805
1838
for tg in this, base, other:
1809
1842
self.assertIs(os.path.islink(this.wt.abspath('b')), True)
1810
1843
self.assertIs(os.path.isfile(this.wt.abspath('c')), True)
1811
1844
for suffix in ('THIS', 'BASE', 'OTHER'):
1812
self.assertEqual(os.readlink(this.wt.abspath('d.'+suffix)), suffix)
1845
self.assertEqual(os.readlink(
1846
this.wt.abspath('d.' + suffix)), suffix)
1813
1847
self.assertIs(os.path.lexists(this.wt.abspath('d')), False)
1814
1848
self.assertEqual(this.wt.id2path(b'd'), 'd.OTHER')
1815
1849
self.assertEqual(this.wt.id2path(b'f'), 'f.THIS')
1897
1931
a = ControlDir.create_standalone_workingtree('a')
1898
1932
os.mkdir('a/foo')
1899
with open('a/foo/bar', 'wb') as f: f.write(b'contents')
1933
with open('a/foo/bar', 'wb') as f:
1934
f.write(b'contents')
1900
1935
os.symlink('a/foo/bar', 'a/foo/baz')
1901
1936
a.add(['foo', 'foo/bar', 'foo/baz'])
1902
1937
a.commit('initial commit')
1913
1948
def test_build_with_references(self):
1914
1949
tree = self.make_branch_and_tree('source',
1915
format='development-subtree')
1950
format='development-subtree')
1916
1951
subtree = self.make_branch_and_tree('source/subtree',
1917
format='development-subtree')
1952
format='development-subtree')
1918
1953
tree.add_reference(subtree)
1919
1954
tree.commit('a revision')
1920
1955
tree.branch.create_checkout('target')
1929
1964
source.add('file', b'new-file')
1930
1965
source.commit('added file')
1931
1966
build_tree(source.basis_tree(), target)
1932
self.assertEqual([DuplicateEntry('Moved existing file to',
1933
'file.moved', 'file', None, 'new-file')],
1968
[DuplicateEntry('Moved existing file to', 'file.moved',
1969
'file', None, 'new-file')],
1935
1971
target2 = self.make_branch_and_tree('target2')
1936
1972
with open('target2/file', 'wb') as target_file, \
1937
1973
open('source/file', 'rb') as source_file:
1949
1985
target = self.make_branch_and_tree('target')
1950
1986
os.symlink('bar', 'target/symlink')
1951
1987
build_tree(source.basis_tree(), target)
1952
self.assertEqual([DuplicateEntry('Moved existing file to',
1953
'symlink.moved', 'symlink', None, 'new-symlink')],
1989
[DuplicateEntry('Moved existing file to', 'symlink.moved',
1990
'symlink', None, 'new-symlink')],
1954
1991
target.conflicts())
1955
1992
target = self.make_branch_and_tree('target2')
1956
1993
os.symlink('foo', 'target2/symlink')
1984
2021
self.assertPathDoesNotExist('target3/dir1/file')
1985
2022
self.assertPathExists('target3/dir1/file2')
1986
2023
self.assertPathExists('target3/dir1.diverted/file')
1987
self.assertEqual([DuplicateEntry('Diverted to',
1988
'dir1.diverted', 'dir1', 'new-dir1', None)],
2025
[DuplicateEntry('Diverted to', 'dir1.diverted',
2026
'dir1', 'new-dir1', None)],
1989
2027
target.conflicts())
1991
2029
target = self.make_branch_and_tree('target4')
1995
2033
self.assertPathExists('target4/dir1/file')
1996
2034
self.assertEqual('directory', file_kind('target4/dir1/file'))
1997
2035
self.assertPathExists('target4/dir1/file.diverted')
1998
self.assertEqual([DuplicateEntry('Diverted to',
1999
'dir1/file.diverted', 'dir1/file', 'new-file', None)],
2037
[DuplicateEntry('Diverted to', 'dir1/file.diverted',
2038
'dir1/file', 'new-file', None)],
2000
2039
target.conflicts())
2002
2041
def test_mixed_conflict_handling(self):
2007
2046
source.add('name', b'new-name')
2008
2047
source.commit('added file')
2009
2048
build_tree(source.basis_tree(), target)
2010
self.assertEqual([DuplicateEntry('Moved existing file to',
2011
'name.moved', 'name', None, 'new-name')], target.conflicts())
2050
[DuplicateEntry('Moved existing file to',
2051
'name.moved', 'name', None, 'new-name')],
2013
2054
def test_raises_in_populated(self):
2014
2055
source = self.make_branch_and_tree('source')
2019
2060
self.build_tree(['target/name'])
2020
2061
target.add('name')
2021
2062
self.assertRaises(errors.WorkingTreeAlreadyPopulated,
2022
build_tree, source.basis_tree(), target)
2063
build_tree, source.basis_tree(), target)
2024
2065
def test_build_tree_rename_count(self):
2025
2066
source = self.make_branch_and_tree('source')
2054
2095
self.build_tree_contents([('source/file2', b'C')])
2056
2097
real_source_get_file = source.get_file
2057
def get_file(path, file_id=None):
2058
calls.append(file_id)
2059
return real_source_get_file(path, file_id)
2101
return real_source_get_file(path)
2060
2102
source.get_file = get_file
2061
2103
target = self.make_branch_and_tree('target')
2062
2104
revision_tree = source.basis_tree()
2063
2105
revision_tree.lock_read()
2064
2106
self.addCleanup(revision_tree.unlock)
2065
2107
build_tree(revision_tree, target, source)
2066
self.assertEqual([b'file1-id'], calls)
2108
self.assertEqual(['file1'], calls)
2067
2109
target.lock_read()
2068
2110
self.addCleanup(target.unlock)
2069
2111
self.assertEqual([], list(target.iter_changes(revision_tree)))
2106
2148
os.symlink('file2', 'source/file1')
2108
2150
real_source_get_file = source.get_file
2109
def get_file(path, file_id=None):
2110
calls.append(file_id)
2111
return real_source_get_file(path, file_id)
2154
return real_source_get_file(path)
2112
2155
source.get_file = get_file
2113
2156
target = self.make_branch_and_tree('target')
2114
2157
revision_tree = source.basis_tree()
2186
2229
# below, but that looks a bit... hard to read even if it's exactly
2187
2230
# the same thing.
2188
2231
original_registry = filters._reset_registry()
2189
2233
def restore_registry():
2190
2234
filters._reset_registry(original_registry)
2191
2235
self.addCleanup(restore_registry)
2192
2237
def rot13(chunks, context=None):
2193
return [codecs.encode(chunk.decode('ascii'), 'rot13').encode('ascii')
2194
for chunk in chunks]
2239
codecs.encode(chunk.decode('ascii'), 'rot13').encode('ascii')
2240
for chunk in chunks]
2195
2241
rot13filter = filters.ContentFilter(rot13, rot13)
2196
2242
filters.filter_stacks_registry.register(
2197
2243
'rot13', {'yes': [rot13filter]}.get)
2231
2278
def test_case_insensitive_build_tree_inventory(self):
2232
2279
if (features.CaseInsensitiveFilesystemFeature.available()
2233
or features.CaseInsCasePresFilenameFeature.available()):
2280
or features.CaseInsCasePresFilenameFeature.available()):
2234
2281
raise tests.UnavailableFeature('Fully case sensitive filesystem')
2235
2282
source = self.make_branch_and_tree('source')
2236
2283
self.build_tree(['source/file', 'source/FILE'])
2274
2321
entry2_state = entry2[1][0]
2275
2322
# Now, make sure that we don't have to re-read the content. The
2276
2323
# packed_stat should match exactly.
2277
self.assertEqual(entry1_sha, target.get_file_sha1('file1', b'file1-id'))
2278
self.assertEqual(entry2_sha,
2279
target.get_file_sha1('dir/file2', b'file2-id'))
2324
self.assertEqual(entry1_sha, target.get_file_sha1('file1'))
2325
self.assertEqual(entry2_sha, target.get_file_sha1('dir/file2'))
2280
2326
self.assertEqual(entry1_state, entry1[1][0])
2281
2327
self.assertEqual(entry2_state, entry2[1][0])
2316
2362
def test_merge_parents(self):
2317
2363
branch, tt = self.get_branch_and_transform()
2318
rev = tt.commit(branch, 'my message', [b'rev1b', b'rev1c'])
2364
tt.commit(branch, 'my message', [b'rev1b', b'rev1c'])
2319
2365
self.assertEqual([b'rev1b', b'rev1c'],
2320
2366
branch.basis_tree().get_parent_ids()[1:])
2326
2372
tt = TransformPreview(branch.basis_tree())
2327
2373
self.addCleanup(tt.finalize)
2328
2374
tt.new_directory('', ROOT_PARENT, b'TREE_ROOT')
2329
rev = tt.commit(branch, 'my message')
2375
tt.commit(branch, 'my message')
2330
2376
self.assertEqual([], branch.basis_tree().get_parent_ids())
2331
2377
self.assertNotEqual(_mod_revision.NULL_REVISION,
2332
2378
branch.last_revision())
2338
2384
tt = TransformPreview(branch.basis_tree())
2339
2385
self.addCleanup(tt.finalize)
2340
2386
e = self.assertRaises(ValueError, tt.commit, branch,
2341
'my message', [b'rev1b-id'])
2387
'my message', [b'rev1b-id'])
2342
2388
self.assertEqual('Cannot supply merge parents for first commit.',
2344
2390
self.assertEqual(_mod_revision.NULL_REVISION, branch.last_revision())
2349
2395
trans_id = tt.new_directory('dir', tt.root, b'dir-id')
2350
2396
if SymlinkFeature.available():
2351
2397
tt.new_symlink('symlink', trans_id, 'target', b'symlink-id')
2352
rev = tt.commit(branch, 'message')
2398
tt.commit(branch, 'message')
2353
2399
tree = branch.basis_tree()
2354
2400
self.assertEqual('file', tree.id2path(b'file-id'))
2355
self.assertEqual(b'contents', tree.get_file_text('file', b'file-id'))
2401
self.assertEqual(b'contents', tree.get_file_text('file'))
2356
2402
self.assertEqual('dir', tree.id2path(b'dir-id'))
2357
2403
if SymlinkFeature.available():
2358
2404
self.assertEqual('dir/symlink', tree.id2path(b'symlink-id'))
2392
2438
committer='me <me@example.com>',
2393
2439
revprops={u'foo': 'bar'}, revision_id=b'revid-1',
2394
2440
authors=['Author1 <author1@example.com>',
2395
'Author2 <author2@example.com>',
2441
'Author2 <author2@example.com>',
2397
2443
self.assertEqual(b'revid-1', rev_id)
2398
2444
revision = branch.repository.get_revision(rev_id)
2399
2445
self.assertEqual(1, revision.timestamp)
2485
2531
def rename(self, source, target):
2486
2532
if (self.bad_source is not None and
2487
source.endswith(self.bad_source)):
2533
source.endswith(self.bad_source)):
2489
2535
elif (self.bad_target is not None and
2490
target.endswith(self.bad_target)):
2536
target.endswith(self.bad_target)):
2493
2539
_FileMover.rename(self, source, target)
2548
2594
new_globals = dict(func.__globals__)
2549
2595
new_globals.update(globals)
2550
2596
new_func = types.FunctionType(func.__code__, new_globals,
2551
func.__name__, func.__defaults__)
2597
func.__name__, func.__defaults__)
2553
2599
setattr(instance, method_name,
2554
types.MethodType(new_func, instance))
2600
types.MethodType(new_func, instance))
2556
2602
setattr(instance, method_name,
2557
types.MethodType(new_func, instance, instance.__class__))
2603
types.MethodType(new_func, instance, instance.__class__))
2558
2604
self.addCleanup(delattr, instance, method_name)
2587
2633
def test_root_create_file_open_raises_before_creation(self):
2588
2634
tt, trans_id = self.create_transform_and_root_trans_id()
2589
self._override_globals_in_method(tt, "create_file",
2590
{"open": self._fake_open_raises_before})
2591
self.assertRaises(RuntimeError, tt.create_file, [b"contents"], trans_id)
2635
self._override_globals_in_method(
2636
tt, "create_file", {"open": self._fake_open_raises_before})
2637
self.assertRaises(RuntimeError, tt.create_file,
2638
[b"contents"], trans_id)
2592
2639
path = tt._limbo_name(trans_id)
2593
2640
self.assertPathDoesNotExist(path)
2597
2644
def test_root_create_file_open_raises_after_creation(self):
2598
2645
tt, trans_id = self.create_transform_and_root_trans_id()
2599
self._override_globals_in_method(tt, "create_file",
2600
{"open": self._fake_open_raises_after})
2601
self.assertRaises(RuntimeError, tt.create_file, [b"contents"], trans_id)
2646
self._override_globals_in_method(
2647
tt, "create_file", {"open": self._fake_open_raises_after})
2648
self.assertRaises(RuntimeError, tt.create_file,
2649
[b"contents"], trans_id)
2602
2650
path = tt._limbo_name(trans_id)
2603
2651
self.assertPathExists(path)
2608
2656
def test_subdir_create_file_open_raises_before_creation(self):
2609
2657
tt, trans_id = self.create_transform_and_subdir_trans_id()
2610
self._override_globals_in_method(tt, "create_file",
2611
{"open": self._fake_open_raises_before})
2612
self.assertRaises(RuntimeError, tt.create_file, [b"contents"], trans_id)
2658
self._override_globals_in_method(
2659
tt, "create_file", {"open": self._fake_open_raises_before})
2660
self.assertRaises(RuntimeError, tt.create_file,
2661
[b"contents"], trans_id)
2613
2662
path = tt._limbo_name(trans_id)
2614
2663
self.assertPathDoesNotExist(path)
2618
2667
def test_subdir_create_file_open_raises_after_creation(self):
2619
2668
tt, trans_id = self.create_transform_and_subdir_trans_id()
2620
self._override_globals_in_method(tt, "create_file",
2621
{"open": self._fake_open_raises_after})
2622
self.assertRaises(RuntimeError, tt.create_file, [b"contents"], trans_id)
2669
self._override_globals_in_method(
2670
tt, "create_file", {"open": self._fake_open_raises_after})
2671
self.assertRaises(RuntimeError, tt.create_file,
2672
[b"contents"], trans_id)
2623
2673
path = tt._limbo_name(trans_id)
2624
2674
self.assertPathExists(path)
2656
2706
def rename(self, old, new):
2657
2707
raise RuntimeError
2658
2708
self._override_globals_in_method(tt, "_rename_in_limbo",
2659
{"os": FakeOSModule()})
2709
{"os": FakeOSModule()})
2660
2710
self.assertRaises(
2661
2711
RuntimeError, tt.adjust_path, "child1", parent2, child1)
2662
2712
path = osutils.pathjoin(tt._limbo_name(parent1), "child1")
2680
2730
def test_resolve_create_parent_for_versioned_file(self):
2681
2731
wt, tt = self.make_tt_with_versioned_dir()
2682
2732
dir_tid = tt.trans_id_tree_path('dir')
2683
file_tid = tt.new_file('file', dir_tid, [b'Contents'], file_id=b'file-id')
2733
tt.new_file('file', dir_tid, [b'Contents'], file_id=b'file-id')
2684
2734
tt.delete_contents(dir_tid)
2685
2735
tt.unversion_file(dir_tid)
2686
2736
conflicts = resolve_conflicts(tt)
2704
2754
A_ENTRY = (b'a-id', ('a', 'a'), True, (True, True),
2705
(b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2755
(b'TREE_ROOT', b'TREE_ROOT'), ('a', 'a'), ('file', 'file'),
2707
2757
ROOT_ENTRY = (b'TREE_ROOT', ('', ''), False, (True, True), (None, None),
2708
2758
('', ''), ('directory', 'directory'), (False, False))
2743
2793
preview.new_file('file2', preview.root, [b'content B\n'], b'file2-id')
2744
2794
preview_tree = preview.get_preview_tree()
2745
2795
self.assertEqual(preview_tree.kind('file2'), 'file')
2746
with preview_tree.get_file('file2', b'file2-id') as f:
2796
with preview_tree.get_file('file2') as f:
2747
2797
self.assertEqual(f.read(), b'content B\n')
2749
2799
def test_diff_preview_tree(self):
2782
2832
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2783
2833
root = revision_tree.get_root_id()
2784
2834
self.assertEqual([(b'a-id', ('a', 'a'), True, (True, True),
2785
(root, root), ('a', 'a'), ('file', 'file'),
2787
list(preview_tree.iter_changes(revision_tree)))
2835
(root, root), ('a', 'a'), ('file', 'file'),
2837
list(preview_tree.iter_changes(revision_tree)))
2789
2839
def test_include_unchanged_succeeds(self):
2790
2840
revision_tree, preview_tree = self.get_tree_and_preview_tree()
2791
2841
changes = preview_tree.iter_changes(revision_tree,
2792
2842
include_unchanged=True)
2793
root = revision_tree.get_root_id()
2795
2843
self.assertEqual([ROOT_ENTRY, A_ENTRY], list(changes))
2797
2845
def test_specific_files(self):
2839
2887
limbo_path = preview._limbo_name(file_trans_id)
2840
2888
preview_tree = preview.get_preview_tree()
2841
2889
self.assertEqual(os.stat(limbo_path).st_mtime,
2842
preview_tree.get_file_mtime('file', b'file-id'))
2890
preview_tree.get_file_mtime('file'))
2844
2892
def test_get_file_mtime_renamed(self):
2845
2893
work_tree = self.make_branch_and_tree('tree')
2850
2898
file_trans_id = preview.trans_id_tree_path('file')
2851
2899
preview.adjust_path('renamed', preview.root, file_trans_id)
2852
2900
preview_tree = preview.get_preview_tree()
2853
preview_mtime = preview_tree.get_file_mtime('renamed', b'file-id')
2854
work_mtime = work_tree.get_file_mtime('file', b'file-id')
2901
preview_mtime = preview_tree.get_file_mtime('renamed')
2902
work_mtime = work_tree.get_file_mtime('file')
2856
2904
def test_get_file_size(self):
2857
2905
work_tree = self.make_branch_and_tree('tree')
2859
2907
work_tree.add('old', b'old-id')
2860
2908
preview = TransformPreview(work_tree)
2861
2909
self.addCleanup(preview.finalize)
2862
new_id = preview.new_file('name', preview.root, [b'contents'], b'new-id',
2910
preview.new_file('name', preview.root, [b'contents'], b'new-id',
2864
2912
tree = preview.get_preview_tree()
2865
2913
self.assertEqual(len('old'), tree.get_file_size('old'))
2866
2914
self.assertEqual(len('contents'), tree.get_file_size('name'))
2912
2960
preview = TransformPreview(tree)
2913
2961
self.addCleanup(preview.finalize)
2914
2962
preview.new_file('new', preview.trans_id_file_id(b'unchanged-id'),
2915
[b'contents'], b'new-id')
2963
[b'contents'], b'new-id')
2916
2964
preview_tree = preview.get_preview_tree()
2917
2965
self.assertEqual(b'new-id', preview_tree.path2id('unchanged/new'))
3018
3066
def test_file_content_summary_executable(self):
3019
3067
preview = self.get_empty_preview()
3020
path_id = preview.new_file('path', preview.root, [b'contents'], b'path-id')
3068
path_id = preview.new_file('path', preview.root, [
3069
b'contents'], b'path-id')
3021
3070
preview.set_executability(True, path_id)
3022
3071
summary = preview.get_preview_tree().path_content_summary('path')
3023
3072
self.assertEqual(4, len(summary))
3126
3178
file_trans_id = preview.trans_id_file_id(b'file-id')
3127
3179
preview.delete_contents(file_trans_id)
3128
3180
preview_tree = preview.get_preview_tree()
3129
annotation = preview_tree.annotate_iter('file', default_revision=b'me:')
3181
annotation = preview_tree.annotate_iter(
3182
'file', default_revision=b'me:')
3130
3183
self.assertIs(None, annotation)
3132
3185
def test_stored_kind(self):
3197
3250
def test_walkdirs(self):
3198
3251
preview = self.get_empty_preview()
3199
root = preview.new_directory('', ROOT_PARENT, b'tree-root')
3252
preview.new_directory('', ROOT_PARENT, b'tree-root')
3200
3253
# FIXME: new_directory should mark root.
3201
3254
preview.fixup_new_roots()
3202
3255
preview_tree = preview.get_preview_tree()
3203
file_trans_id = preview.new_file('a', preview.root, [b'contents'],
3256
preview.new_file('a', preview.root, [b'contents'], b'a-id')
3205
3257
expected = [(('', b'tree-root'),
3206
[('a', 'a', 'file', None, b'a-id', 'file')])]
3258
[('a', 'a', 'file', None, b'a-id', 'file')])]
3207
3259
self.assertEqual(expected, list(preview_tree.walkdirs()))
3209
3261
def test_extras(self):
3305
3357
self.addCleanup(preview.finalize)
3306
3358
preview.new_file('foo', preview.root, [b'bar'], b'baz-id')
3307
3359
preview_tree = preview.get_preview_tree()
3308
self.assertEqual(False, preview_tree.is_executable('tree/foo', b'baz-id'))
3309
3360
self.assertEqual(False, preview_tree.is_executable('tree/foo'))
3311
3362
def test_commit_preview_tree(self):
3485
3536
attribs = self.default_attribs()
3486
3537
attribs[b'_id_number'] = 2
3487
3538
attribs[b'_non_present_ids'] = {
3489
3540
return self.make_records(attribs, [])
3491
3542
def test_serialize_missing(self):
3492
3543
tt = self.get_preview()
3493
boo_trans_id = tt.trans_id_file_id(b'boo')
3544
tt.trans_id_file_id(b'boo')
3494
3545
self.assertSerializesTo(self.missing_records(), tt)
3496
3547
def test_deserialize_missing(self):
3591
3642
def test_get_parents_lines(self):
3592
3643
LINES_ONE = b'aa\nbb\ncc\ndd\n'
3593
LINES_TWO = b'z\nbb\nx\ndd\n'
3594
3644
tree = self.make_branch_and_tree('tree')
3595
3645
self.build_tree_contents([('tree/file', LINES_ONE)])
3596
3646
tree.add('file', b'file-id')
3597
3647
tt = self.get_preview(tree)
3598
3648
trans_id = tt.trans_id_tree_path('file')
3599
3649
self.assertEqual(([b'aa\n', b'bb\n', b'cc\n', b'dd\n'],),
3600
tt._get_parents_lines(trans_id))
3650
tt._get_parents_lines(trans_id))
3602
3652
def test_get_parents_texts(self):
3603
3653
LINES_ONE = b'aa\nbb\ncc\ndd\n'
3604
LINES_TWO = b'z\nbb\nx\ndd\n'
3605
3654
tree = self.make_branch_and_tree('tree')
3606
3655
self.build_tree_contents([('tree/file', LINES_ONE)])
3607
3656
tree.add('file', b'file-id')
3608
3657
tt = self.get_preview(tree)
3609
3658
trans_id = tt.trans_id_tree_path('file')
3610
3659
self.assertEqual((LINES_ONE,),
3611
tt._get_parents_texts(trans_id))
3660
tt._get_parents_texts(trans_id))
3614
3663
class TestOrphan(tests.TestCaseWithTransport):
3648
3697
self._set_orphan_policy(wt, 'move')
3649
3698
tt, orphan_tid = self._prepare_orphan(wt)
3651
3701
def warning(*args):
3652
3702
warnings.append(args[0] % args[1:])
3653
3703
self.overrideAttr(trace, 'warning', warning)
3654
3704
remaining_conflicts = resolve_conflicts(tt)
3655
3705
self.assertEqual(['dir/foo has been orphaned in brz-orphans'],
3657
3707
# Yeah for resolved conflicts !
3658
3708
self.assertLength(0, remaining_conflicts)
3659
3709
# We have a new orphan
3660
3710
self.assertEqual('foo.~1~', tt.final_name(orphan_tid))
3661
3711
self.assertEqual('brz-orphans',
3662
tt.final_name(tt.final_parent(orphan_tid)))
3712
tt.final_name(tt.final_parent(orphan_tid)))
3664
3714
def test_never_orphan(self):
3665
3715
wt = self.make_branch_and_tree('.')
3717
3768
def test_pre_commit_hooks(self):
3719
3771
def record_pre_transform(tree, tt):
3720
3772
calls.append((tree, tt))
3721
MutableTree.hooks.install_named_hook('pre_transform',
3722
record_pre_transform, "Pre transform")
3773
MutableTree.hooks.install_named_hook(
3774
'pre_transform', record_pre_transform, "Pre transform")
3723
3775
transform, root = self.get_transform()
3724
3776
old_root_id = transform.tree_file_id(root)
3725
3777
transform.apply()
3729
3781
def test_post_commit_hooks(self):
3731
3784
def record_post_transform(tree, tt):
3732
3785
calls.append((tree, tt))
3733
MutableTree.hooks.install_named_hook('post_transform',
3734
record_post_transform, "Post transform")
3786
MutableTree.hooks.install_named_hook(
3787
'post_transform', record_post_transform, "Post transform")
3735
3788
transform, root = self.get_transform()
3736
3789
old_root_id = transform.tree_file_id(root)
3737
3790
transform.apply()