/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2006 Canonical Ltd
1740.3.1 by Jelmer Vernooij
Introduce and use CommitBuilder objects.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
"""Tests for repository commit builder."""
18
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
19
from copy import copy
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
20
import errno
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
21
import os
2804.4.2 by Alexander Belchenko
win32-specific fix for removing file/link/dir
22
import sys
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
23
24
from bzrlib import (
25
    errors,
26
    inventory,
27
    osutils,
28
    repository,
3668.5.1 by Jelmer Vernooij
Use NULL_REVISION rather than None for Repository.revision_tree().
29
    revision as _mod_revision,
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
30
    tests,
31
    )
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
32
from bzrlib.graph import Graph
3689.1.1 by John Arbash Meinel
Rename repository_implementations tests into per_repository tests
33
from bzrlib.tests.per_repository import test_repository
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
34
35
36
class TestCommitBuilder(test_repository.TestCaseWithRepository):
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
37
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
38
    def test_get_commit_builder(self):
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
39
        branch = self.make_branch('.')
40
        branch.repository.lock_write()
41
        builder = branch.repository.get_commit_builder(
42
            branch, [], branch.get_config())
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
43
        self.assertIsInstance(builder, repository.CommitBuilder)
2805.6.1 by Robert Collins
Set random_revid on CommitBuilder when a commit generated its own revision id.
44
        self.assertTrue(builder.random_revid)
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
45
        branch.repository.commit_write_group()
46
        branch.repository.unlock()
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
47
1910.2.6 by Aaron Bentley
Update for merge review, handle deprecations
48
    def record_root(self, builder, tree):
49
        if builder.record_root_entry is True:
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
50
            tree.lock_read()
51
            try:
52
                ie = tree.inventory.root
53
            finally:
54
                tree.unlock()
3668.5.1 by Jelmer Vernooij
Use NULL_REVISION rather than None for Repository.revision_tree().
55
            parent_tree = tree.branch.repository.revision_tree(
56
                              _mod_revision.NULL_REVISION)
1910.2.22 by Aaron Bentley
Make commits preserve root entry data
57
            parent_invs = []
2776.4.4 by Robert Collins
Move content summary generation outside of record_entry_contents.
58
            builder.record_entry_contents(ie, parent_invs, '', tree,
59
                tree.path_content_summary(''))
1731.1.33 by Aaron Bentley
Revert no-special-root changes
60
3775.2.4 by Robert Collins
Start on a CommitBuilder.record_iter_changes method.
61
    def test_finish_inventory_with_record_root(self):
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
62
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
63
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
64
        try:
65
            builder = tree.branch.get_commit_builder([])
3775.2.4 by Robert Collins
Start on a CommitBuilder.record_iter_changes method.
66
            repo = tree.branch.repository
2617.6.8 by Robert Collins
Review feedback and documentation.
67
            self.record_root(builder, tree)
68
            builder.finish_inventory()
3775.2.4 by Robert Collins
Start on a CommitBuilder.record_iter_changes method.
69
            repo.commit_write_group()
70
        finally:
71
            tree.unlock()
72
73
    def test_finish_inventory_record_iter_changes(self):
74
        tree = self.make_branch_and_tree(".")
75
        tree.lock_write()
76
        try:
77
            builder = tree.branch.get_commit_builder([])
78
            try:
3775.2.30 by Robert Collins
Remove the basis_tree parameter to record_iter_changes.
79
                builder.record_iter_changes(tree, tree.last_revision(),
80
                    tree.iter_changes(tree.basis_tree()))
3775.2.4 by Robert Collins
Start on a CommitBuilder.record_iter_changes method.
81
                builder.finish_inventory()
82
            except:
83
                builder.abort()
84
                raise
85
            repo = tree.branch.repository
86
            repo.commit_write_group()
2617.6.8 by Robert Collins
Review feedback and documentation.
87
        finally:
88
            tree.unlock()
1740.3.3 by Jelmer Vernooij
Move storing directories and links to commit builder.
89
2749.3.1 by Jelmer Vernooij
Add CommitBuilder.abort().
90
    def test_abort(self):
91
        tree = self.make_branch_and_tree(".")
92
        tree.lock_write()
93
        try:
94
            builder = tree.branch.get_commit_builder([])
95
            self.record_root(builder, tree)
96
            builder.finish_inventory()
97
            builder.abort()
98
        finally:
99
            tree.unlock()
100
3775.2.5 by Robert Collins
CommitBuilder.abort() is callable after record_iter_changes.
101
    def test_abort_record_iter_changes(self):
102
        tree = self.make_branch_and_tree(".")
103
        tree.lock_write()
104
        try:
105
            builder = tree.branch.get_commit_builder([])
106
            try:
3775.2.29 by Robert Collins
Updates to the form of add_inventory_by_delta that landed in trunk.
107
                basis = tree.basis_tree()
108
                last_rev = tree.last_revision()
109
                changes = tree.iter_changes(basis)
3775.2.30 by Robert Collins
Remove the basis_tree parameter to record_iter_changes.
110
                builder.record_iter_changes(tree, last_rev, changes)
3775.2.5 by Robert Collins
CommitBuilder.abort() is callable after record_iter_changes.
111
                builder.finish_inventory()
3775.2.29 by Robert Collins
Updates to the form of add_inventory_by_delta that landed in trunk.
112
            finally:
3775.2.5 by Robert Collins
CommitBuilder.abort() is callable after record_iter_changes.
113
                builder.abort()
114
        finally:
115
            tree.unlock()
116
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
117
    def test_commit_message(self):
1740.3.7 by Jelmer Vernooij
Move committer, log, revprops, timestamp and timezone to CommitBuilder.
118
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
119
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
120
        try:
121
            builder = tree.branch.get_commit_builder([])
122
            self.record_root(builder, tree)
123
            builder.finish_inventory()
124
            rev_id = builder.commit('foo bar blah')
125
        finally:
126
            tree.unlock()
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
127
        rev = tree.branch.repository.get_revision(rev_id)
128
        self.assertEqual('foo bar blah', rev.message)
129
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
130
    def test_commit_with_revision_id(self):
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
131
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
132
        tree.lock_write()
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
133
        try:
2617.6.8 by Robert Collins
Review feedback and documentation.
134
            # use a unicode revision id to test more corner cases.
135
            # The repository layer is meant to handle this.
136
            revision_id = u'\xc8abc'.encode('utf8')
2150.2.2 by Robert Collins
Change the commit builder selected-revision-id test to use a unicode revision id where possible, leading to stricter testing of the hypothetical unicode revision id support in bzr.
137
            try:
2617.6.8 by Robert Collins
Review feedback and documentation.
138
                try:
139
                    builder = tree.branch.get_commit_builder([],
140
                        revision_id=revision_id)
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
141
                except errors.NonAsciiRevisionId:
2617.6.8 by Robert Collins
Review feedback and documentation.
142
                    revision_id = 'abc'
143
                    builder = tree.branch.get_commit_builder([],
144
                        revision_id=revision_id)
2831.5.1 by Vincent Ladeuil
Portability fix in TestCommitBuilder for unlink.
145
            except errors.CannotSetRevisionId:
2617.6.8 by Robert Collins
Review feedback and documentation.
146
                # This format doesn't support supplied revision ids
147
                return
2805.6.1 by Robert Collins
Set random_revid on CommitBuilder when a commit generated its own revision id.
148
            self.assertFalse(builder.random_revid)
2617.6.8 by Robert Collins
Review feedback and documentation.
149
            self.record_root(builder, tree)
150
            builder.finish_inventory()
151
            self.assertEqual(revision_id, builder.commit('foo bar'))
152
        finally:
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
153
            tree.unlock()
2150.2.2 by Robert Collins
Change the commit builder selected-revision-id test to use a unicode revision id where possible, leading to stricter testing of the hypothetical unicode revision id support in bzr.
154
        self.assertTrue(tree.branch.repository.has_revision(revision_id))
155
        # the revision id must be set on the inventory when saving it. This
156
        # does not precisely test that - a repository that wants to can add it
157
        # on deserialisation, but thats all the current contract guarantees
158
        # anyway.
159
        self.assertEqual(revision_id,
160
            tree.branch.repository.get_inventory(revision_id).revision_id)
1740.3.8 by Jelmer Vernooij
Move make_revision() to commit builder.
161
3775.2.6 by Robert Collins
CommitBuilder can specify a revision_id with record_iter_changes.
162
    def test_commit_with_revision_id_record_iter_changes(self):
163
        tree = self.make_branch_and_tree(".")
164
        tree.lock_write()
165
        try:
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')
169
            try:
170
                try:
171
                    builder = tree.branch.get_commit_builder([],
172
                        revision_id=revision_id)
173
                except errors.NonAsciiRevisionId:
174
                    revision_id = 'abc'
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
179
                return
180
            self.assertFalse(builder.random_revid)
181
            try:
3775.2.30 by Robert Collins
Remove the basis_tree parameter to record_iter_changes.
182
                builder.record_iter_changes(tree, tree.last_revision(),
183
                    tree.iter_changes(tree.basis_tree()))
3775.2.6 by Robert Collins
CommitBuilder can specify a revision_id with record_iter_changes.
184
                builder.finish_inventory()
185
            except:
186
                builder.abort()
187
                raise
188
            builder.finish_inventory()
189
            self.assertEqual(revision_id, builder.commit('foo bar'))
190
        finally:
191
            tree.unlock()
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
196
        # anyway.
197
        self.assertEqual(revision_id,
198
            tree.branch.repository.get_inventory(revision_id).revision_id)
199
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
200
    def test_commit_without_root_or_record_iter_changes_errors(self):
1910.2.8 by Aaron Bentley
Fix commit_builder when root not passed to record_entry_contents
201
        tree = self.make_branch_and_tree(".")
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
202
        tree.lock_write()
203
        try:
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
204
            self.build_tree(['foo'])
205
            tree.add('foo', 'foo-id')
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
206
            entry = tree.inventory['foo-id']
207
            builder = tree.branch.get_commit_builder([])
2871.1.2 by Robert Collins
* ``CommitBuilder.record_entry_contents`` now requires the root entry of a
208
            self.assertRaises(errors.RootMissing,
2776.4.4 by Robert Collins
Move content summary generation outside of record_entry_contents.
209
                builder.record_entry_contents, entry, [], 'foo', tree,
210
                    tree.path_content_summary('foo'))
2871.1.2 by Robert Collins
* ``CommitBuilder.record_entry_contents`` now requires the root entry of a
211
            builder.abort()
2255.7.8 by John Arbash Meinel
Lock the tree when using a commit builder.
212
        finally:
213
            tree.unlock()
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
214
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
215
    def test_commit_unchanged_root(self):
216
        tree = self.make_branch_and_tree(".")
2903.2.3 by Martin Pool
CommitBuilder tests should expect the root to be in the delta iff it's changed in the commit
217
        old_revision_id = tree.commit('')
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
218
        tree.lock_write()
219
        parent_tree = tree.basis_tree()
220
        parent_tree.lock_read()
221
        self.addCleanup(parent_tree.unlock)
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
222
        builder = tree.branch.get_commit_builder([old_revision_id])
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
223
        try:
224
            ie = inventory.make_entry('directory', '', None,
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
225
                    tree.get_root_id())
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
226
            delta, version_recorded, fs_hash = builder.record_entry_contents(
2776.4.13 by Robert Collins
Merge bzr.dev.
227
                ie, [parent_tree.inventory], '', tree,
2871.1.4 by Robert Collins
Merge bzr.dev.
228
                tree.path_content_summary(''))
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
229
            # Regardless of repository root behaviour we should consider this a
230
            # pointless commit.
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
231
            self.assertFalse(builder.any_changes())
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
232
            self.assertFalse(version_recorded)
2903.2.3 by Martin Pool
CommitBuilder tests should expect the root to be in the delta iff it's changed in the commit
233
            # if the repository format recorded a new root revision, that
234
            # should be in the delta
235
            got_new_revision = ie.revision != old_revision_id
236
            if got_new_revision:
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
237
                self.assertEqual(('', '', ie.file_id, ie), delta)
238
                # The delta should be tracked
239
                self.assertEqual(delta, builder._basis_delta[-1])
2903.2.3 by Martin Pool
CommitBuilder tests should expect the root to be in the delta iff it's changed in the commit
240
            else:
241
                self.assertEqual(None, delta)
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
242
            # Directories do not get hashed.
243
            self.assertEqual(None, fs_hash)
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
244
            builder.abort()
245
        except:
246
            builder.abort()
247
            tree.unlock()
248
            raise
249
        else:
250
            tree.unlock()
1910.2.8 by Aaron Bentley
Fix commit_builder when root not passed to record_entry_contents
251
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
252
    def test_commit_unchanged_root_record_iter_changes(self):
253
        tree = self.make_branch_and_tree(".")
254
        old_revision_id = tree.commit('')
255
        tree.lock_write()
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
256
        builder = tree.branch.get_commit_builder([old_revision_id])
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
257
        try:
3775.2.30 by Robert Collins
Remove the basis_tree parameter to record_iter_changes.
258
            builder.record_iter_changes(tree, old_revision_id, [])
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
259
            # Regardless of repository root behaviour we should consider this a
260
            # pointless commit.
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
261
            self.assertFalse(builder.any_changes())
3775.2.7 by Robert Collins
CommitBuilder handles no-change commits to roots properly with record_iter_changes.
262
            builder.finish_inventory()
263
            new_root = tree.branch.repository.get_inventory(
264
                builder._new_revision_id).root
265
            if tree.branch.repository.supports_rich_root():
266
                # We should not have seen a new root revision
267
                self.assertEqual(old_revision_id, new_root.revision)
268
            else:
269
                # We should see a new root revision
270
                self.assertNotEqual(old_revision_id, new_root.revision)
271
        finally:
272
            builder.abort()
273
            tree.unlock()
274
1740.3.10 by Jelmer Vernooij
Fix some minor issues pointed out by j-a-m.
275
    def test_commit(self):
1740.3.8 by Jelmer Vernooij
Move make_revision() to commit builder.
276
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
277
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
278
        try:
279
            builder = tree.branch.get_commit_builder([])
280
            self.record_root(builder, tree)
281
            builder.finish_inventory()
282
            rev_id = builder.commit('foo bar')
283
        finally:
284
            tree.unlock()
1740.3.9 by Jelmer Vernooij
Make the commit message the first argument of CommitBuilder.commit().
285
        self.assertNotEqual(None, rev_id)
286
        self.assertTrue(tree.branch.repository.has_revision(rev_id))
1757.1.2 by Robert Collins
Bugfix CommitBuilders recording of the inventory revision id.
287
        # the revision id must be set on the inventory when saving it. This does not
288
        # precisely test that - a repository that wants to can add it on deserialisation,
289
        # but thats all the current contract guarantees anyway.
290
        self.assertEqual(rev_id, tree.branch.repository.get_inventory(rev_id).revision_id)
2041.1.1 by John Arbash Meinel
Add a 'get_tree()' call that returns a RevisionTree for the newly committed tree
291
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
292
    def test_get_basis_delta(self):
293
        tree = self.make_branch_and_tree(".")
294
        self.build_tree(["foo"])
295
        tree.add(["foo"], ["foo-id"])
296
        old_revision_id = tree.commit("added foo")
297
        tree.lock_write()
298
        try:
299
            self.build_tree(['bar'])
300
            tree.add(['bar'], ['bar-id'])
301
            basis = tree.branch.repository.revision_tree(old_revision_id)
302
            basis.lock_read()
303
            self.addCleanup(basis.unlock)
304
            builder = tree.branch.get_commit_builder([old_revision_id])
305
            total_delta = []
306
            try:
307
                parent_invs = [basis.inventory]
308
                builder.will_record_deletes()
309
                if builder.record_root_entry:
310
                    ie = basis.inventory.root.copy()
311
                    delta, _, _ = builder.record_entry_contents(ie, parent_invs,
312
                        '', tree, tree.path_content_summary(''))
313
                    if delta is not None:
314
                        total_delta.append(delta)
315
                delta = builder.record_delete("foo", "foo-id")
316
                total_delta.append(delta)
317
                new_bar = inventory.make_entry('file', 'bar',
318
                    parent_id=tree.get_root_id(), file_id='bar-id')
319
                delta, _, _ = builder.record_entry_contents(new_bar, parent_invs,
320
                    'bar', tree, tree.path_content_summary('bar'))
321
                total_delta.append(delta)
322
                # All actions should have been recorded in the basis_delta
323
                self.assertEqual(total_delta, builder.get_basis_delta())
324
                builder.finish_inventory()
325
                builder.commit('delete foo, add bar')
326
            except:
327
                tree.branch.repository.abort_write_group()
328
                raise
329
        finally:
330
            tree.unlock()
331
332
    def test_get_basis_delta_without_notification(self):
333
        tree = self.make_branch_and_tree(".")
334
        old_revision_id = tree.commit('')
335
        tree.lock_write()
336
        try:
337
            parent_tree = tree.basis_tree()
338
            parent_tree.lock_read()
339
            self.addCleanup(parent_tree.unlock)
340
            builder = tree.branch.get_commit_builder([old_revision_id])
341
            # It is an error to expect builder.get_basis_delta() to be correct,
342
            # if you have not also called will_record_deletes() to indicate you
343
            # will be calling record_delete() when appropriate
344
            self.assertRaises(AssertionError, builder.get_basis_delta)
345
            tree.branch.repository.abort_write_group()
346
        finally:
347
            tree.unlock()
348
3775.2.2 by Robert Collins
Teach CommitBuilder to accumulate inventory deltas.
349
    def test_record_delete(self):
350
        tree = self.make_branch_and_tree(".")
351
        self.build_tree(["foo"])
352
        tree.add(["foo"], ["foo-id"])
353
        rev_id = tree.commit("added foo")
354
        # Remove the inventory details for foo-id, because
355
        # record_entry_contents ends up copying root verbatim.
356
        tree.unversion(["foo-id"])
357
        tree.lock_write()
358
        try:
359
            basis = tree.branch.repository.revision_tree(rev_id)
360
            builder = tree.branch.get_commit_builder([rev_id])
361
            try:
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
362
                builder.will_record_deletes()
3775.2.2 by Robert Collins
Teach CommitBuilder to accumulate inventory deltas.
363
                if builder.record_root_entry is True:
364
                    parent_invs = [basis.inventory]
365
                    del basis.inventory.root.children['foo']
366
                    builder.record_entry_contents(basis.inventory.root,
367
                        parent_invs, '', tree, tree.path_content_summary(''))
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
368
                # the delta should be returned, and recorded in _basis_delta
369
                delta = builder.record_delete("foo", "foo-id")
370
                self.assertEqual(("foo", None, "foo-id", None), delta)
371
                self.assertEqual(delta, builder._basis_delta[-1])
3775.2.2 by Robert Collins
Teach CommitBuilder to accumulate inventory deltas.
372
                builder.finish_inventory()
373
                rev_id2 = builder.commit('delete foo')
374
            except:
375
                tree.branch.repository.abort_write_group()
376
                raise
377
        finally:
378
            tree.unlock()
379
        rev_tree = builder.revision_tree()
380
        rev_tree.lock_read()
381
        self.addCleanup(rev_tree.unlock)
382
        self.assertFalse(rev_tree.path2id('foo'))
383
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
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")
389
        tree.lock_write()
390
        try:
391
            builder = tree.branch.get_commit_builder([rev_id])
392
            try:
393
                delete_change = ('foo-id', ('foo', None), True, (True, False),
394
                    (tree.path2id(''), None), ('foo', None), ('file', None),
395
                    (False, None))
3775.2.30 by Robert Collins
Remove the basis_tree parameter to record_iter_changes.
396
                builder.record_iter_changes(tree, rev_id, [delete_change])
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
397
                self.assertEqual(("foo", None, "foo-id", None),
3775.2.29 by Robert Collins
Updates to the form of add_inventory_by_delta that landed in trunk.
398
                    builder._basis_delta[0])
3775.2.9 by Robert Collins
CommitBuilder handles deletes via record_iter_entries.
399
                self.assertTrue(builder.any_changes())
400
                builder.finish_inventory()
401
                rev_id2 = builder.commit('delete foo')
402
            except:
403
                builder.abort()
404
                raise
405
        finally:
406
            tree.unlock()
407
        rev_tree = builder.revision_tree()
408
        rev_tree.lock_read()
409
        self.addCleanup(rev_tree.unlock)
410
        self.assertFalse(rev_tree.path2id('foo'))
411
3775.2.2 by Robert Collins
Teach CommitBuilder to accumulate inventory deltas.
412
    def test_record_delete_without_notification(self):
413
        tree = self.make_branch_and_tree(".")
414
        self.build_tree(["foo"])
415
        tree.add(["foo"], ["foo-id"])
416
        rev_id = tree.commit("added foo")
417
        tree.lock_write()
418
        try:
419
            builder = tree.branch.get_commit_builder([rev_id])
420
            try:
421
                self.record_root(builder, tree)
422
                self.assertRaises(AssertionError,
423
                    builder.record_delete, "foo", "foo-id")
424
            finally:
425
                tree.branch.repository.abort_write_group()
426
        finally:
427
            tree.unlock()
428
2041.1.5 by John Arbash Meinel
CommitBuilder.get_tree => CommitBuilder.revision_tree
429
    def test_revision_tree(self):
2041.1.1 by John Arbash Meinel
Add a 'get_tree()' call that returns a RevisionTree for the newly committed tree
430
        tree = self.make_branch_and_tree(".")
2617.6.2 by Robert Collins
Add abort_write_group and wire write_groups into fetch and commit.
431
        tree.lock_write()
2617.6.8 by Robert Collins
Review feedback and documentation.
432
        try:
433
            builder = tree.branch.get_commit_builder([])
434
            self.record_root(builder, tree)
435
            builder.finish_inventory()
436
            rev_id = builder.commit('foo bar')
437
        finally:
438
            tree.unlock()
2041.1.5 by John Arbash Meinel
CommitBuilder.get_tree => CommitBuilder.revision_tree
439
        rev_tree = builder.revision_tree()
2041.1.1 by John Arbash Meinel
Add a 'get_tree()' call that returns a RevisionTree for the newly committed tree
440
        # Just a couple simple tests to ensure that it actually follows
441
        # the RevisionTree api.
442
        self.assertEqual(rev_id, rev_tree.get_revision_id())
443
        self.assertEqual([], rev_tree.get_parent_ids())
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
444
3775.2.10 by Robert Collins
CommitBuilder gives a revision tree when used with record_iter_contents.
445
    def test_revision_tree_record_iter_changes(self):
446
        tree = self.make_branch_and_tree(".")
447
        tree.lock_write()
448
        try:
449
            builder = tree.branch.get_commit_builder([])
450
            try:
3775.2.30 by Robert Collins
Remove the basis_tree parameter to record_iter_changes.
451
                builder.record_iter_changes(tree, _mod_revision.NULL_REVISION,
3775.2.10 by Robert Collins
CommitBuilder gives a revision tree when used with record_iter_contents.
452
                    tree.iter_changes(tree.basis_tree()))
453
                builder.finish_inventory()
454
                rev_id = builder.commit('foo bar')
455
            except:
456
                builder.abort()
457
                raise
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())
463
        finally:
464
            tree.unlock()
465
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
466
    def test_root_entry_has_revision(self):
467
        # test the root revision created and put in the basis
468
        # has the right rev id.
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
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.
2255.7.65 by Robert Collins
Split test_root_revision_entry into tree and repository portions.
472
        tree = self.make_branch_and_tree('.')
473
        rev_id = tree.commit('message')
474
        basis_tree = tree.basis_tree()
475
        basis_tree.lock_read()
476
        self.addCleanup(basis_tree.unlock)
477
        self.assertEqual(rev_id, basis_tree.inventory.root.revision)
478
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
479
    def _get_revtrees(self, tree, revision_ids):
2592.3.214 by Robert Collins
Merge bzr.dev.
480
        tree.lock_read()
481
        try:
482
            trees = list(tree.branch.repository.revision_trees(revision_ids))
483
            for _tree in trees:
484
                _tree.lock_read()
485
                self.addCleanup(_tree.unlock)
486
            return trees
487
        finally:
488
            tree.unlock()
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
489
490
    def test_last_modified_revision_after_commit_root_unchanged(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
491
        # commiting without changing the root does not change the
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
492
        # last modified except on non-rich-root-repositories.
493
        tree = self.make_branch_and_tree('.')
494
        rev1 = tree.commit('')
495
        rev2 = tree.commit('')
496
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
497
        self.assertEqual(rev1, tree1.inventory.root.revision)
498
        if tree.branch.repository.supports_rich_root():
499
            self.assertEqual(rev1, tree2.inventory.root.revision)
500
        else:
501
            self.assertEqual(rev2, tree2.inventory.root.revision)
502
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
503
    def _add_commit_check_unchanged(self, tree, name, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
504
        tree.add([name], [name + 'id'])
505
        rev1 = tree.commit('')
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
506
        if mini_commit is None:
507
            mini_commit = self.mini_commit
508
        rev2 = mini_commit(tree, name, name, False, False)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
509
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
510
        self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
511
        self.assertEqual(rev1, tree2.inventory[name + 'id'].revision)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
512
        file_id = name + 'id'
513
        expected_graph = {}
514
        expected_graph[(file_id, rev1)] = ()
515
        self.assertFileGraph(expected_graph, tree, (file_id, rev1))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
516
517
    def test_last_modified_revision_after_commit_dir_unchanged(self):
518
        # committing without changing a dir does not change the last modified.
519
        tree = self.make_branch_and_tree('.')
520
        self.build_tree(['dir/'])
521
        self._add_commit_check_unchanged(tree, 'dir')
522
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
523
    def test_last_modified_revision_after_commit_dir_unchanged_ric(self):
524
        # committing without changing a dir does not change the last modified.
525
        tree = self.make_branch_and_tree('.')
526
        self.build_tree(['dir/'])
527
        self._add_commit_check_unchanged(tree, 'dir',
528
            mini_commit=self.mini_commit_record_iter_changes)
529
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
530
    def test_last_modified_revision_after_commit_dir_contents_unchanged(self):
531
        # committing without changing a dir does not change the last modified
532
        # of the dir even the dirs contents are changed.
533
        tree = self.make_branch_and_tree('.')
534
        self.build_tree(['dir/'])
535
        tree.add(['dir'], ['dirid'])
536
        rev1 = tree.commit('')
537
        self.build_tree(['dir/content'])
538
        tree.add(['dir/content'], ['contentid'])
539
        rev2 = tree.commit('')
540
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
541
        self.assertEqual(rev1, tree1.inventory['dirid'].revision)
542
        self.assertEqual(rev1, tree2.inventory['dirid'].revision)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
543
        file_id = 'dirid'
544
        expected_graph = {}
545
        expected_graph[(file_id, rev1)] = ()
546
        self.assertFileGraph(expected_graph, tree, (file_id, rev1))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
547
548
    def test_last_modified_revision_after_commit_file_unchanged(self):
549
        # committing without changing a file does not change the last modified.
550
        tree = self.make_branch_and_tree('.')
551
        self.build_tree(['file'])
552
        self._add_commit_check_unchanged(tree, 'file')
553
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
554
    def test_last_modified_revision_after_commit_file_unchanged_ric(self):
555
        # committing without changing a file does not change the last modified.
556
        tree = self.make_branch_and_tree('.')
557
        self.build_tree(['file'])
558
        self._add_commit_check_unchanged(tree, 'file',
559
            mini_commit=self.mini_commit_record_iter_changes)
560
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
561
    def test_last_modified_revision_after_commit_link_unchanged(self):
562
        # committing without changing a link does not change the last modified.
563
        self.requireFeature(tests.SymlinkFeature)
564
        tree = self.make_branch_and_tree('.')
565
        os.symlink('target', 'link')
566
        self._add_commit_check_unchanged(tree, 'link')
567
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
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)
575
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
576
    def _add_commit_renamed_check_changed(self, tree, name,
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
577
        expect_fs_hash=False, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
578
        def rename():
579
            tree.rename_one(name, 'new_' + name)
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
580
        if mini_commit is None:
581
            mini_commit = self.mini_commit
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
582
        self._add_commit_change_check_changed(tree, name, rename,
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
583
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
584
585
    def test_last_modified_revision_after_rename_dir_changes(self):
586
        # renaming a dir changes the last modified.
587
        tree = self.make_branch_and_tree('.')
588
        self.build_tree(['dir/'])
589
        self._add_commit_renamed_check_changed(tree, 'dir')
590
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
591
    def test_last_modified_revision_after_rename_dir_changes_ric(self):
592
        # renaming a dir changes the last modified.
593
        tree = self.make_branch_and_tree('.')
594
        self.build_tree(['dir/'])
595
        self._add_commit_renamed_check_changed(tree, 'dir',
596
            mini_commit=self.mini_commit_record_iter_changes)
597
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
598
    def test_last_modified_revision_after_rename_file_changes(self):
599
        # renaming a file changes the last modified.
600
        tree = self.make_branch_and_tree('.')
601
        self.build_tree(['file'])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
602
        self._add_commit_renamed_check_changed(tree, 'file',
603
            expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
604
3775.2.12 by Robert Collins
CommitBuilder.record_iter_changes handles renamed files.
605
    def test_last_modified_revision_after_rename_file_changes_ric(self):
606
        # renaming a file changes the last modified.
607
        tree = self.make_branch_and_tree('.')
608
        self.build_tree(['file'])
609
        self._add_commit_renamed_check_changed(tree, 'file',
610
            expect_fs_hash=True,
611
            mini_commit=self.mini_commit_record_iter_changes)
612
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
613
    def test_last_modified_revision_after_rename_link_changes(self):
614
        # renaming a link changes the last modified.
615
        self.requireFeature(tests.SymlinkFeature)
616
        tree = self.make_branch_and_tree('.')
617
        os.symlink('target', 'link')
618
        self._add_commit_renamed_check_changed(tree, 'link')
619
3775.2.13 by Robert Collins
CommitBuilder.record_iter_changes handles renamed symlinks.
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)
627
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
628
    def _add_commit_reparent_check_changed(self, tree, name,
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
629
        expect_fs_hash=False, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
630
        self.build_tree(['newparent/'])
631
        tree.add(['newparent'])
632
        def reparent():
633
            tree.rename_one(name, 'newparent/new_' + name)
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
634
        self._add_commit_change_check_changed(tree, name, reparent,
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
635
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
636
637
    def test_last_modified_revision_after_reparent_dir_changes(self):
638
        # reparenting a dir changes the last modified.
639
        tree = self.make_branch_and_tree('.')
640
        self.build_tree(['dir/'])
641
        self._add_commit_reparent_check_changed(tree, 'dir')
642
3775.2.14 by Robert Collins
CommitBuilder.record_iter_changes handles reparented directories.
643
    def test_last_modified_revision_after_reparent_dir_changes_ric(self):
644
        # reparenting a dir changes the last modified.
645
        tree = self.make_branch_and_tree('.')
646
        self.build_tree(['dir/'])
647
        self._add_commit_reparent_check_changed(tree, 'dir',
648
            mini_commit=self.mini_commit_record_iter_changes)
649
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
650
    def test_last_modified_revision_after_reparent_file_changes(self):
651
        # reparenting a file changes the last modified.
652
        tree = self.make_branch_and_tree('.')
653
        self.build_tree(['file'])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
654
        self._add_commit_reparent_check_changed(tree, 'file',
655
            expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
656
3775.2.15 by Robert Collins
CommitBuilder.record_iter_changes handles reparented files.
657
    def test_last_modified_revision_after_reparent_file_changes_ric(self):
658
        # reparenting a file changes the last modified.
659
        tree = self.make_branch_and_tree('.')
660
        self.build_tree(['file'])
661
        self._add_commit_reparent_check_changed(tree, 'file',
3775.2.17 by Robert Collins
CommitBuilder.record_iter_changes handles changed files.
662
            expect_fs_hash=True,
663
            mini_commit=self.mini_commit_record_iter_changes)
3775.2.15 by Robert Collins
CommitBuilder.record_iter_changes handles reparented files.
664
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
665
    def test_last_modified_revision_after_reparent_link_changes(self):
666
        # reparenting a link changes the last modified.
667
        self.requireFeature(tests.SymlinkFeature)
668
        tree = self.make_branch_and_tree('.')
669
        os.symlink('target', 'link')
670
        self._add_commit_reparent_check_changed(tree, 'link')
671
3775.2.16 by Robert Collins
CommitBuilder.record_iter_changes handles reparented symlinks.
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)
679
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
680
    def _add_commit_change_check_changed(self, tree, name, changer,
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
681
        expect_fs_hash=False, mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
682
        tree.add([name], [name + 'id'])
683
        rev1 = tree.commit('')
684
        changer()
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
685
        if mini_commit is None:
686
            mini_commit = self.mini_commit
687
        rev2 = mini_commit(tree, name, tree.id2path(name + 'id'),
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
688
            expect_fs_hash=expect_fs_hash)
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
689
        tree1, tree2 = self._get_revtrees(tree, [rev1, rev2])
690
        self.assertEqual(rev1, tree1.inventory[name + 'id'].revision)
691
        self.assertEqual(rev2, tree2.inventory[name + 'id'].revision)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
692
        file_id = name + 'id'
693
        expected_graph = {}
694
        expected_graph[(file_id, rev1)] = ()
695
        expected_graph[(file_id, rev2)] = ((file_id, rev1),)
696
        self.assertFileGraph(expected_graph, tree, (file_id, rev2))
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
697
698
    def mini_commit(self, tree, name, new_name, records_version=True,
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
699
        delta_against_basis=True, expect_fs_hash=False):
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
700
        """Perform a miniature commit looking for record entry results.
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
701
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
702
        :param tree: The tree to commit.
703
        :param name: The path in the basis tree of the tree being committed.
704
        :param new_name: The path in the tree being committed.
705
        :param records_version: True if the commit of new_name is expected to
706
            record a new version.
707
        :param delta_against_basis: True of the commit of new_name is expected
708
            to have a delta against the basis.
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
709
        :param expect_fs_hash: True or false to indicate whether we expect a
710
            file hash to be returned from the record_entry_contents call.
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
711
        """
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
712
        tree.lock_write()
713
        try:
714
            # mini manual commit here so we can check the return of
715
            # record_entry_contents.
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
716
            parent_ids = tree.get_parent_ids()
717
            builder = tree.branch.get_commit_builder(parent_ids)
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
718
            parent_tree = tree.basis_tree()
719
            parent_tree.lock_read()
720
            self.addCleanup(parent_tree.unlock)
721
            parent_invs = [parent_tree.inventory]
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
722
            for parent_id in parent_ids[1:]:
723
                parent_invs.append(tree.branch.repository.revision_tree(
724
                    parent_id).inventory)
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
725
            # root
726
            builder.record_entry_contents(
727
                inventory.make_entry('directory', '', None,
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
728
                    tree.get_root_id()), parent_invs, '', tree,
2776.4.13 by Robert Collins
Merge bzr.dev.
729
                    tree.path_content_summary(''))
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
730
            def commit_id(file_id):
731
                old_ie = tree.inventory[file_id]
732
                path = tree.id2path(file_id)
733
                ie = inventory.make_entry(tree.kind(file_id), old_ie.name,
734
                    old_ie.parent_id, file_id)
2776.4.13 by Robert Collins
Merge bzr.dev.
735
                return builder.record_entry_contents(ie, parent_invs, path,
736
                    tree, tree.path_content_summary(path))
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
737
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
738
            file_id = tree.path2id(new_name)
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
739
            parent_id = tree.inventory[file_id].parent_id
2946.3.3 by John Arbash Meinel
Prefer tree.get_root_id() as more explicit than tree.path2id('')
740
            if parent_id != tree.get_root_id():
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
741
                commit_id(parent_id)
742
            # because a change of some sort is meant to have occurred,
743
            # recording the entry must return True.
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
744
            delta, version_recorded, fs_hash = commit_id(file_id)
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
745
            if records_version:
746
                self.assertTrue(version_recorded)
747
            else:
748
                self.assertFalse(version_recorded)
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
749
            if expect_fs_hash:
3709.3.2 by Robert Collins
Race-free stat-fingerprint updating during commit via a new method get_file_with_stat.
750
                tree_file_stat = tree.get_file_with_stat(file_id)
751
                tree_file_stat[0].close()
752
                self.assertEqual(2, len(fs_hash))
753
                self.assertEqual(tree.get_file_sha1(file_id), fs_hash[0])
754
                self.assertEqualStat(tree_file_stat[1], fs_hash[1])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
755
            else:
756
                self.assertEqual(None, fs_hash)
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
757
            new_entry = builder.new_inventory[file_id]
758
            if delta_against_basis:
759
                expected_delta = (name, new_name, file_id, new_entry)
3879.2.5 by John Arbash Meinel
Change record_delete() to return the delta.
760
                # The delta should be recorded
761
                self.assertEqual(expected_delta, builder._basis_delta[-1])
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
762
            else:
763
                expected_delta = None
764
            self.assertEqual(expected_delta, delta)
2825.5.1 by Robert Collins
* Committing a change which is not a merge and does not change the number of
765
            builder.finish_inventory()
766
            rev2 = builder.commit('')
767
            tree.set_parent_ids([rev2])
768
        except:
769
            builder.abort()
770
            tree.unlock()
771
            raise
772
        else:
773
            tree.unlock()
2871.1.3 by Robert Collins
* The CommitBuilder method ``record_entry_contents`` now returns summary
774
        return rev2
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
775
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
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.
779
780
        This version uses the record_iter_changes interface.
781
        
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'.
791
        """
792
        tree.lock_write()
793
        try:
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))
3775.2.30 by Robert Collins
Remove the basis_tree parameter to record_iter_changes.
806
            builder.record_iter_changes(tree, parent_ids[0], changes)
3775.2.29 by Robert Collins
Updates to the form of add_inventory_by_delta that landed in trunk.
807
            delta = builder._basis_delta
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
808
            delta_dict = dict((change[2], change) for change in delta)
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
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)
3775.2.11 by Robert Collins
CommitBuilder handles renamed directory and unmodified entries with single parents, for record_iter_changes.
813
            if records_version:
814
                self.assertTrue(version_recorded)
815
            else:
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])
823
            else:
824
                expected_delta = None
825
                self.assertFalse(version_recorded)
826
            rev2 = builder.commit('')
827
            tree.set_parent_ids([rev2])
828
        except:
829
            builder.abort()
830
            tree.unlock()
831
            raise
832
        else:
833
            tree.unlock()
834
        return rev2
835
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
836
    def assertFileGraph(self, expected_graph, tree, tip):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
837
        # all the changes that have occured should be in the ancestry
838
        # (closest to a public per-file graph API we have today)
839
        tree.lock_read()
840
        self.addCleanup(tree.unlock)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
841
        graph = dict(Graph(tree.branch.repository.texts).iter_ancestry([tip]))
842
        self.assertEqual(expected_graph, graph)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
843
844
    def test_last_modified_revision_after_content_file_changes(self):
845
        # altering a file changes the last modified.
846
        tree = self.make_branch_and_tree('.')
847
        self.build_tree(['file'])
848
        def change_file():
849
            tree.put_file_bytes_non_atomic('fileid', 'new content')
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
850
        self._add_commit_change_check_changed(tree, 'file', change_file,
851
            expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
852
3775.2.17 by Robert Collins
CommitBuilder.record_iter_changes handles changed files.
853
    def test_last_modified_revision_after_content_file_changes_ric(self):
854
        # altering a file changes the last modified.
855
        tree = self.make_branch_and_tree('.')
856
        self.build_tree(['file'])
857
        def change_file():
858
            tree.put_file_bytes_non_atomic('fileid', 'new content')
859
        self._add_commit_change_check_changed(tree, 'file', change_file,
860
            expect_fs_hash=True,
861
            mini_commit=self.mini_commit_record_iter_changes)
862
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
863
    def test_last_modified_revision_after_content_link_changes(self):
864
        # changing a link changes the last modified.
865
        self.requireFeature(tests.SymlinkFeature)
866
        tree = self.make_branch_and_tree('.')
867
        os.symlink('target', 'link')
868
        def change_link():
869
            os.unlink('link')
870
            os.symlink('newtarget', 'link')
871
        self._add_commit_change_check_changed(tree, 'link', change_link)
872
3775.2.18 by Robert Collins
CommitBuilder.record_iter_changes handles changed symlinks.
873
    def test_last_modified_revision_after_content_link_changes_ric(self):
874
        # changing a link changes the last modified.
875
        self.requireFeature(tests.SymlinkFeature)
876
        tree = self.make_branch_and_tree('.')
877
        os.symlink('target', 'link')
878
        def change_link():
879
            os.unlink('link')
880
            os.symlink('newtarget', 'link')
881
        self._add_commit_change_check_changed(tree, 'link', change_link,
882
            mini_commit=self.mini_commit_record_iter_changes)
883
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
884
    def _commit_sprout(self, tree, name):
885
        tree.add([name], [name + 'id'])
886
        rev_id = tree.commit('')
887
        return rev_id, tree.bzrdir.sprout('t2').open_workingtree()
888
889
    def _rename_in_tree(self, tree, name):
890
        tree.rename_one(name, 'new_' + name)
891
        return tree.commit('')
892
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
893
    def _commit_sprout_rename_merge(self, tree1, name, expect_fs_hash=False,
894
        mini_commit=None):
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
895
        """Do a rename in both trees."""
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
896
        rev1, tree2 = self._commit_sprout(tree1, name)
897
        # change both sides equally
898
        rev2 = self._rename_in_tree(tree1, name)
899
        rev3 = self._rename_in_tree(tree2, name)
900
        tree1.merge_from_branch(tree2.branch)
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
901
        if mini_commit is None:
902
            mini_commit = self.mini_commit
903
        rev4 = mini_commit(tree1, 'new_' + name, 'new_' + name,
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
904
            expect_fs_hash=expect_fs_hash)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
905
        tree3, = self._get_revtrees(tree1, [rev4])
906
        self.assertEqual(rev4, tree3.inventory[name + 'id'].revision)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
907
        file_id = name + 'id'
908
        expected_graph = {}
909
        expected_graph[(file_id, rev1)] = ()
910
        expected_graph[(file_id, rev2)] = ((file_id, rev1),)
911
        expected_graph[(file_id, rev3)] = ((file_id, rev1),)
912
        expected_graph[(file_id, rev4)] = ((file_id, rev2), (file_id, rev3),)
913
        self.assertFileGraph(expected_graph, tree1, (file_id, rev4))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
914
915
    def test_last_modified_revision_after_merge_dir_changes(self):
916
        # merge a dir changes the last modified.
917
        tree1 = self.make_branch_and_tree('t1')
918
        self.build_tree(['t1/dir/'])
919
        self._commit_sprout_rename_merge(tree1, 'dir')
920
3775.2.19 by Robert Collins
CommitBuilder.record_iter_changes handles merged directories.
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)
927
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
928
    def test_last_modified_revision_after_merge_file_changes(self):
929
        # merge a file changes the last modified.
930
        tree1 = self.make_branch_and_tree('t1')
931
        self.build_tree(['t1/file'])
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
932
        self._commit_sprout_rename_merge(tree1, 'file', expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
933
3775.2.20 by Robert Collins
CommitBuilder.record_iter_changes handles merged files.
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)
940
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
941
    def test_last_modified_revision_after_merge_link_changes(self):
942
        # merge a link changes the last modified.
943
        self.requireFeature(tests.SymlinkFeature)
944
        tree1 = self.make_branch_and_tree('t1')
945
        os.symlink('target', 't1/link')
946
        self._commit_sprout_rename_merge(tree1, 'link')
947
3775.2.21 by Robert Collins
CommitBuilder.record_iter_changes handles merged symlinks.
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)
955
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
956
    def _commit_sprout_rename_merge_converged(self, tree1, name,
957
        mini_commit=None):
958
        # Make a merge which just incorporates a change from a branch:
959
        # The per-file graph is straight line, and no alteration occurs
960
        # in the inventory.
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
961
        rev1, tree2 = self._commit_sprout(tree1, name)
962
        # change on the other side to merge back
963
        rev2 = self._rename_in_tree(tree2, name)
964
        tree1.merge_from_branch(tree2.branch)
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
965
        if mini_commit is None:
966
            mini_commit = self.mini_commit
967
        rev3 = mini_commit(tree1, name, 'new_' + name, False)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
968
        tree3, = self._get_revtrees(tree1, [rev2])
969
        self.assertEqual(rev2, tree3.inventory[name + 'id'].revision)
3350.6.4 by Robert Collins
First cut at pluralised VersionedFiles. Some rather massive API incompatabilities, primarily because of the difficulty of coherence among competing stores.
970
        file_id = name + 'id'
971
        expected_graph = {}
972
        expected_graph[(file_id, rev1)] = ()
973
        expected_graph[(file_id, rev2)] = ((file_id, rev1),)
974
        self.assertFileGraph(expected_graph, tree1, (file_id, rev2))
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
975
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
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
983
        make('t2/name')
984
        file_id = 'nameid'
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)
994
        expected_graph = {}
995
        expected_graph[(file_id, rev2)] = ()
996
        self.assertFileGraph(expected_graph, tree1, (file_id, rev2))
997
998
    def test_last_modified_revision_after_converged_merge_dir_unchanged(self):
999
        # merge a dir that changed preserves the last modified.
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1000
        tree1 = self.make_branch_and_tree('t1')
1001
        self.build_tree(['t1/dir/'])
1002
        self._commit_sprout_rename_merge_converged(tree1, 'dir')
1003
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1004
    def test_last_modified_revision_after_converged_merge_dir_unchanged_ric(self):
1005
        # merge a dir that changed preserves the last modified.
3775.2.22 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch directories.
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)
1010
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1011
    def test_last_modified_revision_after_converged_merge_file_unchanged(self):
1012
        # merge a file that changed preserves the last modified.
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1013
        tree1 = self.make_branch_and_tree('t1')
1014
        self.build_tree(['t1/file'])
1015
        self._commit_sprout_rename_merge_converged(tree1, 'file')
1016
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1017
    def test_last_modified_revision_after_converged_merge_file_unchanged_ric(self):
1018
        # merge a file that changed preserves the last modified.
3775.2.23 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch files.
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)
1023
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1024
    def test_last_modified_revision_after_converged_merge_link_unchanged(self):
1025
        # merge a link that changed preserves the last modified.
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1026
        self.requireFeature(tests.SymlinkFeature)
1027
        tree1 = self.make_branch_and_tree('t1')
1028
        os.symlink('target', 't1/link')
1029
        self._commit_sprout_rename_merge_converged(tree1, 'link')
1030
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
1031
    def test_last_modified_revision_after_converged_merge_link_unchanged_ric(self):
1032
        # merge a link that changed preserves the last modified.
3775.2.24 by Robert Collins
CommitBuilder.record_iter_changes handles changed-in-branch symlinks.
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)
1038
3775.2.33 by Robert Collins
Fix bug with merges of new files, increasing test coverage to ensure its kept fixed.
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)
1043
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)
1049
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)
1054
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)
1060
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)
1065
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)
1071
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1072
    def make_dir(self, name):
1073
        self.build_tree([name + '/'])
1074
1075
    def make_file(self, name):
1076
        self.build_tree([name])
1077
1078
    def make_link(self, name):
1079
        self.requireFeature(tests.SymlinkFeature)
1080
        os.symlink('target', name)
1081
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
1082
    def _check_kind_change(self, make_before, make_after, expect_fs_hash=False,
1083
        mini_commit=None):
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1084
        tree = self.make_branch_and_tree('.')
1085
        path = 'name'
1086
        make_before(path)
2831.5.2 by Vincent Ladeuil
Review feedback.
1087
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1088
        def change_kind():
2831.5.2 by Vincent Ladeuil
Review feedback.
1089
            osutils.delete_any(path)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1090
            make_after(path)
2831.5.2 by Vincent Ladeuil
Review feedback.
1091
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
1092
        self._add_commit_change_check_changed(tree, path, change_kind,
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
1093
            expect_fs_hash=expect_fs_hash, mini_commit=mini_commit)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1094
1095
    def test_last_modified_dir_file(self):
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
1096
        self._check_kind_change(self.make_dir, self.make_file,
1097
            expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1098
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
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)
1103
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1104
    def test_last_modified_dir_link(self):
1105
        self._check_kind_change(self.make_dir, self.make_link)
1106
3775.2.25 by Robert Collins
CommitBuilder.record_iter_changes handles directories becoming files and links.
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)
1110
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1111
    def test_last_modified_link_file(self):
3709.3.1 by Robert Collins
First cut - make it work - at updating the tree stat cache during commit.
1112
        self._check_kind_change(self.make_link, self.make_file,
1113
            expect_fs_hash=True)
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1114
3775.2.26 by Robert Collins
CommitBuilder.record_iter_changes handles links becomes directories and files.
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)
1119
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1120
    def test_last_modified_link_dir(self):
1121
        self._check_kind_change(self.make_link, self.make_dir)
1122
3775.2.26 by Robert Collins
CommitBuilder.record_iter_changes handles links becomes directories and files.
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)
1126
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1127
    def test_last_modified_file_dir(self):
1128
        self._check_kind_change(self.make_file, self.make_dir)
1129
3775.2.27 by Robert Collins
CommitBuilder.record_iter_changes handles files becoming directories and links.
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)
1133
2776.1.5 by Robert Collins
Add reasonably comprehensive tests for path last modified and per file graph behaviour.
1134
    def test_last_modified_file_link(self):
1135
        self._check_kind_change(self.make_file, self.make_link)
3831.1.1 by John Arbash Meinel
Before allowing commit to succeed, verify the texts will be 'safe'.
1136
3775.2.27 by Robert Collins
CommitBuilder.record_iter_changes handles files becoming directories and links.
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)
3775.2.28 by Robert Collins
Merge .dev.
1140
3831.1.1 by John Arbash Meinel
Before allowing commit to succeed, verify the texts will be 'safe'.
1141
    def test_get_commit_builder_with_invalid_revprops(self):
1142
        branch = self.make_branch('.')
1143
        branch.repository.lock_write()
1144
        self.addCleanup(branch.repository.unlock)
1145
        self.assertRaises(ValueError, branch.repository.get_commit_builder,
1146
            branch, [], branch.get_config(),
1147
            revprops={'invalid': u'property\rwith\r\ninvalid chars'})
1148
1149
    def test_commit_builder_commit_with_invalid_message(self):
1150
        branch = self.make_branch('.')
1151
        branch.repository.lock_write()
1152
        self.addCleanup(branch.repository.unlock)
1153
        builder = branch.repository.get_commit_builder(branch, [],
1154
            branch.get_config())
1155
        self.addCleanup(branch.repository.abort_write_group)
1156
        self.assertRaises(ValueError, builder.commit,
1157
            u'Invalid\r\ncommit message\r\n')