/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: Robert Collins
  • Date: 2010-05-11 08:36:16 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100511083616-b8fjb19zomwupid0
Make all lock methods return Result objects, rather than lock_read returning self, as per John's review.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2016 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
16
16
 
17
17
 
18
18
import os
19
 
from io import BytesIO
20
19
 
21
 
import breezy
22
 
from .. import (
23
 
    config,
24
 
    controldir,
 
20
import bzrlib
 
21
from bzrlib import (
 
22
    bzrdir,
25
23
    errors,
26
 
    trace,
27
 
    )
28
 
from ..branch import Branch
29
 
from ..bzr.bzrdir import BzrDirMetaFormat1
30
 
from ..commit import (
31
 
    CannotCommitSelectedFileMerge,
32
 
    Commit,
33
 
    NullCommitReporter,
34
 
    PointlessCommit,
35
 
    filter_excluded,
36
 
    )
37
 
from ..errors import (
38
 
    BzrError,
39
 
    LockContention,
40
 
    )
41
 
from ..bzr.inventorytree import InventoryTreeChange
42
 
from . import (
43
 
    TestCase,
44
 
    TestCaseWithTransport,
45
 
    test_foreign,
46
 
    )
47
 
from .features import (
48
 
    SymlinkFeature,
49
 
    )
50
 
from .matchers import MatchesAncestry
 
24
    lockdir,
 
25
    osutils,
 
26
    tests,
 
27
    )
 
28
from bzrlib.branch import Branch
 
29
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
 
30
from bzrlib.commit import Commit, NullCommitReporter
 
31
from bzrlib.config import BranchConfig
 
32
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed,
 
33
                           LockContention)
 
34
from bzrlib.tests import SymlinkFeature, TestCaseWithTransport
 
35
from bzrlib.workingtree import WorkingTree
51
36
 
52
37
 
53
38
# TODO: Test commit with some added, and added-but-missing files
54
39
 
55
 
class MustSignConfig(config.MemoryStack):
56
 
 
57
 
    def __init__(self):
58
 
        super(MustSignConfig, self).__init__(b'''
59
 
create_signatures=always
60
 
''')
 
40
class MustSignConfig(BranchConfig):
 
41
 
 
42
    def signature_needed(self):
 
43
        return True
 
44
 
 
45
    def gpg_signing_command(self):
 
46
        return ['cat', '-']
 
47
 
 
48
 
 
49
class BranchWithHooks(BranchConfig):
 
50
 
 
51
    def post_commit(self):
 
52
        return "bzrlib.ahook bzrlib.ahook"
61
53
 
62
54
 
63
55
class CapturingReporter(NullCommitReporter):
89
81
        """Commit and check two versions of a single file."""
90
82
        wt = self.make_branch_and_tree('.')
91
83
        b = wt.branch
92
 
        with open('hello', 'w') as f:
93
 
            f.write('hello world')
 
84
        file('hello', 'w').write('hello world')
94
85
        wt.add('hello')
95
 
        rev1 = wt.commit(message='add hello')
96
 
 
97
 
        with open('hello', 'w') as f:
98
 
            f.write('version 2')
99
 
        rev2 = wt.commit(message='commit 2')
100
 
 
101
 
        eq = self.assertEqual
 
86
        wt.commit(message='add hello')
 
87
        file_id = wt.path2id('hello')
 
88
 
 
89
        file('hello', 'w').write('version 2')
 
90
        wt.commit(message='commit 2')
 
91
 
 
92
        eq = self.assertEquals
102
93
        eq(b.revno(), 2)
103
 
        rev = b.repository.get_revision(rev1)
 
94
        rh = b.revision_history()
 
95
        rev = b.repository.get_revision(rh[0])
104
96
        eq(rev.message, 'add hello')
105
97
 
106
 
        tree1 = b.repository.revision_tree(rev1)
 
98
        tree1 = b.repository.revision_tree(rh[0])
107
99
        tree1.lock_read()
108
 
        text = tree1.get_file_text('hello')
 
100
        text = tree1.get_file_text(file_id)
109
101
        tree1.unlock()
110
 
        self.assertEqual(b'hello world', text)
 
102
        self.assertEqual('hello world', text)
111
103
 
112
 
        tree2 = b.repository.revision_tree(rev2)
 
104
        tree2 = b.repository.revision_tree(rh[1])
113
105
        tree2.lock_read()
114
 
        text = tree2.get_file_text('hello')
 
106
        text = tree2.get_file_text(file_id)
115
107
        tree2.unlock()
116
 
        self.assertEqual(b'version 2', text)
117
 
 
118
 
    def test_commit_lossy_native(self):
119
 
        """Attempt a lossy commit to a native branch."""
120
 
        wt = self.make_branch_and_tree('.')
121
 
        b = wt.branch
122
 
        with open('hello', 'w') as f:
123
 
            f.write('hello world')
124
 
        wt.add('hello')
125
 
        revid = wt.commit(message='add hello', rev_id=b'revid', lossy=True)
126
 
        self.assertEqual(b'revid', revid)
127
 
 
128
 
    def test_commit_lossy_foreign(self):
129
 
        """Attempt a lossy commit to a foreign branch."""
130
 
        test_foreign.register_dummy_foreign_for_test(self)
131
 
        wt = self.make_branch_and_tree('.',
132
 
                                       format=test_foreign.DummyForeignVcsDirFormat())
133
 
        b = wt.branch
134
 
        with open('hello', 'w') as f:
135
 
            f.write('hello world')
136
 
        wt.add('hello')
137
 
        revid = wt.commit(message='add hello', lossy=True,
138
 
                          timestamp=1302659388, timezone=0)
139
 
        self.assertEqual(b'dummy-v1:1302659388-0-UNKNOWN', revid)
140
 
 
141
 
    def test_commit_bound_lossy_foreign(self):
142
 
        """Attempt a lossy commit to a bzr branch bound to a foreign branch."""
143
 
        test_foreign.register_dummy_foreign_for_test(self)
144
 
        foreign_branch = self.make_branch('foreign',
145
 
                                          format=test_foreign.DummyForeignVcsDirFormat())
146
 
        wt = foreign_branch.create_checkout("local")
147
 
        b = wt.branch
148
 
        with open('local/hello', 'w') as f:
149
 
            f.write('hello world')
150
 
        wt.add('hello')
151
 
        revid = wt.commit(message='add hello', lossy=True,
152
 
                          timestamp=1302659388, timezone=0)
153
 
        self.assertEqual(b'dummy-v1:1302659388-0-0', revid)
154
 
        self.assertEqual(b'dummy-v1:1302659388-0-0',
155
 
                         foreign_branch.last_revision())
156
 
        self.assertEqual(b'dummy-v1:1302659388-0-0',
157
 
                         wt.branch.last_revision())
 
108
        self.assertEqual('version 2', text)
158
109
 
159
110
    def test_missing_commit(self):
160
111
        """Test a commit with a missing file"""
161
112
        wt = self.make_branch_and_tree('.')
162
113
        b = wt.branch
163
 
        with open('hello', 'w') as f:
164
 
            f.write('hello world')
165
 
        wt.add(['hello'], [b'hello-id'])
 
114
        file('hello', 'w').write('hello world')
 
115
        wt.add(['hello'], ['hello-id'])
166
116
        wt.commit(message='add hello')
167
117
 
168
118
        os.remove('hello')
169
 
        reporter = CapturingReporter()
170
 
        wt.commit('removed hello', rev_id=b'rev2', reporter=reporter)
171
 
        self.assertEqual(
172
 
            [('missing', u'hello'), ('deleted', u'hello')],
173
 
            reporter.calls)
 
119
        wt.commit('removed hello', rev_id='rev2')
174
120
 
175
 
        tree = b.repository.revision_tree(b'rev2')
176
 
        self.assertFalse(tree.has_filename('hello'))
 
121
        tree = b.repository.revision_tree('rev2')
 
122
        self.assertFalse(tree.has_id('hello-id'))
177
123
 
178
124
    def test_partial_commit_move(self):
179
125
        """Test a partial commit where a file was renamed but not committed.
188
134
        b = wt.branch
189
135
        self.build_tree(['annotate/', 'annotate/foo.py',
190
136
                         'olive/', 'olive/dialog.py'
191
 
                         ])
 
137
                        ])
192
138
        wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
193
139
        wt.commit(message='add files')
194
140
        wt.rename_one("olive/dialog.py", "aaa")
195
 
        self.build_tree_contents([('annotate/foo.py', b'modified\n')])
 
141
        self.build_tree_contents([('annotate/foo.py', 'modified\n')])
196
142
        wt.commit('renamed hello', specific_files=["annotate"])
197
143
 
198
144
    def test_pointless_commit(self):
199
145
        """Commit refuses unless there are changes or it's forced."""
200
146
        wt = self.make_branch_and_tree('.')
201
147
        b = wt.branch
202
 
        with open('hello', 'w') as f:
203
 
            f.write('hello')
 
148
        file('hello', 'w').write('hello')
204
149
        wt.add(['hello'])
205
150
        wt.commit(message='add hello')
206
 
        self.assertEqual(b.revno(), 1)
 
151
        self.assertEquals(b.revno(), 1)
207
152
        self.assertRaises(PointlessCommit,
208
153
                          wt.commit,
209
154
                          message='fails',
210
155
                          allow_pointless=False)
211
 
        self.assertEqual(b.revno(), 1)
 
156
        self.assertEquals(b.revno(), 1)
212
157
 
213
158
    def test_commit_empty(self):
214
159
        """Commiting an empty tree works."""
220
165
                          message='empty tree',
221
166
                          allow_pointless=False)
222
167
        wt.commit(message='empty tree', allow_pointless=True)
223
 
        self.assertEqual(b.revno(), 2)
 
168
        self.assertEquals(b.revno(), 2)
224
169
 
225
170
    def test_selective_delete(self):
226
171
        """Selective commit in tree with deletions"""
227
172
        wt = self.make_branch_and_tree('.')
228
173
        b = wt.branch
229
 
        with open('hello', 'w') as f:
230
 
            f.write('hello')
231
 
        with open('buongia', 'w') as f:
232
 
            f.write('buongia')
 
174
        file('hello', 'w').write('hello')
 
175
        file('buongia', 'w').write('buongia')
233
176
        wt.add(['hello', 'buongia'],
234
 
               [b'hello-id', b'buongia-id'])
 
177
              ['hello-id', 'buongia-id'])
235
178
        wt.commit(message='add files',
236
 
                  rev_id=b'test@rev-1')
 
179
                 rev_id='test@rev-1')
237
180
 
238
181
        os.remove('hello')
239
 
        with open('buongia', 'w') as f:
240
 
            f.write('new text')
 
182
        file('buongia', 'w').write('new text')
241
183
        wt.commit(message='update text',
242
 
                  specific_files=['buongia'],
243
 
                  allow_pointless=False,
244
 
                  rev_id=b'test@rev-2')
 
184
                 specific_files=['buongia'],
 
185
                 allow_pointless=False,
 
186
                 rev_id='test@rev-2')
245
187
 
246
188
        wt.commit(message='remove hello',
247
 
                  specific_files=['hello'],
248
 
                  allow_pointless=False,
249
 
                  rev_id=b'test@rev-3')
 
189
                 specific_files=['hello'],
 
190
                 allow_pointless=False,
 
191
                 rev_id='test@rev-3')
250
192
 
251
 
        eq = self.assertEqual
 
193
        eq = self.assertEquals
252
194
        eq(b.revno(), 3)
253
195
 
254
 
        tree2 = b.repository.revision_tree(b'test@rev-2')
 
196
        tree2 = b.repository.revision_tree('test@rev-2')
255
197
        tree2.lock_read()
256
198
        self.addCleanup(tree2.unlock)
257
199
        self.assertTrue(tree2.has_filename('hello'))
258
 
        self.assertEqual(tree2.get_file_text('hello'), b'hello')
259
 
        self.assertEqual(tree2.get_file_text('buongia'), b'new text')
 
200
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
 
201
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
260
202
 
261
 
        tree3 = b.repository.revision_tree(b'test@rev-3')
 
203
        tree3 = b.repository.revision_tree('test@rev-3')
262
204
        tree3.lock_read()
263
205
        self.addCleanup(tree3.unlock)
264
206
        self.assertFalse(tree3.has_filename('hello'))
265
 
        self.assertEqual(tree3.get_file_text('buongia'), b'new text')
 
207
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
266
208
 
267
209
    def test_commit_rename(self):
268
210
        """Test commit of a revision where a file is renamed."""
269
211
        tree = self.make_branch_and_tree('.')
270
212
        b = tree.branch
271
213
        self.build_tree(['hello'], line_endings='binary')
272
 
        tree.add(['hello'], [b'hello-id'])
273
 
        tree.commit(message='one', rev_id=b'test@rev-1', allow_pointless=False)
 
214
        tree.add(['hello'], ['hello-id'])
 
215
        tree.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
274
216
 
275
217
        tree.rename_one('hello', 'fruity')
276
 
        tree.commit(message='renamed', rev_id=b'test@rev-2',
277
 
                    allow_pointless=False)
 
218
        tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
278
219
 
279
 
        eq = self.assertEqual
280
 
        tree1 = b.repository.revision_tree(b'test@rev-1')
 
220
        eq = self.assertEquals
 
221
        tree1 = b.repository.revision_tree('test@rev-1')
281
222
        tree1.lock_read()
282
223
        self.addCleanup(tree1.unlock)
283
 
        eq(tree1.id2path(b'hello-id'), 'hello')
284
 
        eq(tree1.get_file_text('hello'), b'contents of hello\n')
 
224
        eq(tree1.id2path('hello-id'), 'hello')
 
225
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
285
226
        self.assertFalse(tree1.has_filename('fruity'))
286
 
        self.check_tree_shape(tree1, ['hello'])
287
 
        eq(tree1.get_file_revision('hello'), b'test@rev-1')
 
227
        self.check_inventory_shape(tree1.inventory, ['hello'])
 
228
        ie = tree1.inventory['hello-id']
 
229
        eq(ie.revision, 'test@rev-1')
288
230
 
289
 
        tree2 = b.repository.revision_tree(b'test@rev-2')
 
231
        tree2 = b.repository.revision_tree('test@rev-2')
290
232
        tree2.lock_read()
291
233
        self.addCleanup(tree2.unlock)
292
 
        eq(tree2.id2path(b'hello-id'), 'fruity')
293
 
        eq(tree2.get_file_text('fruity'), b'contents of hello\n')
294
 
        self.check_tree_shape(tree2, ['fruity'])
295
 
        eq(tree2.get_file_revision('fruity'), b'test@rev-2')
 
234
        eq(tree2.id2path('hello-id'), 'fruity')
 
235
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
 
236
        self.check_inventory_shape(tree2.inventory, ['fruity'])
 
237
        ie = tree2.inventory['hello-id']
 
238
        eq(ie.revision, 'test@rev-2')
296
239
 
297
240
    def test_reused_rev_id(self):
298
241
        """Test that a revision id cannot be reused in a branch"""
299
242
        wt = self.make_branch_and_tree('.')
300
243
        b = wt.branch
301
 
        wt.commit('initial', rev_id=b'test@rev-1', allow_pointless=True)
 
244
        wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
302
245
        self.assertRaises(Exception,
303
246
                          wt.commit,
304
247
                          message='reused id',
305
 
                          rev_id=b'test@rev-1',
 
248
                          rev_id='test@rev-1',
306
249
                          allow_pointless=True)
307
250
 
308
251
    def test_commit_move(self):
309
252
        """Test commit of revisions with moved files and directories"""
310
 
        eq = self.assertEqual
 
253
        eq = self.assertEquals
311
254
        wt = self.make_branch_and_tree('.')
312
255
        b = wt.branch
313
 
        r1 = b'test@rev-1'
 
256
        r1 = 'test@rev-1'
314
257
        self.build_tree(['hello', 'a/', 'b/'])
315
 
        wt.add(['hello', 'a', 'b'], [b'hello-id', b'a-id', b'b-id'])
 
258
        wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
316
259
        wt.commit('initial', rev_id=r1, allow_pointless=False)
317
260
        wt.move(['hello'], 'a')
318
 
        r2 = b'test@rev-2'
 
261
        r2 = 'test@rev-2'
319
262
        wt.commit('two', rev_id=r2, allow_pointless=False)
320
263
        wt.lock_read()
321
264
        try:
322
 
            self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
 
265
            self.check_inventory_shape(wt.read_working_inventory(),
 
266
                                       ['a/', 'a/hello', 'b/'])
323
267
        finally:
324
268
            wt.unlock()
325
269
 
326
270
        wt.move(['b'], 'a')
327
 
        r3 = b'test@rev-3'
 
271
        r3 = 'test@rev-3'
328
272
        wt.commit('three', rev_id=r3, allow_pointless=False)
329
273
        wt.lock_read()
330
274
        try:
331
 
            self.check_tree_shape(wt,
332
 
                                  ['a/', 'a/hello', 'a/b/'])
333
 
            self.check_tree_shape(b.repository.revision_tree(r3),
334
 
                                  ['a/', 'a/hello', 'a/b/'])
 
275
            self.check_inventory_shape(wt.read_working_inventory(),
 
276
                                       ['a/', 'a/hello', 'a/b/'])
 
277
            self.check_inventory_shape(b.repository.get_inventory(r3),
 
278
                                       ['a/', 'a/hello', 'a/b/'])
335
279
        finally:
336
280
            wt.unlock()
337
281
 
338
282
        wt.move(['a/hello'], 'a/b')
339
 
        r4 = b'test@rev-4'
 
283
        r4 = 'test@rev-4'
340
284
        wt.commit('four', rev_id=r4, allow_pointless=False)
341
285
        wt.lock_read()
342
286
        try:
343
 
            self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
 
287
            self.check_inventory_shape(wt.read_working_inventory(),
 
288
                                       ['a/', 'a/b/hello', 'a/b/'])
344
289
        finally:
345
290
            wt.unlock()
346
291
 
347
292
        inv = b.repository.get_inventory(r4)
348
 
        eq(inv.get_entry(b'hello-id').revision, r4)
349
 
        eq(inv.get_entry(b'a-id').revision, r1)
350
 
        eq(inv.get_entry(b'b-id').revision, r3)
 
293
        eq(inv['hello-id'].revision, r4)
 
294
        eq(inv['a-id'].revision, r1)
 
295
        eq(inv['b-id'].revision, r3)
351
296
 
352
297
    def test_removed_commit(self):
353
298
        """Commit with a removed file"""
354
299
        wt = self.make_branch_and_tree('.')
355
300
        b = wt.branch
356
 
        with open('hello', 'w') as f:
357
 
            f.write('hello world')
358
 
        wt.add(['hello'], [b'hello-id'])
 
301
        file('hello', 'w').write('hello world')
 
302
        wt.add(['hello'], ['hello-id'])
359
303
        wt.commit(message='add hello')
360
304
        wt.remove('hello')
361
 
        wt.commit('removed hello', rev_id=b'rev2')
 
305
        wt.commit('removed hello', rev_id='rev2')
362
306
 
363
 
        tree = b.repository.revision_tree(b'rev2')
364
 
        self.assertFalse(tree.has_filename('hello'))
 
307
        tree = b.repository.revision_tree('rev2')
 
308
        self.assertFalse(tree.has_id('hello-id'))
365
309
 
366
310
    def test_committed_ancestry(self):
367
311
        """Test commit appends revisions to ancestry."""
369
313
        b = wt.branch
370
314
        rev_ids = []
371
315
        for i in range(4):
372
 
            with open('hello', 'w') as f:
373
 
                f.write((str(i) * 4) + '\n')
 
316
            file('hello', 'w').write((str(i) * 4) + '\n')
374
317
            if i == 0:
375
 
                wt.add(['hello'], [b'hello-id'])
376
 
            rev_id = b'test@rev-%d' % (i + 1)
 
318
                wt.add(['hello'], ['hello-id'])
 
319
            rev_id = 'test@rev-%d' % (i+1)
377
320
            rev_ids.append(rev_id)
378
 
            wt.commit(message='rev %d' % (i + 1),
379
 
                      rev_id=rev_id)
 
321
            wt.commit(message='rev %d' % (i+1),
 
322
                     rev_id=rev_id)
 
323
        eq = self.assertEquals
 
324
        eq(b.revision_history(), rev_ids)
380
325
        for i in range(4):
381
 
            self.assertThat(rev_ids[:i + 1],
382
 
                            MatchesAncestry(b.repository, rev_ids[i]))
 
326
            anc = b.repository.get_ancestry(rev_ids[i])
 
327
            eq(anc, [None] + rev_ids[:i+1])
383
328
 
384
329
    def test_commit_new_subdir_child_selective(self):
385
330
        wt = self.make_branch_and_tree('.')
386
331
        b = wt.branch
387
332
        self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
388
333
        wt.add(['dir', 'dir/file1', 'dir/file2'],
389
 
               [b'dirid', b'file1id', b'file2id'])
390
 
        wt.commit('dir/file1', specific_files=['dir/file1'], rev_id=b'1')
391
 
        inv = b.repository.get_inventory(b'1')
392
 
        self.assertEqual(b'1', inv.get_entry(b'dirid').revision)
393
 
        self.assertEqual(b'1', inv.get_entry(b'file1id').revision)
 
334
              ['dirid', 'file1id', 'file2id'])
 
335
        wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
 
336
        inv = b.repository.get_inventory('1')
 
337
        self.assertEqual('1', inv['dirid'].revision)
 
338
        self.assertEqual('1', inv['file1id'].revision)
394
339
        # FIXME: This should raise a KeyError I think, rbc20051006
395
 
        self.assertRaises(BzrError, inv.get_entry, b'file2id')
 
340
        self.assertRaises(BzrError, inv.__getitem__, 'file2id')
396
341
 
397
342
    def test_strict_commit(self):
398
343
        """Try and commit with unknown files and strict = True, should fail."""
399
 
        from ..errors import StrictCommitFailed
 
344
        from bzrlib.errors import StrictCommitFailed
400
345
        wt = self.make_branch_and_tree('.')
401
346
        b = wt.branch
402
 
        with open('hello', 'w') as f:
403
 
            f.write('hello world')
 
347
        file('hello', 'w').write('hello world')
404
348
        wt.add('hello')
405
 
        with open('goodbye', 'w') as f:
406
 
            f.write('goodbye cruel world!')
 
349
        file('goodbye', 'w').write('goodbye cruel world!')
407
350
        self.assertRaises(StrictCommitFailed, wt.commit,
408
 
                          message='add hello but not goodbye', strict=True)
 
351
            message='add hello but not goodbye', strict=True)
409
352
 
410
353
    def test_strict_commit_without_unknowns(self):
411
354
        """Try and commit with no unknown files and strict = True,
412
355
        should work."""
 
356
        from bzrlib.errors import StrictCommitFailed
413
357
        wt = self.make_branch_and_tree('.')
414
358
        b = wt.branch
415
 
        with open('hello', 'w') as f:
416
 
            f.write('hello world')
 
359
        file('hello', 'w').write('hello world')
417
360
        wt.add('hello')
418
361
        wt.commit(message='add hello', strict=True)
419
362
 
421
364
        """Try and commit with unknown files and strict = False, should work."""
422
365
        wt = self.make_branch_and_tree('.')
423
366
        b = wt.branch
424
 
        with open('hello', 'w') as f:
425
 
            f.write('hello world')
 
367
        file('hello', 'w').write('hello world')
426
368
        wt.add('hello')
427
 
        with open('goodbye', 'w') as f:
428
 
            f.write('goodbye cruel world!')
 
369
        file('goodbye', 'w').write('goodbye cruel world!')
429
370
        wt.commit(message='add hello but not goodbye', strict=False)
430
371
 
431
372
    def test_nonstrict_commit_without_unknowns(self):
433
374
        should work."""
434
375
        wt = self.make_branch_and_tree('.')
435
376
        b = wt.branch
436
 
        with open('hello', 'w') as f:
437
 
            f.write('hello world')
 
377
        file('hello', 'w').write('hello world')
438
378
        wt.add('hello')
439
379
        wt.commit(message='add hello', strict=False)
440
380
 
441
381
    def test_signed_commit(self):
442
 
        import breezy.gpg
443
 
        import breezy.commit as commit
444
 
        oldstrategy = breezy.gpg.GPGStrategy
 
382
        import bzrlib.gpg
 
383
        import bzrlib.commit as commit
 
384
        oldstrategy = bzrlib.gpg.GPGStrategy
445
385
        wt = self.make_branch_and_tree('.')
446
386
        branch = wt.branch
447
 
        wt.commit("base", allow_pointless=True, rev_id=b'A')
448
 
        self.assertFalse(branch.repository.has_signature_for_revision_id(b'A'))
 
387
        wt.commit("base", allow_pointless=True, rev_id='A')
 
388
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
449
389
        try:
450
 
            from ..bzr.testament import Testament
 
390
            from bzrlib.testament import Testament
451
391
            # monkey patch gpg signing mechanism
452
 
            breezy.gpg.GPGStrategy = breezy.gpg.LoopbackGPGStrategy
453
 
            conf = config.MemoryStack(b'''
454
 
create_signatures=always
455
 
''')
456
 
            commit.Commit(config_stack=conf).commit(
457
 
                message="base", allow_pointless=True, rev_id=b'B',
458
 
                working_tree=wt)
459
 
 
 
392
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
 
393
            commit.Commit(config=MustSignConfig(branch)).commit(message="base",
 
394
                                                      allow_pointless=True,
 
395
                                                      rev_id='B',
 
396
                                                      working_tree=wt)
460
397
            def sign(text):
461
 
                return breezy.gpg.LoopbackGPGStrategy(None).sign(
462
 
                    text, breezy.gpg.MODE_CLEAR)
 
398
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
463
399
            self.assertEqual(sign(Testament.from_revision(branch.repository,
464
 
                                                          b'B').as_short_text()),
465
 
                             branch.repository.get_signature_text(b'B'))
 
400
                             'B').as_short_text()),
 
401
                             branch.repository.get_signature_text('B'))
466
402
        finally:
467
 
            breezy.gpg.GPGStrategy = oldstrategy
 
403
            bzrlib.gpg.GPGStrategy = oldstrategy
468
404
 
469
405
    def test_commit_failed_signature(self):
470
 
        import breezy.gpg
471
 
        import breezy.commit as commit
472
 
        oldstrategy = breezy.gpg.GPGStrategy
 
406
        import bzrlib.gpg
 
407
        import bzrlib.commit as commit
 
408
        oldstrategy = bzrlib.gpg.GPGStrategy
473
409
        wt = self.make_branch_and_tree('.')
474
410
        branch = wt.branch
475
 
        wt.commit("base", allow_pointless=True, rev_id=b'A')
476
 
        self.assertFalse(branch.repository.has_signature_for_revision_id(b'A'))
 
411
        wt.commit("base", allow_pointless=True, rev_id='A')
 
412
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
477
413
        try:
 
414
            from bzrlib.testament import Testament
478
415
            # monkey patch gpg signing mechanism
479
 
            breezy.gpg.GPGStrategy = breezy.gpg.DisabledGPGStrategy
480
 
            conf = config.MemoryStack(b'''
481
 
create_signatures=always
482
 
''')
483
 
            self.assertRaises(breezy.gpg.SigningFailed,
484
 
                              commit.Commit(config_stack=conf).commit,
 
416
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
 
417
            config = MustSignConfig(branch)
 
418
            self.assertRaises(SigningFailed,
 
419
                              commit.Commit(config=config).commit,
485
420
                              message="base",
486
421
                              allow_pointless=True,
487
 
                              rev_id=b'B',
 
422
                              rev_id='B',
488
423
                              working_tree=wt)
489
424
            branch = Branch.open(self.get_url('.'))
490
 
            self.assertEqual(branch.last_revision(), b'A')
491
 
            self.assertFalse(branch.repository.has_revision(b'B'))
 
425
            self.assertEqual(branch.revision_history(), ['A'])
 
426
            self.failIf(branch.repository.has_revision('B'))
492
427
        finally:
493
 
            breezy.gpg.GPGStrategy = oldstrategy
 
428
            bzrlib.gpg.GPGStrategy = oldstrategy
494
429
 
495
430
    def test_commit_invokes_hooks(self):
496
 
        import breezy.commit as commit
 
431
        import bzrlib.commit as commit
497
432
        wt = self.make_branch_and_tree('.')
498
433
        branch = wt.branch
499
434
        calls = []
500
 
 
501
435
        def called(branch, rev_id):
502
436
            calls.append('called')
503
 
        breezy.ahook = called
 
437
        bzrlib.ahook = called
504
438
        try:
505
 
            conf = config.MemoryStack(b'post_commit=breezy.ahook breezy.ahook')
506
 
            commit.Commit(config_stack=conf).commit(
507
 
                message="base", allow_pointless=True, rev_id=b'A',
508
 
                working_tree=wt)
 
439
            config = BranchWithHooks(branch)
 
440
            commit.Commit(config=config).commit(
 
441
                            message = "base",
 
442
                            allow_pointless=True,
 
443
                            rev_id='A', working_tree = wt)
509
444
            self.assertEqual(['called', 'called'], calls)
510
445
        finally:
511
 
            del breezy.ahook
 
446
            del bzrlib.ahook
512
447
 
513
448
    def test_commit_object_doesnt_set_nick(self):
514
449
        # using the Commit object directly does not set the branch nick.
515
450
        wt = self.make_branch_and_tree('.')
516
451
        c = Commit()
517
452
        c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
518
 
        self.assertEqual(wt.branch.revno(), 1)
 
453
        self.assertEquals(wt.branch.revno(), 1)
519
454
        self.assertEqual({},
520
455
                         wt.branch.repository.get_revision(
521
 
            wt.branch.last_revision()).properties)
 
456
                            wt.branch.last_revision()).properties)
522
457
 
523
458
    def test_safe_master_lock(self):
524
459
        os.mkdir('master')
529
464
        bound = master.sprout('bound')
530
465
        wt = bound.open_workingtree()
531
466
        wt.branch.set_bound_location(os.path.realpath('master'))
532
 
        with master_branch.lock_write():
 
467
        master_branch.lock_write()
 
468
        try:
533
469
            self.assertRaises(LockContention, wt.commit, 'silly')
 
470
        finally:
 
471
            master_branch.unlock()
534
472
 
535
473
    def test_commit_bound_merge(self):
536
474
        # see bug #43959; commit of a merge in a bound branch fails to push
539
477
        bound_tree = self.make_branch_and_tree('bound')
540
478
        bound_tree.branch.bind(master_branch)
541
479
 
542
 
        self.build_tree_contents(
543
 
            [('bound/content_file', b'initial contents\n')])
 
480
        self.build_tree_contents([('bound/content_file', 'initial contents\n')])
544
481
        bound_tree.add(['content_file'])
545
482
        bound_tree.commit(message='woo!')
546
483
 
547
 
        other_bzrdir = master_branch.controldir.sprout('other')
 
484
        other_bzrdir = master_branch.bzrdir.sprout('other')
548
485
        other_tree = other_bzrdir.open_workingtree()
549
486
 
550
487
        # do a commit to the other branch changing the content file so
551
488
        # that our commit after merging will have a merged revision in the
552
489
        # content file history.
553
 
        self.build_tree_contents(
554
 
            [('other/content_file', b'change in other\n')])
 
490
        self.build_tree_contents([('other/content_file', 'change in other\n')])
555
491
        other_tree.commit('change in other')
556
492
 
557
493
        # do a merge into the bound branch from other, and then change the
558
494
        # content file locally to force a new revision (rather than using the
559
495
        # revision from other). This forces extra processing in commit.
560
496
        bound_tree.merge_from_branch(other_tree.branch)
561
 
        self.build_tree_contents(
562
 
            [('bound/content_file', b'change in bound\n')])
 
497
        self.build_tree_contents([('bound/content_file', 'change in bound\n')])
563
498
 
564
499
        # before #34959 was fixed, this failed with 'revision not present in
565
500
        # weave' when trying to implicitly push from the bound branch to the master
593
528
            'filetoleave']
594
529
            )
595
530
        this_tree.commit('create_files')
596
 
        other_dir = this_tree.controldir.sprout('other')
 
531
        other_dir = this_tree.bzrdir.sprout('other')
597
532
        other_tree = other_dir.open_workingtree()
598
533
        other_tree.lock_write()
599
534
        # perform the needed actions on the files and dirs.
601
536
            other_tree.rename_one('dirtorename', 'renameddir')
602
537
            other_tree.rename_one('dirtoreparent', 'renameddir/reparenteddir')
603
538
            other_tree.rename_one('filetorename', 'renamedfile')
604
 
            other_tree.rename_one(
605
 
                'filetoreparent', 'renameddir/reparentedfile')
 
539
            other_tree.rename_one('filetoreparent', 'renameddir/reparentedfile')
606
540
            other_tree.remove(['dirtoremove', 'filetoremove'])
607
541
            self.build_tree_contents([
608
542
                ('other/newdir/', ),
609
 
                ('other/filetomodify', b'new content'),
610
 
                ('other/newfile', b'new file content')])
 
543
                ('other/filetomodify', 'new content'),
 
544
                ('other/newfile', 'new file content')])
611
545
            other_tree.add('newfile')
612
546
            other_tree.add('newdir/')
613
547
            other_tree.commit('modify all sample files and dirs.')
616
550
        this_tree.merge_from_branch(other_tree.branch)
617
551
        reporter = CapturingReporter()
618
552
        this_tree.commit('do the commit', reporter=reporter)
619
 
        expected = {
 
553
        expected = set([
620
554
            ('change', 'modified', 'filetomodify'),
621
555
            ('change', 'added', 'newdir'),
622
556
            ('change', 'added', 'newfile'),
626
560
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
627
561
            ('deleted', 'dirtoremove'),
628
562
            ('deleted', 'filetoremove'),
629
 
            }
 
563
            ])
630
564
        result = set(reporter.calls)
631
565
        missing = expected - result
632
566
        new = result - expected
641
575
        tree.remove(['a', 'b'])
642
576
        tree.commit('removed a', specific_files='a')
643
577
        basis = tree.basis_tree()
644
 
        with tree.lock_read():
645
 
            self.assertFalse(basis.is_versioned('a'))
646
 
            self.assertTrue(basis.is_versioned('b'))
 
578
        tree.lock_read()
 
579
        try:
 
580
            self.assertIs(None, basis.path2id('a'))
 
581
            self.assertFalse(basis.path2id('b') is None)
 
582
        finally:
 
583
            tree.unlock()
647
584
 
648
585
    def test_commit_saves_1ms_timestamp(self):
649
586
        """Passing in a timestamp is saved with 1ms resolution"""
651
588
        self.build_tree(['a'])
652
589
        tree.add('a')
653
590
        tree.commit('added a', timestamp=1153248633.4186721, timezone=0,
654
 
                    rev_id=b'a1')
 
591
                    rev_id='a1')
655
592
 
656
 
        rev = tree.branch.repository.get_revision(b'a1')
 
593
        rev = tree.branch.repository.get_revision('a1')
657
594
        self.assertEqual(1153248633.419, rev.timestamp)
658
595
 
659
596
    def test_commit_has_1ms_resolution(self):
661
598
        tree = self.make_branch_and_tree('.')
662
599
        self.build_tree(['a'])
663
600
        tree.add('a')
664
 
        tree.commit('added a', rev_id=b'a1')
 
601
        tree.commit('added a', rev_id='a1')
665
602
 
666
 
        rev = tree.branch.repository.get_revision(b'a1')
 
603
        rev = tree.branch.repository.get_revision('a1')
667
604
        timestamp = rev.timestamp
668
605
        timestamp_1ms = round(timestamp, 3)
669
606
        self.assertEqual(timestamp_1ms, timestamp)
670
607
 
671
 
    def assertBasisTreeKind(self, kind, tree, path):
 
608
    def assertBasisTreeKind(self, kind, tree, file_id):
672
609
        basis = tree.basis_tree()
673
610
        basis.lock_read()
674
611
        try:
675
 
            self.assertEqual(kind, basis.kind(path))
 
612
            self.assertEqual(kind, basis.kind(file_id))
676
613
        finally:
677
614
            basis.unlock()
678
615
 
679
 
    def test_unsupported_symlink_commit(self):
680
 
        self.requireFeature(SymlinkFeature)
681
 
        tree = self.make_branch_and_tree('.')
682
 
        self.build_tree(['hello'])
683
 
        tree.add('hello')
684
 
        tree.commit('added hello', rev_id=b'hello_id')
685
 
        os.symlink('hello', 'foo')
686
 
        tree.add('foo')
687
 
        tree.commit('added foo', rev_id=b'foo_id')
688
 
        log = BytesIO()
689
 
        trace.push_log_file(log)
690
 
        os_symlink = getattr(os, 'symlink', None)
691
 
        os.symlink = None
692
 
        try:
693
 
            # At this point as bzr thinks symlinks are not supported
694
 
            # we should get a warning about symlink foo and bzr should
695
 
            # not think its removed.
696
 
            os.unlink('foo')
697
 
            self.build_tree(['world'])
698
 
            tree.add('world')
699
 
            tree.commit('added world', rev_id=b'world_id')
700
 
        finally:
701
 
            if os_symlink:
702
 
                os.symlink = os_symlink
703
 
        self.assertContainsRe(
704
 
            log.getvalue(),
705
 
            b'Ignoring "foo" as symlinks are not '
706
 
            b'supported on this filesystem\\.')
707
 
 
708
616
    def test_commit_kind_changes(self):
709
617
        self.requireFeature(SymlinkFeature)
710
618
        tree = self.make_branch_and_tree('.')
711
619
        os.symlink('target', 'name')
712
 
        tree.add('name', b'a-file-id')
 
620
        tree.add('name', 'a-file-id')
713
621
        tree.commit('Added a symlink')
714
 
        self.assertBasisTreeKind('symlink', tree, 'name')
 
622
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
715
623
 
716
624
        os.unlink('name')
717
625
        self.build_tree(['name'])
718
626
        tree.commit('Changed symlink to file')
719
 
        self.assertBasisTreeKind('file', tree, 'name')
 
627
        self.assertBasisTreeKind('file', tree, 'a-file-id')
720
628
 
721
629
        os.unlink('name')
722
630
        os.symlink('target', 'name')
723
631
        tree.commit('file to symlink')
724
 
        self.assertBasisTreeKind('symlink', tree, 'name')
 
632
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
725
633
 
726
634
        os.unlink('name')
727
635
        os.mkdir('name')
728
636
        tree.commit('symlink to directory')
729
 
        self.assertBasisTreeKind('directory', tree, 'name')
 
637
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
730
638
 
731
639
        os.rmdir('name')
732
640
        os.symlink('target', 'name')
733
641
        tree.commit('directory to symlink')
734
 
        self.assertBasisTreeKind('symlink', tree, 'name')
 
642
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
735
643
 
736
644
        # prepare for directory <-> file tests
737
645
        os.unlink('name')
738
646
        os.mkdir('name')
739
647
        tree.commit('symlink to directory')
740
 
        self.assertBasisTreeKind('directory', tree, 'name')
 
648
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
741
649
 
742
650
        os.rmdir('name')
743
651
        self.build_tree(['name'])
744
652
        tree.commit('Changed directory to file')
745
 
        self.assertBasisTreeKind('file', tree, 'name')
 
653
        self.assertBasisTreeKind('file', tree, 'a-file-id')
746
654
 
747
655
        os.unlink('name')
748
656
        os.mkdir('name')
749
657
        tree.commit('file to directory')
750
 
        self.assertBasisTreeKind('directory', tree, 'name')
 
658
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
751
659
 
752
660
    def test_commit_unversioned_specified(self):
753
661
        """Commit should raise if specified files isn't in basis or worktree"""
773
681
        tree = self.make_branch_and_tree('.')
774
682
        try:
775
683
            tree.commit()
776
 
        except Exception as e:
 
684
        except Exception, e:
777
685
            self.assertTrue(isinstance(e, BzrError))
778
686
            self.assertEqual('The message or message_callback keyword'
779
687
                             ' parameter is required for commit().', str(e))
800
708
        cb = self.Callback(u'commit 2', self)
801
709
        repository = tree.branch.repository
802
710
        # simulate network failure
803
 
 
804
711
        def raise_(self, arg, arg2, arg3=None, arg4=None):
805
712
            raise errors.NoSuchFile('foo')
806
713
        repository.add_inventory = raise_
813
720
        tree = self.make_branch_and_tree('foo')
814
721
        # pending merge would turn into a left parent
815
722
        tree.commit('commit 1')
816
 
        tree.add_parent_tree_id(b'example')
 
723
        tree.add_parent_tree_id('example')
817
724
        self.build_tree(['foo/bar', 'foo/baz'])
818
725
        tree.add(['bar', 'baz'])
819
 
        err = self.assertRaises(CannotCommitSelectedFileMerge,
820
 
                                tree.commit, 'commit 2', specific_files=['bar', 'baz'])
 
726
        err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
 
727
            tree.commit, 'commit 2', specific_files=['bar', 'baz'])
821
728
        self.assertEqual(['bar', 'baz'], err.files)
822
729
        self.assertEqual('Selected-file commit of merges is not supported'
823
730
                         ' yet: files bar, baz', str(err))
844
751
        self.assertFalse('authors' in rev.properties)
845
752
 
846
753
    def test_commit_author(self):
847
 
        """Passing a non-empty authors kwarg to MutableTree.commit should add
 
754
        """Passing a non-empty author kwarg to MutableTree.commit should add
848
755
        the 'author' revision property.
849
756
        """
850
757
        tree = self.make_branch_and_tree('foo')
851
 
        rev_id = tree.commit(
852
 
            'commit 1',
853
 
            authors=['John Doe <jdoe@example.com>'])
 
758
        rev_id = self.callDeprecated(['The parameter author was '
 
759
                'deprecated in version 1.13. Use authors instead'],
 
760
                tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
854
761
        rev = tree.branch.repository.get_revision(rev_id)
855
762
        self.assertEqual('John Doe <jdoe@example.com>',
856
763
                         rev.properties['authors'])
867
774
    def test_multiple_authors(self):
868
775
        tree = self.make_branch_and_tree('foo')
869
776
        rev_id = tree.commit('commit 1',
870
 
                             authors=['John Doe <jdoe@example.com>',
871
 
                                      'Jane Rey <jrey@example.com>'])
 
777
                authors=['John Doe <jdoe@example.com>',
 
778
                         'Jane Rey <jrey@example.com>'])
872
779
        rev = tree.branch.repository.get_revision(rev_id)
873
780
        self.assertEqual('John Doe <jdoe@example.com>\n'
874
 
                         'Jane Rey <jrey@example.com>', rev.properties['authors'])
 
781
                'Jane Rey <jrey@example.com>', rev.properties['authors'])
875
782
        self.assertFalse('author' in rev.properties)
876
783
 
 
784
    def test_author_and_authors_incompatible(self):
 
785
        tree = self.make_branch_and_tree('foo')
 
786
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
 
787
                authors=['John Doe <jdoe@example.com>',
 
788
                         'Jane Rey <jrey@example.com>'],
 
789
                author="Jack Me <jme@example.com>")
 
790
 
877
791
    def test_author_with_newline_rejected(self):
878
792
        tree = self.make_branch_and_tree('foo')
879
793
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
880
 
                          authors=['John\nDoe <jdoe@example.com>'])
 
794
                authors=['John\nDoe <jdoe@example.com>'])
881
795
 
882
796
    def test_commit_with_checkout_and_branch_sharing_repo(self):
883
797
        repo = self.make_repository('repo', shared=True)
884
798
        # make_branch_and_tree ignores shared repos
885
 
        branch = controldir.ControlDir.create_branch_convenience('repo/branch')
 
799
        branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
886
800
        tree2 = branch.create_checkout('repo/tree2')
887
 
        tree2.commit('message', rev_id=b'rev1')
888
 
        self.assertTrue(tree2.branch.repository.has_revision(b'rev1'))
889
 
 
890
 
 
891
 
class FilterExcludedTests(TestCase):
892
 
 
893
 
    def test_add_file_not_excluded(self):
894
 
        changes = [
895
 
            InventoryTreeChange(
896
 
                'fid', (None, 'newpath'),
897
 
                0, (False, False), ('pid', 'pid'), ('newpath', 'newpath'),
898
 
                ('file', 'file'), (True, True))]
899
 
        self.assertEqual(changes, list(
900
 
            filter_excluded(changes, ['otherpath'])))
901
 
 
902
 
    def test_add_file_excluded(self):
903
 
        changes = [
904
 
            InventoryTreeChange(
905
 
                'fid', (None, 'newpath'),
906
 
                0, (False, False), ('pid', 'pid'), ('newpath', 'newpath'),
907
 
                ('file', 'file'), (True, True))]
908
 
        self.assertEqual([], list(filter_excluded(changes, ['newpath'])))
909
 
 
910
 
    def test_delete_file_excluded(self):
911
 
        changes = [
912
 
            InventoryTreeChange(
913
 
                'fid', ('somepath', None),
914
 
                0, (False, None), ('pid', None), ('newpath', None),
915
 
                ('file', None), (True, None))]
916
 
        self.assertEqual([], list(filter_excluded(changes, ['somepath'])))
917
 
 
918
 
    def test_move_from_or_to_excluded(self):
919
 
        changes = [
920
 
            InventoryTreeChange(
921
 
                'fid', ('oldpath', 'newpath'),
922
 
                0, (False, False), ('pid', 'pid'), ('oldpath', 'newpath'),
923
 
                ('file', 'file'), (True, True))]
924
 
        self.assertEqual([], list(filter_excluded(changes, ['oldpath'])))
925
 
        self.assertEqual([], list(filter_excluded(changes, ['newpath'])))
 
801
        tree2.commit('message', rev_id='rev1')
 
802
        self.assertTrue(tree2.branch.repository.has_revision('rev1'))