~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

[merge] jam-integration

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
import os
19
19
 
20
 
from bzrlib.selftest import TestCaseInTempDir
 
20
import bzrlib
 
21
from bzrlib.tests import TestCaseWithTransport
21
22
from bzrlib.branch import Branch
 
23
from bzrlib.workingtree import WorkingTree
22
24
from bzrlib.commit import Commit
23
 
from bzrlib.errors import PointlessCommit, BzrError
 
25
from bzrlib.config import BranchConfig
 
26
from bzrlib.errors import PointlessCommit, BzrError, SigningFailed
24
27
 
25
28
 
26
29
# TODO: Test commit with some added, and added-but-missing files
27
30
 
28
 
class TestCommit(TestCaseInTempDir):
 
31
class MustSignConfig(BranchConfig):
 
32
 
 
33
    def signature_needed(self):
 
34
        return True
 
35
 
 
36
    def gpg_signing_command(self):
 
37
        return ['cat', '-']
 
38
 
 
39
 
 
40
class BranchWithHooks(BranchConfig):
 
41
 
 
42
    def post_commit(self):
 
43
        return "bzrlib.ahook bzrlib.ahook"
 
44
 
 
45
 
 
46
class TestCommit(TestCaseWithTransport):
29
47
 
30
48
    def test_simple_commit(self):
31
49
        """Commit and check two versions of a single file."""
32
 
        b = Branch.initialize('.')
 
50
        wt = self.make_branch_and_tree('.')
 
51
        b = wt.branch
33
52
        file('hello', 'w').write('hello world')
34
 
        b.add('hello')
35
 
        b.commit(message='add hello')
36
 
        file_id = b.working_tree().path2id('hello')
 
53
        wt.add('hello')
 
54
        wt.commit(message='add hello')
 
55
        file_id = wt.path2id('hello')
37
56
 
38
57
        file('hello', 'w').write('version 2')
39
 
        b.commit(message='commit 2')
 
58
        wt.commit(message='commit 2')
40
59
 
41
60
        eq = self.assertEquals
42
61
        eq(b.revno(), 2)
43
62
        rh = b.revision_history()
44
 
        rev = b.get_revision(rh[0])
 
63
        rev = b.repository.get_revision(rh[0])
45
64
        eq(rev.message, 'add hello')
46
65
 
47
 
        tree1 = b.revision_tree(rh[0])
 
66
        tree1 = b.repository.revision_tree(rh[0])
48
67
        text = tree1.get_file_text(file_id)
49
68
        eq(text, 'hello world')
50
69
 
51
 
        tree2 = b.revision_tree(rh[1])
 
70
        tree2 = b.repository.revision_tree(rh[1])
52
71
        eq(tree2.get_file_text(file_id), 'version 2')
53
72
 
54
 
 
55
73
    def test_delete_commit(self):
56
74
        """Test a commit with a deleted file"""
57
 
        b = Branch.initialize('.')
 
75
        wt = self.make_branch_and_tree('.')
 
76
        b = wt.branch
58
77
        file('hello', 'w').write('hello world')
59
 
        b.add(['hello'], ['hello-id'])
60
 
        b.commit(message='add hello')
 
78
        wt.add(['hello'], ['hello-id'])
 
79
        wt.commit(message='add hello')
61
80
 
62
81
        os.remove('hello')
63
 
        b.commit('removed hello', rev_id='rev2')
 
82
        wt.commit('removed hello', rev_id='rev2')
64
83
 
65
 
        tree = b.revision_tree('rev2')
 
84
        tree = b.repository.revision_tree('rev2')
66
85
        self.assertFalse(tree.has_id('hello-id'))
67
86
 
68
 
 
69
87
    def test_pointless_commit(self):
70
88
        """Commit refuses unless there are changes or it's forced."""
71
 
        b = Branch.initialize('.')
 
89
        wt = self.make_branch_and_tree('.')
 
90
        b = wt.branch
72
91
        file('hello', 'w').write('hello')
73
 
        b.add(['hello'])
74
 
        b.commit(message='add hello')
 
92
        wt.add(['hello'])
 
93
        wt.commit(message='add hello')
75
94
        self.assertEquals(b.revno(), 1)
76
95
        self.assertRaises(PointlessCommit,
77
 
                          b.commit,
 
96
                          wt.commit,
78
97
                          message='fails',
79
98
                          allow_pointless=False)
80
99
        self.assertEquals(b.revno(), 1)
81
100
        
82
 
 
83
 
 
84
101
    def test_commit_empty(self):
85
102
        """Commiting an empty tree works."""
86
 
        b = Branch.initialize('.')
87
 
        b.commit(message='empty tree', allow_pointless=True)
 
103
        wt = self.make_branch_and_tree('.')
 
104
        b = wt.branch
 
105
        wt.commit(message='empty tree', allow_pointless=True)
88
106
        self.assertRaises(PointlessCommit,
89
 
                          b.commit,
 
107
                          wt.commit,
90
108
                          message='empty tree',
91
109
                          allow_pointless=False)
92
 
        b.commit(message='empty tree', allow_pointless=True)
 
110
        wt.commit(message='empty tree', allow_pointless=True)
93
111
        self.assertEquals(b.revno(), 2)
94
112
 
95
 
 
96
113
    def test_selective_delete(self):
97
114
        """Selective commit in tree with deletions"""
98
 
        b = Branch.initialize('.')
 
115
        wt = self.make_branch_and_tree('.')
 
116
        b = wt.branch
99
117
        file('hello', 'w').write('hello')
100
118
        file('buongia', 'w').write('buongia')
101
 
        b.add(['hello', 'buongia'],
 
119
        wt.add(['hello', 'buongia'],
102
120
              ['hello-id', 'buongia-id'])
103
 
        b.commit(message='add files',
 
121
        wt.commit(message='add files',
104
122
                 rev_id='test@rev-1')
105
123
        
106
124
        os.remove('hello')
107
125
        file('buongia', 'w').write('new text')
108
 
        b.commit(message='update text',
 
126
        wt.commit(message='update text',
109
127
                 specific_files=['buongia'],
110
128
                 allow_pointless=False,
111
129
                 rev_id='test@rev-2')
112
130
 
113
 
        b.commit(message='remove hello',
 
131
        wt.commit(message='remove hello',
114
132
                 specific_files=['hello'],
115
133
                 allow_pointless=False,
116
134
                 rev_id='test@rev-3')
118
136
        eq = self.assertEquals
119
137
        eq(b.revno(), 3)
120
138
 
121
 
        tree2 = b.revision_tree('test@rev-2')
 
139
        tree2 = b.repository.revision_tree('test@rev-2')
122
140
        self.assertTrue(tree2.has_filename('hello'))
123
141
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
124
142
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
125
143
        
126
 
        tree3 = b.revision_tree('test@rev-3')
 
144
        tree3 = b.repository.revision_tree('test@rev-3')
127
145
        self.assertFalse(tree3.has_filename('hello'))
128
146
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
129
147
 
130
 
 
131
148
    def test_commit_rename(self):
132
149
        """Test commit of a revision where a file is renamed."""
133
 
        b = Branch.initialize('.')
134
 
        self.build_tree(['hello'])
135
 
        b.add(['hello'], ['hello-id'])
136
 
        b.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
 
150
        tree = self.make_branch_and_tree('.')
 
151
        b = tree.branch
 
152
        self.build_tree(['hello'], line_endings='binary')
 
153
        tree.add(['hello'], ['hello-id'])
 
154
        tree.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
137
155
 
138
 
        b.rename_one('hello', 'fruity')
139
 
        b.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
 
156
        tree.rename_one('hello', 'fruity')
 
157
        tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
140
158
 
141
159
        eq = self.assertEquals
142
 
        tree1 = b.revision_tree('test@rev-1')
 
160
        tree1 = b.repository.revision_tree('test@rev-1')
143
161
        eq(tree1.id2path('hello-id'), 'hello')
144
162
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
145
163
        self.assertFalse(tree1.has_filename('fruity'))
147
165
        ie = tree1.inventory['hello-id']
148
166
        eq(ie.revision, 'test@rev-1')
149
167
 
150
 
        tree2 = b.revision_tree('test@rev-2')
 
168
        tree2 = b.repository.revision_tree('test@rev-2')
151
169
        eq(tree2.id2path('hello-id'), 'fruity')
152
170
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
153
171
        self.check_inventory_shape(tree2.inventory, ['fruity'])
154
172
        ie = tree2.inventory['hello-id']
155
173
        eq(ie.revision, 'test@rev-2')
156
174
 
157
 
 
158
175
    def test_reused_rev_id(self):
159
176
        """Test that a revision id cannot be reused in a branch"""
160
 
        b = Branch.initialize('.')
161
 
        b.commit('initial', rev_id='test@rev-1', allow_pointless=True)
 
177
        wt = self.make_branch_and_tree('.')
 
178
        b = wt.branch
 
179
        wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
162
180
        self.assertRaises(Exception,
163
 
                          b.commit,
 
181
                          b.working_tree().commit,
164
182
                          message='reused id',
165
183
                          rev_id='test@rev-1',
166
184
                          allow_pointless=True)
167
 
                          
168
 
 
169
185
 
170
186
    def test_commit_move(self):
171
187
        """Test commit of revisions with moved files and directories"""
172
188
        eq = self.assertEquals
173
 
        b = Branch.initialize('.')
 
189
        wt = self.make_branch_and_tree('.')
 
190
        b = wt.branch
174
191
        r1 = 'test@rev-1'
175
192
        self.build_tree(['hello', 'a/', 'b/'])
176
 
        b.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
177
 
        b.commit('initial', rev_id=r1, allow_pointless=False)
178
 
 
179
 
        b.move(['hello'], 'a')
 
193
        wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
 
194
        wt.commit('initial', rev_id=r1, allow_pointless=False)
 
195
        wt.move(['hello'], 'a')
180
196
        r2 = 'test@rev-2'
181
 
        b.commit('two', rev_id=r2, allow_pointless=False)
182
 
        self.check_inventory_shape(b.inventory,
 
197
        wt.commit('two', rev_id=r2, allow_pointless=False)
 
198
        self.check_inventory_shape(b.working_tree().read_working_inventory(),
183
199
                                   ['a', 'a/hello', 'b'])
184
200
 
185
 
        b.move(['b'], 'a')
 
201
        wt.move(['b'], 'a')
186
202
        r3 = 'test@rev-3'
187
 
        b.commit('three', rev_id=r3, allow_pointless=False)
188
 
        self.check_inventory_shape(b.inventory,
 
203
        wt.commit('three', rev_id=r3, allow_pointless=False)
 
204
        self.check_inventory_shape(wt.read_working_inventory(),
189
205
                                   ['a', 'a/hello', 'a/b'])
190
 
        self.check_inventory_shape(b.get_revision_inventory(r3),
 
206
        self.check_inventory_shape(b.repository.get_revision_inventory(r3),
191
207
                                   ['a', 'a/hello', 'a/b'])
192
208
 
193
 
        b.move([os.sep.join(['a', 'hello'])],
194
 
               os.sep.join(['a', 'b']))
 
209
        wt.move(['a/hello'], 'a/b')
195
210
        r4 = 'test@rev-4'
196
 
        b.commit('four', rev_id=r4, allow_pointless=False)
197
 
        self.check_inventory_shape(b.inventory,
 
211
        wt.commit('four', rev_id=r4, allow_pointless=False)
 
212
        self.check_inventory_shape(wt.read_working_inventory(),
198
213
                                   ['a', 'a/b/hello', 'a/b'])
199
214
 
200
 
        inv = b.get_revision_inventory(r4)
 
215
        inv = b.repository.get_revision_inventory(r4)
201
216
        eq(inv['hello-id'].revision, r4)
202
217
        eq(inv['a-id'].revision, r1)
203
218
        eq(inv['b-id'].revision, r3)
204
 
 
205
219
        
206
220
    def test_removed_commit(self):
207
 
        """Test a commit with a removed file"""
208
 
        b = Branch.initialize('.')
 
221
        """Commit with a removed file"""
 
222
        wt = self.make_branch_and_tree('.')
 
223
        b = wt.branch
209
224
        file('hello', 'w').write('hello world')
210
 
        b.add(['hello'], ['hello-id'])
211
 
        b.commit(message='add hello')
212
 
 
213
 
        b.remove('hello')
214
 
        b.commit('removed hello', rev_id='rev2')
215
 
 
216
 
        tree = b.revision_tree('rev2')
 
225
        wt.add(['hello'], ['hello-id'])
 
226
        wt.commit(message='add hello')
 
227
        wt.remove('hello')
 
228
        wt.commit('removed hello', rev_id='rev2')
 
229
 
 
230
        tree = b.repository.revision_tree('rev2')
217
231
        self.assertFalse(tree.has_id('hello-id'))
218
232
 
219
 
 
220
233
    def test_committed_ancestry(self):
221
234
        """Test commit appends revisions to ancestry."""
222
 
        b = Branch.initialize('.')
 
235
        wt = self.make_branch_and_tree('.')
 
236
        b = wt.branch
223
237
        rev_ids = []
224
238
        for i in range(4):
225
239
            file('hello', 'w').write((str(i) * 4) + '\n')
226
240
            if i == 0:
227
 
                b.add(['hello'], ['hello-id'])
 
241
                wt.add(['hello'], ['hello-id'])
228
242
            rev_id = 'test@rev-%d' % (i+1)
229
243
            rev_ids.append(rev_id)
230
 
            b.commit(message='rev %d' % (i+1),
 
244
            wt.commit(message='rev %d' % (i+1),
231
245
                     rev_id=rev_id)
232
246
        eq = self.assertEquals
233
247
        eq(b.revision_history(), rev_ids)
234
248
        for i in range(4):
235
 
            anc = b.get_ancestry(rev_ids[i])
 
249
            anc = b.repository.get_ancestry(rev_ids[i])
236
250
            eq(anc, [None] + rev_ids[:i+1])
237
251
 
238
252
    def test_commit_new_subdir_child_selective(self):
239
 
        b = Branch.initialize('.')
 
253
        wt = self.make_branch_and_tree('.')
 
254
        b = wt.branch
240
255
        self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
241
 
        b.add(['dir', 'dir/file1', 'dir/file2'],
 
256
        wt.add(['dir', 'dir/file1', 'dir/file2'],
242
257
              ['dirid', 'file1id', 'file2id'])
243
 
        b.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
244
 
        inv = b.get_inventory('1')
 
258
        wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
 
259
        inv = b.repository.get_inventory('1')
245
260
        self.assertEqual('1', inv['dirid'].revision)
246
261
        self.assertEqual('1', inv['file1id'].revision)
247
262
        # FIXME: This should raise a KeyError I think, rbc20051006
248
263
        self.assertRaises(BzrError, inv.__getitem__, 'file2id')
 
264
 
 
265
    def test_strict_commit(self):
 
266
        """Try and commit with unknown files and strict = True, should fail."""
 
267
        from bzrlib.errors import StrictCommitFailed
 
268
        wt = self.make_branch_and_tree('.')
 
269
        b = wt.branch
 
270
        file('hello', 'w').write('hello world')
 
271
        wt.add('hello')
 
272
        file('goodbye', 'w').write('goodbye cruel world!')
 
273
        self.assertRaises(StrictCommitFailed, b.working_tree().commit,
 
274
            message='add hello but not goodbye', strict=True)
 
275
 
 
276
    def test_strict_commit_without_unknowns(self):
 
277
        """Try and commit with no unknown files and strict = True,
 
278
        should work."""
 
279
        from bzrlib.errors import StrictCommitFailed
 
280
        wt = self.make_branch_and_tree('.')
 
281
        b = wt.branch
 
282
        file('hello', 'w').write('hello world')
 
283
        wt.add('hello')
 
284
        wt.commit(message='add hello', strict=True)
 
285
 
 
286
    def test_nonstrict_commit(self):
 
287
        """Try and commit with unknown files and strict = False, should work."""
 
288
        wt = self.make_branch_and_tree('.')
 
289
        b = wt.branch
 
290
        file('hello', 'w').write('hello world')
 
291
        wt.add('hello')
 
292
        file('goodbye', 'w').write('goodbye cruel world!')
 
293
        wt.commit(message='add hello but not goodbye', strict=False)
 
294
 
 
295
    def test_nonstrict_commit_without_unknowns(self):
 
296
        """Try and commit with no unknown files and strict = False,
 
297
        should work."""
 
298
        wt = self.make_branch_and_tree('.')
 
299
        b = wt.branch
 
300
        file('hello', 'w').write('hello world')
 
301
        wt.add('hello')
 
302
        wt.commit(message='add hello', strict=False)
 
303
 
 
304
    def test_signed_commit(self):
 
305
        import bzrlib.gpg
 
306
        import bzrlib.commit as commit
 
307
        oldstrategy = bzrlib.gpg.GPGStrategy
 
308
        wt = self.make_branch_and_tree('.')
 
309
        branch = wt.branch
 
310
        wt.commit("base", allow_pointless=True, rev_id='A')
 
311
        self.failIf(branch.repository.revision_store.has_id('A', 'sig'))
 
312
        try:
 
313
            from bzrlib.testament import Testament
 
314
            # monkey patch gpg signing mechanism
 
315
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
 
316
            commit.Commit(config=MustSignConfig(branch)).commit(message="base",
 
317
                                                      allow_pointless=True,
 
318
                                                      rev_id='B',
 
319
                                                      working_tree=wt)
 
320
            self.assertEqual(Testament.from_revision(branch.repository,
 
321
                             'B').as_short_text(),
 
322
                             branch.repository.revision_store.get('B', 
 
323
                                                               'sig').read())
 
324
        finally:
 
325
            bzrlib.gpg.GPGStrategy = oldstrategy
 
326
 
 
327
    def test_commit_failed_signature(self):
 
328
        import bzrlib.gpg
 
329
        import bzrlib.commit as commit
 
330
        oldstrategy = bzrlib.gpg.GPGStrategy
 
331
        wt = self.make_branch_and_tree('.')
 
332
        branch = wt.branch
 
333
        wt.commit("base", allow_pointless=True, rev_id='A')
 
334
        self.failIf(branch.repository.revision_store.has_id('A', 'sig'))
 
335
        try:
 
336
            from bzrlib.testament import Testament
 
337
            # monkey patch gpg signing mechanism
 
338
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
 
339
            config = MustSignConfig(branch)
 
340
            self.assertRaises(SigningFailed,
 
341
                              commit.Commit(config=config).commit,
 
342
                              branch, "base",
 
343
                              allow_pointless=True,
 
344
                              rev_id='B')
 
345
            branch = Branch.open(self.get_url('.'))
 
346
            self.assertEqual(branch.revision_history(), ['A'])
 
347
            self.failIf(branch.repository.revision_store.has_id('B'))
 
348
        finally:
 
349
            bzrlib.gpg.GPGStrategy = oldstrategy
 
350
 
 
351
    def test_commit_invokes_hooks(self):
 
352
        import bzrlib.commit as commit
 
353
        wt = self.make_branch_and_tree('.')
 
354
        branch = wt.branch
 
355
        calls = []
 
356
        def called(branch, rev_id):
 
357
            calls.append('called')
 
358
        bzrlib.ahook = called
 
359
        try:
 
360
            config = BranchWithHooks(branch)
 
361
            commit.Commit(config=config).commit(
 
362
                            message = "base",
 
363
                            allow_pointless=True,
 
364
                            rev_id='A', working_tree = wt)
 
365
            self.assertEqual(['called', 'called'], calls)
 
366
        finally:
 
367
            del bzrlib.ahook