50
50
def test_finish_inventory_record_iter_changes(self):
51
51
tree = self.make_branch_and_tree(".")
52
with tree.lock_write():
54
53
builder = tree.branch.get_commit_builder([])
56
55
list(builder.record_iter_changes(tree, tree.last_revision(),
57
tree.iter_changes(tree.basis_tree())))
56
tree.iter_changes(tree.basis_tree())))
58
57
builder.finish_inventory()
62
61
repo = tree.branch.repository
63
62
repo.commit_write_group()
67
64
def test_abort_record_iter_changes(self):
68
65
tree = self.make_branch_and_tree(".")
66
with tree.lock_write():
71
67
builder = tree.branch.get_commit_builder([])
73
69
basis = tree.basis_tree()
77
73
builder.finish_inventory()
83
77
def test_commit_lossy(self):
84
78
tree = self.make_branch_and_tree(".")
79
with tree.lock_write():
87
80
builder = tree.branch.get_commit_builder([], lossy=True)
88
81
list(builder.record_iter_changes(tree, tree.last_revision(),
89
tree.iter_changes(tree.basis_tree())))
82
tree.iter_changes(tree.basis_tree())))
90
83
builder.finish_inventory()
91
84
rev_id = builder.commit('foo bar blah')
94
85
rev = tree.branch.repository.get_revision(rev_id)
95
86
self.assertEqual('foo bar blah', rev.message)
97
88
def test_commit_message(self):
98
89
tree = self.make_branch_and_tree(".")
90
with tree.lock_write():
101
91
builder = tree.branch.get_commit_builder([])
102
92
list(builder.record_iter_changes(tree, tree.last_revision(),
103
tree.iter_changes(tree.basis_tree())))
93
tree.iter_changes(tree.basis_tree())))
104
94
builder.finish_inventory()
105
95
rev_id = builder.commit('foo bar blah')
108
96
rev = tree.branch.repository.get_revision(rev_id)
109
97
self.assertEqual('foo bar blah', rev.message)
111
99
def test_updates_branch(self):
112
100
tree = self.make_branch_and_tree(".")
101
with tree.lock_write():
115
102
builder = tree.branch.get_commit_builder([])
116
103
list(builder.record_iter_changes(tree, tree.last_revision(),
117
tree.iter_changes(tree.basis_tree())))
104
tree.iter_changes(tree.basis_tree())))
118
105
builder.finish_inventory()
119
106
will_update_branch = builder.updates_branch
120
107
rev_id = builder.commit('might update the branch')
123
108
actually_updated_branch = (tree.branch.last_revision() == rev_id)
124
109
self.assertEqual(actually_updated_branch, will_update_branch)
126
111
def test_commit_with_revision_id_record_iter_changes(self):
127
112
tree = self.make_branch_and_tree(".")
113
with tree.lock_write():
130
114
# use a unicode revision id to test more corner cases.
131
115
# The repository layer is meant to handle this.
132
116
revision_id = u'\xc8abc'.encode('utf8')
135
119
builder = tree.branch.get_commit_builder([],
136
revision_id=revision_id)
120
revision_id=revision_id)
137
121
except errors.NonAsciiRevisionId:
138
122
revision_id = b'abc'
139
123
builder = tree.branch.get_commit_builder([],
140
revision_id=revision_id)
124
revision_id=revision_id)
141
125
except repository.CannotSetRevisionId:
142
126
# This format doesn't support supplied revision ids
144
128
self.assertFalse(builder.random_revid)
146
130
list(builder.record_iter_changes(tree, tree.last_revision(),
147
tree.iter_changes(tree.basis_tree())))
131
tree.iter_changes(tree.basis_tree())))
148
132
builder.finish_inventory()
152
136
self.assertEqual(revision_id, builder.commit('foo bar'))
155
137
self.assertTrue(tree.branch.repository.has_revision(revision_id))
156
138
# the revision id must be set on the inventory when saving it. This
157
139
# does not precisely test that - a repository that wants to can add it
158
140
# on deserialisation, but thats all the current contract guarantees
160
self.assertEqual(revision_id,
161
144
tree.branch.repository.revision_tree(revision_id).get_revision_id())
163
146
def test_commit_without_root_errors(self):
164
147
tree = self.make_branch_and_tree(".")
148
with tree.lock_write():
167
149
builder = tree.branch.get_commit_builder([])
170
153
list(builder.record_iter_changes(
209
190
tree.add(["foo"])
210
191
foo_id = tree.path2id('foo')
211
192
rev_id = tree.commit("added foo")
193
with tree.lock_write():
214
194
builder = tree.branch.get_commit_builder([rev_id])
216
196
delete_change = (foo_id, ('foo', None), True, (True, False),
217
(tree.path2id(''), None), ('foo', None), ('file', None),
197
(tree.path2id(''), None), ('foo',
198
None), ('file', None),
219
200
list(builder.record_iter_changes(tree, rev_id,
221
202
self.assertEqual(("foo", None, foo_id, None),
222
builder.get_basis_delta()[0])
203
builder.get_basis_delta()[0])
223
204
self.assertTrue(builder.any_changes())
224
205
builder.finish_inventory()
225
206
rev_id2 = builder.commit('delete foo')
231
210
rev_tree = builder.revision_tree()
232
211
rev_tree.lock_read()
233
212
self.addCleanup(rev_tree.unlock)
236
215
def test_revision_tree_record_iter_changes(self):
237
216
tree = self.make_branch_and_tree(".")
217
with tree.lock_write():
240
218
builder = tree.branch.get_commit_builder([])
242
220
list(builder.record_iter_changes(tree,
243
_mod_revision.NULL_REVISION,
244
tree.iter_changes(tree.basis_tree())))
221
_mod_revision.NULL_REVISION,
222
tree.iter_changes(tree.basis_tree())))
245
223
builder.finish_inventory()
246
224
rev_id = builder.commit('foo bar')
266
242
basis_tree = tree.basis_tree()
267
243
basis_tree.lock_read()
268
244
self.addCleanup(basis_tree.unlock)
269
self.assertEqual(rev_id,
270
basis_tree.get_file_revision(u'', basis_tree.get_root_id()))
245
self.assertEqual(rev_id, basis_tree.get_file_revision(u''))
272
247
def _get_revtrees(self, tree, revision_ids):
248
with tree.lock_read():
275
249
trees = list(tree.branch.repository.revision_trees(revision_ids))
276
250
for _tree in trees:
277
251
_tree.lock_read()
278
252
self.addCleanup(_tree.unlock)
283
255
def test_last_modified_revision_after_commit_root_unchanged(self):
284
256
# commiting without changing the root does not change the
300
272
def _commit_check_unchanged(self, tree, name, file_id):
301
273
rev1 = tree.commit('rev1')
302
rev2 = self.mini_commit_record_iter_changes(tree, name, name, False, False)
274
rev2 = self.mini_commit_record_iter_changes(
275
tree, name, name, False, False)
303
276
tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
304
277
self.assertEqual(rev1, tree1.get_file_revision(name))
305
278
self.assertEqual(rev1, tree2.get_file_revision(name))
356
329
tree.add_reference(subtree)
357
330
self._commit_check_unchanged(tree, 'reference',
358
subtree.get_root_id())
331
subtree.get_root_id())
359
332
except errors.UnsupportedOperation:
362
335
def _add_commit_renamed_check_changed(self, tree, name,
363
expect_fs_hash=False):
336
expect_fs_hash=False):
365
338
tree.rename_one(name, 'new_' + name)
366
339
self._add_commit_change_check_changed(tree,
367
(name, 'new_' + name), rename,
368
expect_fs_hash=expect_fs_hash)
340
(name, 'new_' + name), rename,
341
expect_fs_hash=expect_fs_hash)
370
343
def _commit_renamed_check_changed(self, tree, name,
371
expect_fs_hash=False):
344
expect_fs_hash=False):
373
346
tree.rename_one(name, 'new_' + name)
374
347
self._commit_change_check_changed(tree, [name, 'new_' + name],
375
rename, expect_fs_hash=expect_fs_hash)
348
rename, expect_fs_hash=expect_fs_hash)
377
350
def test_last_modified_revision_after_rename_dir_changes(self):
378
351
# renaming a dir changes the last modified.
379
352
tree = self.make_branch_and_tree('.')
380
353
if not tree.has_versioned_directories():
381
354
raise tests.TestNotApplicable(
382
'Format does not support versioned directories')
355
'Format does not support versioned directories')
383
356
self.build_tree(['dir/'])
384
357
self._add_commit_renamed_check_changed(tree, 'dir')
411
384
def _add_commit_reparent_check_changed(self, tree, name,
412
expect_fs_hash=False):
385
expect_fs_hash=False):
413
386
self.build_tree(['newparent/'])
414
387
tree.add(['newparent'])
416
390
tree.rename_one(name, 'newparent/new_' + name)
417
391
self._add_commit_change_check_changed(
418
tree, (name, 'newparent/new_' + name), reparent,
392
tree, (name, 'newparent/new_' + name), reparent,
419
393
expect_fs_hash=expect_fs_hash)
421
395
def test_last_modified_revision_after_reparent_dir_changes(self):
454
428
rev1 = tree.commit('rev1')
456
430
rev2 = self.mini_commit_record_iter_changes(
457
tree, names[0], names[1], expect_fs_hash=expect_fs_hash)
431
tree, names[0], names[1], expect_fs_hash=expect_fs_hash)
458
432
tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
459
433
self.assertEqual(rev1, tree1.get_file_revision(names[0]))
460
434
self.assertEqual(rev2, tree2.get_file_revision(names[1]))
465
439
self.assertFileGraph(expected_graph, tree, (file_id, rev2))
467
441
def mini_commit_record_iter_changes(self, tree, name, new_name,
468
records_version=True, delta_against_basis=True, expect_fs_hash=False):
442
records_version=True,
443
delta_against_basis=True,
444
expect_fs_hash=False):
469
445
"""Perform a miniature commit looking for record entry results.
471
447
This version uses the record_iter_changes interface.
501
477
tree_file_stat[0].close()
502
478
self.assertLength(1, result)
503
479
result = result[0]
504
self.assertEqual(result[:2], (file_id, new_name))
505
self.assertEqual(result[2][0], tree.get_file_sha1(new_name))
506
self.assertEqualStat(result[2][1], tree_file_stat[1])
480
self.assertEqual(result[0], new_name)
482
result[1][0], tree.get_file_sha1(new_name))
483
self.assertEqualStat(result[1][1], tree_file_stat[1])
508
485
self.assertEqual([], result)
509
486
builder.finish_inventory()
510
487
if tree.branch.repository._format.supports_full_versioned_files:
511
488
inv_key = (builder._new_revision_id,)
512
489
inv_sha1 = tree.branch.repository.inventories.get_sha1s(
514
491
self.assertEqual(inv_sha1, builder.inv_sha1)
515
492
rev2 = builder.commit('rev2')
516
493
except BaseException:
519
496
delta = builder.get_basis_delta()
520
497
delta_dict = dict((change[2], change) for change in delta)
521
498
if tree.branch.repository._format.records_per_file_revision:
522
version_recorded = (file_id in delta_dict and
523
delta_dict[file_id][3] is not None and
524
delta_dict[file_id][3].revision == rev2)
499
version_recorded = (file_id in delta_dict
500
and delta_dict[file_id][3] is not None
501
and delta_dict[file_id][3].revision == rev2)
525
502
if records_version:
526
503
self.assertTrue(version_recorded)
528
505
self.assertFalse(version_recorded)
530
507
revtree = builder.revision_tree()
531
new_entry = next(revtree.iter_entries_by_dir(specific_files=[new_name]))[1]
508
new_entry = next(revtree.iter_entries_by_dir(
509
specific_files=[new_name]))[1]
533
511
if delta_against_basis:
534
512
if tree.supports_rename_tracking() or name == new_name:
555
533
# altering a file changes the last modified.
556
534
tree = self.make_branch_and_tree('.')
557
535
self.build_tree(['file'])
558
537
def change_file():
559
538
tree.put_file_bytes_non_atomic('file', b'new content')
560
539
self._add_commit_change_check_changed(tree, ('file', 'file'), change_file,
563
542
def _test_last_mod_rev_after_content_link_changes(
564
self, link, target, newtarget):
543
self, link, target, newtarget):
565
544
# changing a link changes the last modified.
566
545
self.requireFeature(features.SymlinkFeature)
567
546
tree = self.make_branch_and_tree('.')
568
547
os.symlink(target, link)
569
549
def change_link():
571
551
os.symlink(newtarget, link)
599
579
rev2 = self._rename_in_tree(tree1, name, 'rev2')
600
580
rev3 = self._rename_in_tree(tree2, name, 'rev3')
601
581
tree1.merge_from_branch(tree2.branch)
602
rev4 = self.mini_commit_record_iter_changes(tree1, 'new_' + name, 'new_' + name,
582
rev4 = self.mini_commit_record_iter_changes(
583
tree1, 'new_' + name, 'new_' + name,
603
584
expect_fs_hash=expect_fs_hash,
604
585
delta_against_basis=tree1.supports_rename_tracking())
605
586
tree3, = self._get_revtrees(tree1, [rev4])
609
590
expected_graph[(file_id, rev1)] = ()
610
591
expected_graph[(file_id, rev2)] = ((file_id, rev1),)
611
592
expected_graph[(file_id, rev3)] = ((file_id, rev1),)
612
expected_graph[(file_id, rev4)] = ((file_id, rev2), (file_id, rev3),)
593
expected_graph[(file_id, rev4)] = (
594
(file_id, rev2), (file_id, rev3),)
614
596
self.assertEqual(rev2, tree3.get_file_revision('new_' + name))
615
597
expected_graph[(file_id, rev4)] = ()
648
630
# change on the other side to merge back
649
631
rev2 = self._rename_in_tree(tree2, name, 'rev2')
650
632
tree1.merge_from_branch(tree2.branch)
651
634
def _check_graph(in_tree, changed_in_tree):
652
635
rev3 = self.mini_commit_record_iter_changes(
653
in_tree, name, 'new_' + name, False,
654
delta_against_basis=changed_in_tree)
636
in_tree, name, 'new_' + name, False,
637
delta_against_basis=changed_in_tree)
655
638
tree3, = self._get_revtrees(in_tree, [rev2])
658
tree3.get_file_revision('new_' + name, file_id))
639
self.assertEqual(rev2, tree3.get_file_revision('new_' + name))
659
640
expected_graph = {}
660
641
expected_graph[(file_id, rev1)] = ()
661
642
expected_graph[(file_id, rev2)] = ((file_id, rev1),)
820
801
branch.repository.lock_write()
821
802
self.addCleanup(branch.repository.unlock)
822
803
self.assertRaises(ValueError, branch.repository.get_commit_builder,
823
branch, [], branch.get_config_stack(),
824
revprops={'invalid': u'property\rwith\r\ninvalid chars'})
804
branch, [], branch.get_config_stack(),
805
revprops={'invalid': u'property\rwith\r\ninvalid chars'})
826
807
def test_commit_builder_commit_with_invalid_message(self):
827
808
branch = self.make_branch('.')
828
809
branch.repository.lock_write()
829
810
self.addCleanup(branch.repository.unlock)
830
811
builder = branch.repository.get_commit_builder(branch, [],
831
branch.get_config_stack())
812
branch.get_config_stack())
832
813
self.addCleanup(branch.repository.abort_write_group)
833
814
self.assertRaises(ValueError, builder.commit,
834
u'Invalid\r\ncommit message\r\n')
815
u'Invalid\r\ncommit message\r\n')
836
817
def test_non_ascii_str_committer_rejected(self):
837
818
"""Ensure an error is raised on a non-ascii byte string committer"""
839
820
branch.repository.lock_write()
840
821
self.addCleanup(branch.repository.unlock)
841
822
self.assertRaises(UnicodeDecodeError,
842
branch.repository.get_commit_builder,
843
branch, [], branch.get_config_stack(),
844
committer=b"Erik B\xe5gfors <erik@example.com>")
823
branch.repository.get_commit_builder,
824
branch, [], branch.get_config_stack(),
825
committer=b"Erik B\xe5gfors <erik@example.com>")
846
827
def test_stacked_repositories_reject_commit_builder(self):
847
828
# As per bug 375013, committing to stacked repositories is currently
857
838
self.addCleanup(repo_local.lock_write().unlock)
858
839
if not repo_local._format.supports_chks:
859
840
self.assertRaises(errors.BzrError, repo_local.get_commit_builder,
860
branch, [], branch.get_config_stack())
841
branch, [], branch.get_config_stack())
862
843
builder = repo_local.get_commit_builder(branch, [],
863
844
branch.get_config_stack())