58
58
builder.record_entry_contents(ie, parent_invs, '', tree,
59
59
tree.path_content_summary(''))
61
def test_finish_inventory(self):
61
def test_finish_inventory_with_record_root(self):
62
62
tree = self.make_branch_and_tree(".")
65
65
builder = tree.branch.get_commit_builder([])
66
repo = tree.branch.repository
66
67
self.record_root(builder, tree)
67
68
builder.finish_inventory()
68
tree.branch.repository.commit_write_group()
69
repo.commit_write_group()
73
def test_finish_inventory_record_iter_changes(self):
74
tree = self.make_branch_and_tree(".")
77
builder = tree.branch.get_commit_builder([])
79
builder.record_iter_changes(tree, tree.last_revision(),
80
tree.iter_changes(tree.basis_tree()))
81
builder.finish_inventory()
85
repo = tree.branch.repository
86
repo.commit_write_group()
125
159
self.assertEqual(revision_id,
126
160
tree.branch.repository.get_inventory(revision_id).revision_id)
128
def test_commit_without_root_errors(self):
162
def test_commit_with_revision_id_record_iter_changes(self):
163
tree = self.make_branch_and_tree(".")
166
# use a unicode revision id to test more corner cases.
167
# The repository layer is meant to handle this.
168
revision_id = u'\xc8abc'.encode('utf8')
171
builder = tree.branch.get_commit_builder([],
172
revision_id=revision_id)
173
except errors.NonAsciiRevisionId:
175
builder = tree.branch.get_commit_builder([],
176
revision_id=revision_id)
177
except errors.CannotSetRevisionId:
178
# This format doesn't support supplied revision ids
180
self.assertFalse(builder.random_revid)
182
builder.record_iter_changes(tree, tree.last_revision(),
183
tree.iter_changes(tree.basis_tree()))
184
builder.finish_inventory()
188
builder.finish_inventory()
189
self.assertEqual(revision_id, builder.commit('foo bar'))
192
self.assertTrue(tree.branch.repository.has_revision(revision_id))
193
# the revision id must be set on the inventory when saving it. This
194
# does not precisely test that - a repository that wants to can add it
195
# on deserialisation, but thats all the current contract guarantees
197
self.assertEqual(revision_id,
198
tree.branch.repository.get_inventory(revision_id).revision_id)
200
def test_commit_without_root_or_record_iter_changes_errors(self):
129
201
tree = self.make_branch_and_tree(".")
130
202
tree.lock_write()
283
381
self.addCleanup(rev_tree.unlock)
284
382
self.assertFalse(rev_tree.path2id('foo'))
384
def test_record_delete_record_iter_changes(self):
385
tree = self.make_branch_and_tree(".")
386
self.build_tree(["foo"])
387
tree.add(["foo"], ["foo-id"])
388
rev_id = tree.commit("added foo")
391
builder = tree.branch.get_commit_builder([rev_id])
393
delete_change = ('foo-id', ('foo', None), True, (True, False),
394
(tree.path2id(''), None), ('foo', None), ('file', None),
396
builder.record_iter_changes(tree, rev_id, [delete_change])
397
self.assertEqual(("foo", None, "foo-id", None),
398
builder._basis_delta[0])
399
self.assertTrue(builder.any_changes())
400
builder.finish_inventory()
401
rev_id2 = builder.commit('delete foo')
407
rev_tree = builder.revision_tree()
409
self.addCleanup(rev_tree.unlock)
410
self.assertFalse(rev_tree.path2id('foo'))
286
412
def test_record_delete_without_notification(self):
287
413
tree = self.make_branch_and_tree(".")
288
414
self.build_tree(["foo"])
316
442
self.assertEqual(rev_id, rev_tree.get_revision_id())
317
443
self.assertEqual([], rev_tree.get_parent_ids())
445
def test_revision_tree_record_iter_changes(self):
446
tree = self.make_branch_and_tree(".")
449
builder = tree.branch.get_commit_builder([])
451
builder.record_iter_changes(tree, _mod_revision.NULL_REVISION,
452
tree.iter_changes(tree.basis_tree()))
453
builder.finish_inventory()
454
rev_id = builder.commit('foo bar')
458
rev_tree = builder.revision_tree()
459
# Just a couple simple tests to ensure that it actually follows
460
# the RevisionTree api.
461
self.assertEqual(rev_id, rev_tree.get_revision_id())
462
self.assertEqual([], rev_tree.get_parent_ids())
319
466
def test_root_entry_has_revision(self):
320
467
# test the root revision created and put in the basis
321
468
# has the right rev id.
469
# XXX: RBC 20081118 - this test is too big, it depends on the exact
470
# behaviour of tree methods and so on; it should be written to the
471
# commit builder interface directly.
322
472
tree = self.make_branch_and_tree('.')
323
473
rev_id = tree.commit('message')
324
474
basis_tree = tree.basis_tree()
351
501
self.assertEqual(rev2, tree2.inventory.root.revision)
353
def _add_commit_check_unchanged(self, tree, name):
503
def _add_commit_check_unchanged(self, tree, name, mini_commit=None):
354
504
tree.add([name], [name + 'id'])
355
505
rev1 = tree.commit('')
356
rev2 = self.mini_commit(tree, name, name, False, False)
506
if mini_commit is None:
507
mini_commit = self.mini_commit
508
rev2 = mini_commit(tree, name, name, False, False)
357
509
tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
358
510
self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
359
511
self.assertEqual(rev1, tree2.inventory[name + 'id'].revision)
399
565
os.symlink('target', 'link')
400
566
self._add_commit_check_unchanged(tree, 'link')
568
def test_last_modified_revision_after_commit_link_unchanged_ric(self):
569
# committing without changing a link does not change the last modified.
570
self.requireFeature(tests.SymlinkFeature)
571
tree = self.make_branch_and_tree('.')
572
os.symlink('target', 'link')
573
self._add_commit_check_unchanged(tree, 'link',
574
mini_commit=self.mini_commit_record_iter_changes)
402
576
def _add_commit_renamed_check_changed(self, tree, name,
403
expect_fs_hash=False):
577
expect_fs_hash=False, mini_commit=None):
405
579
tree.rename_one(name, 'new_' + name)
580
if mini_commit is None:
581
mini_commit = self.mini_commit
406
582
self._add_commit_change_check_changed(tree, name, rename,
407
expect_fs_hash=expect_fs_hash)
583
expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
409
585
def test_last_modified_revision_after_rename_dir_changes(self):
410
586
# renaming a dir changes the last modified.
426
617
os.symlink('target', 'link')
427
618
self._add_commit_renamed_check_changed(tree, 'link')
620
def test_last_modified_revision_after_rename_link_changes_ric(self):
621
# renaming a link changes the last modified.
622
self.requireFeature(tests.SymlinkFeature)
623
tree = self.make_branch_and_tree('.')
624
os.symlink('target', 'link')
625
self._add_commit_renamed_check_changed(tree, 'link',
626
mini_commit=self.mini_commit_record_iter_changes)
429
628
def _add_commit_reparent_check_changed(self, tree, name,
430
expect_fs_hash=False):
629
expect_fs_hash=False, mini_commit=None):
431
630
self.build_tree(['newparent/'])
432
631
tree.add(['newparent'])
434
633
tree.rename_one(name, 'newparent/new_' + name)
435
634
self._add_commit_change_check_changed(tree, name, reparent,
436
expect_fs_hash=expect_fs_hash)
635
expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
438
637
def test_last_modified_revision_after_reparent_dir_changes(self):
439
638
# reparenting a dir changes the last modified.
455
669
os.symlink('target', 'link')
456
670
self._add_commit_reparent_check_changed(tree, 'link')
672
def test_last_modified_revision_after_reparent_link_changes_ric(self):
673
# reparenting a link changes the last modified.
674
self.requireFeature(tests.SymlinkFeature)
675
tree = self.make_branch_and_tree('.')
676
os.symlink('target', 'link')
677
self._add_commit_reparent_check_changed(tree, 'link',
678
mini_commit=self.mini_commit_record_iter_changes)
458
680
def _add_commit_change_check_changed(self, tree, name, changer,
459
expect_fs_hash=False):
681
expect_fs_hash=False, mini_commit=None):
460
682
tree.add([name], [name + 'id'])
461
683
rev1 = tree.commit('')
463
rev2 = self.mini_commit(tree, name, tree.id2path(name + 'id'),
685
if mini_commit is None:
686
mini_commit = self.mini_commit
687
rev2 = mini_commit(tree, name, tree.id2path(name + 'id'),
464
688
expect_fs_hash=expect_fs_hash)
465
689
tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
466
690
self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
776
def mini_commit_record_iter_changes(self, tree, name, new_name,
777
records_version=True, delta_against_basis=True, expect_fs_hash=False):
778
"""Perform a miniature commit looking for record entry results.
780
This version uses the record_iter_changes interface.
782
:param tree: The tree to commit.
783
:param name: The path in the basis tree of the tree being committed.
784
:param new_name: The path in the tree being committed.
785
:param records_version: True if the commit of new_name is expected to
786
record a new version.
787
:param delta_against_basis: True of the commit of new_name is expected
788
to have a delta against the basis.
789
:param expect_fs_hash: ignored, present for compatibility with test
790
driver code for 'mini_commit'.
794
# mini manual commit here so we can check the return of
795
# record_entry_contents.
796
parent_ids = tree.get_parent_ids()
797
builder = tree.branch.get_commit_builder(parent_ids)
798
parent_tree = tree.basis_tree()
799
parent_tree.lock_read()
800
self.addCleanup(parent_tree.unlock)
801
parent_invs = [parent_tree.inventory]
802
for parent_id in parent_ids[1:]:
803
parent_invs.append(tree.branch.repository.revision_tree(
804
parent_id).inventory)
805
changes = list(tree.iter_changes(parent_tree))
806
builder.record_iter_changes(tree, parent_ids[0], changes)
807
delta = builder._basis_delta
808
delta_dict = dict((change[2], change) for change in delta)
809
file_id = tree.path2id(new_name)
810
version_recorded = (file_id in delta_dict and
811
delta_dict[file_id][3] is not None and
812
delta_dict[file_id][3].revision == builder._new_revision_id)
814
self.assertTrue(version_recorded)
816
self.assertFalse(version_recorded)
817
builder.finish_inventory()
818
new_inventory = builder.revision_tree().inventory
819
new_entry = new_inventory[file_id]
820
if delta_against_basis:
821
expected_delta = (name, new_name, file_id, new_entry)
822
self.assertEqual(expected_delta, delta_dict[file_id])
824
expected_delta = None
825
self.assertFalse(version_recorded)
826
rev2 = builder.commit('')
827
tree.set_parent_ids([rev2])
552
836
def assertFileGraph(self, expected_graph, tree, tip):
553
837
# all the changes that have occured should be in the ancestry
554
838
# (closest to a public per-file graph API we have today)
585
890
tree.rename_one(name, 'new_' + name)
586
891
return tree.commit('')
588
def _commit_sprout_rename_merge(self, tree1, name, expect_fs_hash=False):
893
def _commit_sprout_rename_merge(self, tree1, name, expect_fs_hash=False,
895
"""Do a rename in both trees."""
589
896
rev1, tree2 = self._commit_sprout(tree1, name)
590
897
# change both sides equally
591
898
rev2 = self._rename_in_tree(tree1, name)
592
899
rev3 = self._rename_in_tree(tree2, name)
593
900
tree1.merge_from_branch(tree2.branch)
594
rev4 = self.mini_commit(tree1, 'new_' + name, 'new_' + name,
901
if mini_commit is None:
902
mini_commit = self.mini_commit
903
rev4 = mini_commit(tree1, 'new_' + name, 'new_' + name,
595
904
expect_fs_hash=expect_fs_hash)
596
905
tree3, = self._get_revtrees(tree1, [rev4])
597
906
self.assertEqual(rev4, tree3.inventory[name + 'id'].revision)
609
918
self.build_tree(['t1/dir/'])
610
919
self._commit_sprout_rename_merge(tree1, 'dir')
921
def test_last_modified_revision_after_merge_dir_changes_ric(self):
922
# merge a dir changes the last modified.
923
tree1 = self.make_branch_and_tree('t1')
924
self.build_tree(['t1/dir/'])
925
self._commit_sprout_rename_merge(tree1, 'dir',
926
mini_commit=self.mini_commit_record_iter_changes)
612
928
def test_last_modified_revision_after_merge_file_changes(self):
613
929
# merge a file changes the last modified.
614
930
tree1 = self.make_branch_and_tree('t1')
615
931
self.build_tree(['t1/file'])
616
932
self._commit_sprout_rename_merge(tree1, 'file', expect_fs_hash=True)
934
def test_last_modified_revision_after_merge_file_changes_ric(self):
935
# merge a file changes the last modified.
936
tree1 = self.make_branch_and_tree('t1')
937
self.build_tree(['t1/file'])
938
self._commit_sprout_rename_merge(tree1, 'file', expect_fs_hash=True,
939
mini_commit=self.mini_commit_record_iter_changes)
618
941
def test_last_modified_revision_after_merge_link_changes(self):
619
942
# merge a link changes the last modified.
620
943
self.requireFeature(tests.SymlinkFeature)
622
945
os.symlink('target', 't1/link')
623
946
self._commit_sprout_rename_merge(tree1, 'link')
625
def _commit_sprout_rename_merge_converged(self, tree1, name):
948
def test_last_modified_revision_after_merge_link_changes_ric(self):
949
# merge a link changes the last modified.
950
self.requireFeature(tests.SymlinkFeature)
951
tree1 = self.make_branch_and_tree('t1')
952
os.symlink('target', 't1/link')
953
self._commit_sprout_rename_merge(tree1, 'link',
954
mini_commit=self.mini_commit_record_iter_changes)
956
def _commit_sprout_rename_merge_converged(self, tree1, name,
958
# Make a merge which just incorporates a change from a branch:
959
# The per-file graph is straight line, and no alteration occurs
626
961
rev1, tree2 = self._commit_sprout(tree1, name)
627
962
# change on the other side to merge back
628
963
rev2 = self._rename_in_tree(tree2, name)
629
964
tree1.merge_from_branch(tree2.branch)
630
rev3 = self.mini_commit(tree1, name, 'new_' + name, False)
965
if mini_commit is None:
966
mini_commit = self.mini_commit
967
rev3 = mini_commit(tree1, name, 'new_' + name, False)
631
968
tree3, = self._get_revtrees(tree1, [rev2])
632
969
self.assertEqual(rev2, tree3.inventory[name + 'id'].revision)
633
970
file_id = name + 'id'
636
973
expected_graph[(file_id, rev2)] = ((file_id, rev1),)
637
974
self.assertFileGraph(expected_graph, tree1, (file_id, rev2))
639
def test_last_modified_revision_after_converged_merge_dir_changes(self):
640
# merge a dir changes the last modified.
976
def _commit_sprout_make_merge(self, tree1, make, mini_commit=None):
977
# Make a merge which incorporates the addition of a new object to
978
# another branch. The per-file graph shows no additional change
979
# in the merge because its a straight line.
980
rev1 = tree1.commit('')
981
tree2 = tree1.bzrdir.sprout('t2').open_workingtree()
982
# make and commit on the other side to merge back
985
tree2.add(['name'], [file_id])
986
rev2 = tree2.commit('')
987
tree1.merge_from_branch(tree2.branch)
988
if mini_commit is None:
989
mini_commit = self.mini_commit
990
rev3 = mini_commit(tree1, None, 'name', False)
991
tree3, = self._get_revtrees(tree1, [rev2])
992
# in rev2, name should be only changed in rev2
993
self.assertEqual(rev2, tree3.inventory[file_id].revision)
995
expected_graph[(file_id, rev2)] = ()
996
self.assertFileGraph(expected_graph, tree1, (file_id, rev2))
998
def test_last_modified_revision_after_converged_merge_dir_unchanged(self):
999
# merge a dir that changed preserves the last modified.
641
1000
tree1 = self.make_branch_and_tree('t1')
642
1001
self.build_tree(['t1/dir/'])
643
1002
self._commit_sprout_rename_merge_converged(tree1, 'dir')
645
def test_last_modified_revision_after_converged_merge_file_changes(self):
646
# merge a file changes the last modified.
1004
def test_last_modified_revision_after_converged_merge_dir_unchanged_ric(self):
1005
# merge a dir that changed preserves the last modified.
1006
tree1 = self.make_branch_and_tree('t1')
1007
self.build_tree(['t1/dir/'])
1008
self._commit_sprout_rename_merge_converged(tree1, 'dir',
1009
mini_commit=self.mini_commit_record_iter_changes)
1011
def test_last_modified_revision_after_converged_merge_file_unchanged(self):
1012
# merge a file that changed preserves the last modified.
647
1013
tree1 = self.make_branch_and_tree('t1')
648
1014
self.build_tree(['t1/file'])
649
1015
self._commit_sprout_rename_merge_converged(tree1, 'file')
651
def test_last_modified_revision_after_converged_merge_link_changes(self):
652
# merge a link changes the last modified.
1017
def test_last_modified_revision_after_converged_merge_file_unchanged_ric(self):
1018
# merge a file that changed preserves the last modified.
1019
tree1 = self.make_branch_and_tree('t1')
1020
self.build_tree(['t1/file'])
1021
self._commit_sprout_rename_merge_converged(tree1, 'file',
1022
mini_commit=self.mini_commit_record_iter_changes)
1024
def test_last_modified_revision_after_converged_merge_link_unchanged(self):
1025
# merge a link that changed preserves the last modified.
653
1026
self.requireFeature(tests.SymlinkFeature)
654
1027
tree1 = self.make_branch_and_tree('t1')
655
1028
os.symlink('target', 't1/link')
656
1029
self._commit_sprout_rename_merge_converged(tree1, 'link')
1031
def test_last_modified_revision_after_converged_merge_link_unchanged_ric(self):
1032
# merge a link that changed preserves the last modified.
1033
self.requireFeature(tests.SymlinkFeature)
1034
tree1 = self.make_branch_and_tree('t1')
1035
os.symlink('target', 't1/link')
1036
self._commit_sprout_rename_merge_converged(tree1, 'link',
1037
mini_commit=self.mini_commit_record_iter_changes)
1039
def test_last_modified_revision_after_merge_new_dir_unchanged(self):
1040
# merge a new dir does not change the last modified.
1041
tree1 = self.make_branch_and_tree('t1')
1042
self._commit_sprout_make_merge(tree1, self.make_dir)
1044
def test_last_modified_revision_after_merge_new_dir_unchanged_ric(self):
1045
# merge a new dir does not change the last modified.
1046
tree1 = self.make_branch_and_tree('t1')
1047
self._commit_sprout_make_merge(tree1, self.make_dir,
1048
mini_commit=self.mini_commit_record_iter_changes)
1050
def test_last_modified_revision_after_merge_new_file_unchanged(self):
1051
# merge a new file does not change the last modified.
1052
tree1 = self.make_branch_and_tree('t1')
1053
self._commit_sprout_make_merge(tree1, self.make_file)
1055
def test_last_modified_revision_after_merge_new_file_unchanged_ric(self):
1056
# merge a new file does not change the last modified.
1057
tree1 = self.make_branch_and_tree('t1')
1058
self._commit_sprout_make_merge(tree1, self.make_file,
1059
mini_commit=self.mini_commit_record_iter_changes)
1061
def test_last_modified_revision_after_merge_new_link_unchanged(self):
1062
# merge a new link does not change the last modified.
1063
tree1 = self.make_branch_and_tree('t1')
1064
self._commit_sprout_make_merge(tree1, self.make_link)
1066
def test_last_modified_revision_after_merge_new_link_unchanged_ric(self):
1067
# merge a new link does not change the last modified.
1068
tree1 = self.make_branch_and_tree('t1')
1069
self._commit_sprout_make_merge(tree1, self.make_link,
1070
mini_commit=self.mini_commit_record_iter_changes)
658
1072
def make_dir(self, name):
659
1073
self.build_tree([name + '/'])
675
1090
make_after(path)
677
1092
self._add_commit_change_check_changed(tree, path, change_kind,
678
expect_fs_hash=expect_fs_hash)
1093
expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
680
1095
def test_last_modified_dir_file(self):
681
1096
self._check_kind_change(self.make_dir, self.make_file,
682
1097
expect_fs_hash=True)
1099
def test_last_modified_dir_file_ric(self):
1100
self._check_kind_change(self.make_dir, self.make_file,
1101
expect_fs_hash=True,
1102
mini_commit=self.mini_commit_record_iter_changes)
684
1104
def test_last_modified_dir_link(self):
685
1105
self._check_kind_change(self.make_dir, self.make_link)
1107
def test_last_modified_dir_link_ric(self):
1108
self._check_kind_change(self.make_dir, self.make_link,
1109
mini_commit=self.mini_commit_record_iter_changes)
687
1111
def test_last_modified_link_file(self):
688
1112
self._check_kind_change(self.make_link, self.make_file,
689
1113
expect_fs_hash=True)
1115
def test_last_modified_link_file_ric(self):
1116
self._check_kind_change(self.make_link, self.make_file,
1117
expect_fs_hash=True,
1118
mini_commit=self.mini_commit_record_iter_changes)
691
1120
def test_last_modified_link_dir(self):
692
1121
self._check_kind_change(self.make_link, self.make_dir)
1123
def test_last_modified_link_dir_ric(self):
1124
self._check_kind_change(self.make_link, self.make_dir,
1125
mini_commit=self.mini_commit_record_iter_changes)
694
1127
def test_last_modified_file_dir(self):
695
1128
self._check_kind_change(self.make_file, self.make_dir)
1130
def test_last_modified_file_dir_ric(self):
1131
self._check_kind_change(self.make_file, self.make_dir,
1132
mini_commit=self.mini_commit_record_iter_changes)
697
1134
def test_last_modified_file_link(self):
698
1135
self._check_kind_change(self.make_file, self.make_link)
1137
def test_last_modified_file_link_ric(self):
1138
self._check_kind_change(self.make_file, self.make_link,
1139
mini_commit=self.mini_commit_record_iter_changes)
700
1141
def test_get_commit_builder_with_invalid_revprops(self):
701
1142
branch = self.make_branch('.')
702
1143
branch.repository.lock_write()