/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-05 00:05:29 UTC
  • mto: This revision was merged to the branch mainline in revision 5206.
  • Revision ID: robertc@robertcollins.net-20100505000529-ltmllyms5watqj5u
Make 'pydoc bzrlib.tests.build_tree_shape' useful.

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
17
17
 
18
18
import os
19
19
 
20
 
import breezy
21
 
from .. import (
22
 
    config,
23
 
    controldir,
 
20
import bzrlib
 
21
from bzrlib import (
 
22
    bzrdir,
24
23
    errors,
25
 
    )
26
 
from ..branch import Branch
27
 
from ..bzr.bzrdir import BzrDirMetaFormat1
28
 
from ..commit import (
29
 
    CannotCommitSelectedFileMerge,
30
 
    Commit,
31
 
    NullCommitReporter,
32
 
    PointlessCommit,
33
 
    filter_excluded,
34
 
    )
35
 
from ..errors import (
36
 
    BzrError,
37
 
    LockContention,
38
 
    )
39
 
from . import (
40
 
    TestCase,
41
 
    TestCaseWithTransport,
42
 
    test_foreign,
43
 
    )
44
 
from .features import (
45
 
    SymlinkFeature,
46
 
    )
47
 
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
48
36
 
49
37
 
50
38
# TODO: Test commit with some added, and added-but-missing files
51
39
 
52
 
class MustSignConfig(config.MemoryStack):
53
 
 
54
 
    def __init__(self):
55
 
        super(MustSignConfig, self).__init__(b'''
56
 
create_signatures=always
57
 
''')
 
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"
58
53
 
59
54
 
60
55
class CapturingReporter(NullCommitReporter):
86
81
        """Commit and check two versions of a single file."""
87
82
        wt = self.make_branch_and_tree('.')
88
83
        b = wt.branch
89
 
        with open('hello', 'w') as f:
90
 
            f.write('hello world')
 
84
        file('hello', 'w').write('hello world')
91
85
        wt.add('hello')
92
 
        rev1 = wt.commit(message='add hello')
93
 
 
94
 
        with open('hello', 'w') as f:
95
 
            f.write('version 2')
96
 
        rev2 = wt.commit(message='commit 2')
97
 
 
98
 
        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
99
93
        eq(b.revno(), 2)
100
 
        rev = b.repository.get_revision(rev1)
 
94
        rh = b.revision_history()
 
95
        rev = b.repository.get_revision(rh[0])
101
96
        eq(rev.message, 'add hello')
102
97
 
103
 
        tree1 = b.repository.revision_tree(rev1)
 
98
        tree1 = b.repository.revision_tree(rh[0])
104
99
        tree1.lock_read()
105
 
        text = tree1.get_file_text('hello')
 
100
        text = tree1.get_file_text(file_id)
106
101
        tree1.unlock()
107
 
        self.assertEqual(b'hello world', text)
 
102
        self.assertEqual('hello world', text)
108
103
 
109
 
        tree2 = b.repository.revision_tree(rev2)
 
104
        tree2 = b.repository.revision_tree(rh[1])
110
105
        tree2.lock_read()
111
 
        text = tree2.get_file_text('hello')
 
106
        text = tree2.get_file_text(file_id)
112
107
        tree2.unlock()
113
 
        self.assertEqual(b'version 2', text)
114
 
 
115
 
    def test_commit_lossy_native(self):
116
 
        """Attempt a lossy commit to a native branch."""
117
 
        wt = self.make_branch_and_tree('.')
118
 
        b = wt.branch
119
 
        with open('hello', 'w') as f:
120
 
            f.write('hello world')
121
 
        wt.add('hello')
122
 
        revid = wt.commit(message='add hello', rev_id=b'revid', lossy=True)
123
 
        self.assertEqual(b'revid', revid)
124
 
 
125
 
    def test_commit_lossy_foreign(self):
126
 
        """Attempt a lossy commit to a foreign branch."""
127
 
        test_foreign.register_dummy_foreign_for_test(self)
128
 
        wt = self.make_branch_and_tree('.',
129
 
                                       format=test_foreign.DummyForeignVcsDirFormat())
130
 
        b = wt.branch
131
 
        with open('hello', 'w') as f:
132
 
            f.write('hello world')
133
 
        wt.add('hello')
134
 
        revid = wt.commit(message='add hello', lossy=True,
135
 
                          timestamp=1302659388, timezone=0)
136
 
        self.assertEqual(b'dummy-v1:1302659388-0-UNKNOWN', revid)
137
 
 
138
 
    def test_commit_bound_lossy_foreign(self):
139
 
        """Attempt a lossy commit to a bzr branch bound to a foreign branch."""
140
 
        test_foreign.register_dummy_foreign_for_test(self)
141
 
        foreign_branch = self.make_branch('foreign',
142
 
                                          format=test_foreign.DummyForeignVcsDirFormat())
143
 
        wt = foreign_branch.create_checkout("local")
144
 
        b = wt.branch
145
 
        with open('local/hello', 'w') as f:
146
 
            f.write('hello world')
147
 
        wt.add('hello')
148
 
        revid = wt.commit(message='add hello', lossy=True,
149
 
                          timestamp=1302659388, timezone=0)
150
 
        self.assertEqual(b'dummy-v1:1302659388-0-0', revid)
151
 
        self.assertEqual(b'dummy-v1:1302659388-0-0',
152
 
                         foreign_branch.last_revision())
153
 
        self.assertEqual(b'dummy-v1:1302659388-0-0',
154
 
                         wt.branch.last_revision())
 
108
        self.assertEqual('version 2', text)
155
109
 
156
110
    def test_missing_commit(self):
157
111
        """Test a commit with a missing file"""
158
112
        wt = self.make_branch_and_tree('.')
159
113
        b = wt.branch
160
 
        with open('hello', 'w') as f:
161
 
            f.write('hello world')
162
 
        wt.add(['hello'], [b'hello-id'])
 
114
        file('hello', 'w').write('hello world')
 
115
        wt.add(['hello'], ['hello-id'])
163
116
        wt.commit(message='add hello')
164
117
 
165
118
        os.remove('hello')
166
 
        reporter = CapturingReporter()
167
 
        wt.commit('removed hello', rev_id=b'rev2', reporter=reporter)
168
 
        self.assertEqual(
169
 
            [('missing', u'hello'), ('deleted', u'hello')],
170
 
            reporter.calls)
 
119
        wt.commit('removed hello', rev_id='rev2')
171
120
 
172
 
        tree = b.repository.revision_tree(b'rev2')
173
 
        self.assertFalse(tree.has_id(b'hello-id'))
 
121
        tree = b.repository.revision_tree('rev2')
 
122
        self.assertFalse(tree.has_id('hello-id'))
174
123
 
175
124
    def test_partial_commit_move(self):
176
125
        """Test a partial commit where a file was renamed but not committed.
185
134
        b = wt.branch
186
135
        self.build_tree(['annotate/', 'annotate/foo.py',
187
136
                         'olive/', 'olive/dialog.py'
188
 
                         ])
 
137
                        ])
189
138
        wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
190
139
        wt.commit(message='add files')
191
140
        wt.rename_one("olive/dialog.py", "aaa")
192
 
        self.build_tree_contents([('annotate/foo.py', b'modified\n')])
 
141
        self.build_tree_contents([('annotate/foo.py', 'modified\n')])
193
142
        wt.commit('renamed hello', specific_files=["annotate"])
194
143
 
195
144
    def test_pointless_commit(self):
196
145
        """Commit refuses unless there are changes or it's forced."""
197
146
        wt = self.make_branch_and_tree('.')
198
147
        b = wt.branch
199
 
        with open('hello', 'w') as f:
200
 
            f.write('hello')
 
148
        file('hello', 'w').write('hello')
201
149
        wt.add(['hello'])
202
150
        wt.commit(message='add hello')
203
 
        self.assertEqual(b.revno(), 1)
 
151
        self.assertEquals(b.revno(), 1)
204
152
        self.assertRaises(PointlessCommit,
205
153
                          wt.commit,
206
154
                          message='fails',
207
155
                          allow_pointless=False)
208
 
        self.assertEqual(b.revno(), 1)
 
156
        self.assertEquals(b.revno(), 1)
209
157
 
210
158
    def test_commit_empty(self):
211
159
        """Commiting an empty tree works."""
217
165
                          message='empty tree',
218
166
                          allow_pointless=False)
219
167
        wt.commit(message='empty tree', allow_pointless=True)
220
 
        self.assertEqual(b.revno(), 2)
 
168
        self.assertEquals(b.revno(), 2)
221
169
 
222
170
    def test_selective_delete(self):
223
171
        """Selective commit in tree with deletions"""
224
172
        wt = self.make_branch_and_tree('.')
225
173
        b = wt.branch
226
 
        with open('hello', 'w') as f:
227
 
            f.write('hello')
228
 
        with open('buongia', 'w') as f:
229
 
            f.write('buongia')
 
174
        file('hello', 'w').write('hello')
 
175
        file('buongia', 'w').write('buongia')
230
176
        wt.add(['hello', 'buongia'],
231
 
               [b'hello-id', b'buongia-id'])
 
177
              ['hello-id', 'buongia-id'])
232
178
        wt.commit(message='add files',
233
 
                  rev_id=b'test@rev-1')
 
179
                 rev_id='test@rev-1')
234
180
 
235
181
        os.remove('hello')
236
 
        with open('buongia', 'w') as f:
237
 
            f.write('new text')
 
182
        file('buongia', 'w').write('new text')
238
183
        wt.commit(message='update text',
239
 
                  specific_files=['buongia'],
240
 
                  allow_pointless=False,
241
 
                  rev_id=b'test@rev-2')
 
184
                 specific_files=['buongia'],
 
185
                 allow_pointless=False,
 
186
                 rev_id='test@rev-2')
242
187
 
243
188
        wt.commit(message='remove hello',
244
 
                  specific_files=['hello'],
245
 
                  allow_pointless=False,
246
 
                  rev_id=b'test@rev-3')
 
189
                 specific_files=['hello'],
 
190
                 allow_pointless=False,
 
191
                 rev_id='test@rev-3')
247
192
 
248
 
        eq = self.assertEqual
 
193
        eq = self.assertEquals
249
194
        eq(b.revno(), 3)
250
195
 
251
 
        tree2 = b.repository.revision_tree(b'test@rev-2')
 
196
        tree2 = b.repository.revision_tree('test@rev-2')
252
197
        tree2.lock_read()
253
198
        self.addCleanup(tree2.unlock)
254
199
        self.assertTrue(tree2.has_filename('hello'))
255
 
        self.assertEqual(tree2.get_file_text('hello'), b'hello')
256
 
        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')
257
202
 
258
 
        tree3 = b.repository.revision_tree(b'test@rev-3')
 
203
        tree3 = b.repository.revision_tree('test@rev-3')
259
204
        tree3.lock_read()
260
205
        self.addCleanup(tree3.unlock)
261
206
        self.assertFalse(tree3.has_filename('hello'))
262
 
        self.assertEqual(tree3.get_file_text('buongia'), b'new text')
 
207
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
263
208
 
264
209
    def test_commit_rename(self):
265
210
        """Test commit of a revision where a file is renamed."""
266
211
        tree = self.make_branch_and_tree('.')
267
212
        b = tree.branch
268
213
        self.build_tree(['hello'], line_endings='binary')
269
 
        tree.add(['hello'], [b'hello-id'])
270
 
        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)
271
216
 
272
217
        tree.rename_one('hello', 'fruity')
273
 
        tree.commit(message='renamed', rev_id=b'test@rev-2',
274
 
                    allow_pointless=False)
 
218
        tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
275
219
 
276
 
        eq = self.assertEqual
277
 
        tree1 = b.repository.revision_tree(b'test@rev-1')
 
220
        eq = self.assertEquals
 
221
        tree1 = b.repository.revision_tree('test@rev-1')
278
222
        tree1.lock_read()
279
223
        self.addCleanup(tree1.unlock)
280
 
        eq(tree1.id2path(b'hello-id'), 'hello')
281
 
        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')
282
226
        self.assertFalse(tree1.has_filename('fruity'))
283
 
        self.check_tree_shape(tree1, ['hello'])
284
 
        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')
285
230
 
286
 
        tree2 = b.repository.revision_tree(b'test@rev-2')
 
231
        tree2 = b.repository.revision_tree('test@rev-2')
287
232
        tree2.lock_read()
288
233
        self.addCleanup(tree2.unlock)
289
 
        eq(tree2.id2path(b'hello-id'), 'fruity')
290
 
        eq(tree2.get_file_text('fruity'), b'contents of hello\n')
291
 
        self.check_tree_shape(tree2, ['fruity'])
292
 
        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')
293
239
 
294
240
    def test_reused_rev_id(self):
295
241
        """Test that a revision id cannot be reused in a branch"""
296
242
        wt = self.make_branch_and_tree('.')
297
243
        b = wt.branch
298
 
        wt.commit('initial', rev_id=b'test@rev-1', allow_pointless=True)
 
244
        wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
299
245
        self.assertRaises(Exception,
300
246
                          wt.commit,
301
247
                          message='reused id',
302
 
                          rev_id=b'test@rev-1',
 
248
                          rev_id='test@rev-1',
303
249
                          allow_pointless=True)
304
250
 
305
251
    def test_commit_move(self):
306
252
        """Test commit of revisions with moved files and directories"""
307
 
        eq = self.assertEqual
 
253
        eq = self.assertEquals
308
254
        wt = self.make_branch_and_tree('.')
309
255
        b = wt.branch
310
 
        r1 = b'test@rev-1'
 
256
        r1 = 'test@rev-1'
311
257
        self.build_tree(['hello', 'a/', 'b/'])
312
 
        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'])
313
259
        wt.commit('initial', rev_id=r1, allow_pointless=False)
314
260
        wt.move(['hello'], 'a')
315
 
        r2 = b'test@rev-2'
 
261
        r2 = 'test@rev-2'
316
262
        wt.commit('two', rev_id=r2, allow_pointless=False)
317
263
        wt.lock_read()
318
264
        try:
319
 
            self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
 
265
            self.check_inventory_shape(wt.read_working_inventory(),
 
266
                                       ['a/', 'a/hello', 'b/'])
320
267
        finally:
321
268
            wt.unlock()
322
269
 
323
270
        wt.move(['b'], 'a')
324
 
        r3 = b'test@rev-3'
 
271
        r3 = 'test@rev-3'
325
272
        wt.commit('three', rev_id=r3, allow_pointless=False)
326
273
        wt.lock_read()
327
274
        try:
328
 
            self.check_tree_shape(wt,
329
 
                                  ['a/', 'a/hello', 'a/b/'])
330
 
            self.check_tree_shape(b.repository.revision_tree(r3),
331
 
                                  ['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/'])
332
279
        finally:
333
280
            wt.unlock()
334
281
 
335
282
        wt.move(['a/hello'], 'a/b')
336
 
        r4 = b'test@rev-4'
 
283
        r4 = 'test@rev-4'
337
284
        wt.commit('four', rev_id=r4, allow_pointless=False)
338
285
        wt.lock_read()
339
286
        try:
340
 
            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/'])
341
289
        finally:
342
290
            wt.unlock()
343
291
 
344
292
        inv = b.repository.get_inventory(r4)
345
 
        eq(inv.get_entry(b'hello-id').revision, r4)
346
 
        eq(inv.get_entry(b'a-id').revision, r1)
347
 
        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)
348
296
 
349
297
    def test_removed_commit(self):
350
298
        """Commit with a removed file"""
351
299
        wt = self.make_branch_and_tree('.')
352
300
        b = wt.branch
353
 
        with open('hello', 'w') as f:
354
 
            f.write('hello world')
355
 
        wt.add(['hello'], [b'hello-id'])
 
301
        file('hello', 'w').write('hello world')
 
302
        wt.add(['hello'], ['hello-id'])
356
303
        wt.commit(message='add hello')
357
304
        wt.remove('hello')
358
 
        wt.commit('removed hello', rev_id=b'rev2')
 
305
        wt.commit('removed hello', rev_id='rev2')
359
306
 
360
 
        tree = b.repository.revision_tree(b'rev2')
361
 
        self.assertFalse(tree.has_id(b'hello-id'))
 
307
        tree = b.repository.revision_tree('rev2')
 
308
        self.assertFalse(tree.has_id('hello-id'))
362
309
 
363
310
    def test_committed_ancestry(self):
364
311
        """Test commit appends revisions to ancestry."""
366
313
        b = wt.branch
367
314
        rev_ids = []
368
315
        for i in range(4):
369
 
            with open('hello', 'w') as f:
370
 
                f.write((str(i) * 4) + '\n')
 
316
            file('hello', 'w').write((str(i) * 4) + '\n')
371
317
            if i == 0:
372
 
                wt.add(['hello'], [b'hello-id'])
373
 
            rev_id = b'test@rev-%d' % (i + 1)
 
318
                wt.add(['hello'], ['hello-id'])
 
319
            rev_id = 'test@rev-%d' % (i+1)
374
320
            rev_ids.append(rev_id)
375
 
            wt.commit(message='rev %d' % (i + 1),
376
 
                      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)
377
325
        for i in range(4):
378
 
            self.assertThat(rev_ids[:i + 1],
379
 
                            MatchesAncestry(b.repository, rev_ids[i]))
 
326
            anc = b.repository.get_ancestry(rev_ids[i])
 
327
            eq(anc, [None] + rev_ids[:i+1])
380
328
 
381
329
    def test_commit_new_subdir_child_selective(self):
382
330
        wt = self.make_branch_and_tree('.')
383
331
        b = wt.branch
384
332
        self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
385
333
        wt.add(['dir', 'dir/file1', 'dir/file2'],
386
 
               [b'dirid', b'file1id', b'file2id'])
387
 
        wt.commit('dir/file1', specific_files=['dir/file1'], rev_id=b'1')
388
 
        inv = b.repository.get_inventory(b'1')
389
 
        self.assertEqual(b'1', inv.get_entry(b'dirid').revision)
390
 
        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)
391
339
        # FIXME: This should raise a KeyError I think, rbc20051006
392
 
        self.assertRaises(BzrError, inv.get_entry, b'file2id')
 
340
        self.assertRaises(BzrError, inv.__getitem__, 'file2id')
393
341
 
394
342
    def test_strict_commit(self):
395
343
        """Try and commit with unknown files and strict = True, should fail."""
396
 
        from ..errors import StrictCommitFailed
 
344
        from bzrlib.errors import StrictCommitFailed
397
345
        wt = self.make_branch_and_tree('.')
398
346
        b = wt.branch
399
 
        with open('hello', 'w') as f:
400
 
            f.write('hello world')
 
347
        file('hello', 'w').write('hello world')
401
348
        wt.add('hello')
402
 
        with open('goodbye', 'w') as f:
403
 
            f.write('goodbye cruel world!')
 
349
        file('goodbye', 'w').write('goodbye cruel world!')
404
350
        self.assertRaises(StrictCommitFailed, wt.commit,
405
 
                          message='add hello but not goodbye', strict=True)
 
351
            message='add hello but not goodbye', strict=True)
406
352
 
407
353
    def test_strict_commit_without_unknowns(self):
408
354
        """Try and commit with no unknown files and strict = True,
409
355
        should work."""
 
356
        from bzrlib.errors import StrictCommitFailed
410
357
        wt = self.make_branch_and_tree('.')
411
358
        b = wt.branch
412
 
        with open('hello', 'w') as f:
413
 
            f.write('hello world')
 
359
        file('hello', 'w').write('hello world')
414
360
        wt.add('hello')
415
361
        wt.commit(message='add hello', strict=True)
416
362
 
418
364
        """Try and commit with unknown files and strict = False, should work."""
419
365
        wt = self.make_branch_and_tree('.')
420
366
        b = wt.branch
421
 
        with open('hello', 'w') as f:
422
 
            f.write('hello world')
 
367
        file('hello', 'w').write('hello world')
423
368
        wt.add('hello')
424
 
        with open('goodbye', 'w') as f:
425
 
            f.write('goodbye cruel world!')
 
369
        file('goodbye', 'w').write('goodbye cruel world!')
426
370
        wt.commit(message='add hello but not goodbye', strict=False)
427
371
 
428
372
    def test_nonstrict_commit_without_unknowns(self):
430
374
        should work."""
431
375
        wt = self.make_branch_and_tree('.')
432
376
        b = wt.branch
433
 
        with open('hello', 'w') as f:
434
 
            f.write('hello world')
 
377
        file('hello', 'w').write('hello world')
435
378
        wt.add('hello')
436
379
        wt.commit(message='add hello', strict=False)
437
380
 
438
381
    def test_signed_commit(self):
439
 
        import breezy.gpg
440
 
        import breezy.commit as commit
441
 
        oldstrategy = breezy.gpg.GPGStrategy
 
382
        import bzrlib.gpg
 
383
        import bzrlib.commit as commit
 
384
        oldstrategy = bzrlib.gpg.GPGStrategy
442
385
        wt = self.make_branch_and_tree('.')
443
386
        branch = wt.branch
444
 
        wt.commit("base", allow_pointless=True, rev_id=b'A')
445
 
        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'))
446
389
        try:
447
 
            from ..testament import Testament
 
390
            from bzrlib.testament import Testament
448
391
            # monkey patch gpg signing mechanism
449
 
            breezy.gpg.GPGStrategy = breezy.gpg.LoopbackGPGStrategy
450
 
            conf = config.MemoryStack(b'''
451
 
create_signatures=always
452
 
''')
453
 
            commit.Commit(config_stack=conf).commit(
454
 
                message="base", allow_pointless=True, rev_id=b'B',
455
 
                working_tree=wt)
456
 
 
 
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)
457
397
            def sign(text):
458
 
                return breezy.gpg.LoopbackGPGStrategy(None).sign(
459
 
                    text, breezy.gpg.MODE_CLEAR)
 
398
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
460
399
            self.assertEqual(sign(Testament.from_revision(branch.repository,
461
 
                                                          b'B').as_short_text()),
462
 
                             branch.repository.get_signature_text(b'B'))
 
400
                             'B').as_short_text()),
 
401
                             branch.repository.get_signature_text('B'))
463
402
        finally:
464
 
            breezy.gpg.GPGStrategy = oldstrategy
 
403
            bzrlib.gpg.GPGStrategy = oldstrategy
465
404
 
466
405
    def test_commit_failed_signature(self):
467
 
        import breezy.gpg
468
 
        import breezy.commit as commit
469
 
        oldstrategy = breezy.gpg.GPGStrategy
 
406
        import bzrlib.gpg
 
407
        import bzrlib.commit as commit
 
408
        oldstrategy = bzrlib.gpg.GPGStrategy
470
409
        wt = self.make_branch_and_tree('.')
471
410
        branch = wt.branch
472
 
        wt.commit("base", allow_pointless=True, rev_id=b'A')
473
 
        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'))
474
413
        try:
 
414
            from bzrlib.testament import Testament
475
415
            # monkey patch gpg signing mechanism
476
 
            breezy.gpg.GPGStrategy = breezy.gpg.DisabledGPGStrategy
477
 
            conf = config.MemoryStack(b'''
478
 
create_signatures=always
479
 
''')
480
 
            self.assertRaises(breezy.gpg.SigningFailed,
481
 
                              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,
482
420
                              message="base",
483
421
                              allow_pointless=True,
484
 
                              rev_id=b'B',
 
422
                              rev_id='B',
485
423
                              working_tree=wt)
486
424
            branch = Branch.open(self.get_url('.'))
487
 
            self.assertEqual(branch.last_revision(), b'A')
488
 
            self.assertFalse(branch.repository.has_revision(b'B'))
 
425
            self.assertEqual(branch.revision_history(), ['A'])
 
426
            self.failIf(branch.repository.has_revision('B'))
489
427
        finally:
490
 
            breezy.gpg.GPGStrategy = oldstrategy
 
428
            bzrlib.gpg.GPGStrategy = oldstrategy
491
429
 
492
430
    def test_commit_invokes_hooks(self):
493
 
        import breezy.commit as commit
 
431
        import bzrlib.commit as commit
494
432
        wt = self.make_branch_and_tree('.')
495
433
        branch = wt.branch
496
434
        calls = []
497
 
 
498
435
        def called(branch, rev_id):
499
436
            calls.append('called')
500
 
        breezy.ahook = called
 
437
        bzrlib.ahook = called
501
438
        try:
502
 
            conf = config.MemoryStack(b'post_commit=breezy.ahook breezy.ahook')
503
 
            commit.Commit(config_stack=conf).commit(
504
 
                message="base", allow_pointless=True, rev_id=b'A',
505
 
                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)
506
444
            self.assertEqual(['called', 'called'], calls)
507
445
        finally:
508
 
            del breezy.ahook
 
446
            del bzrlib.ahook
509
447
 
510
448
    def test_commit_object_doesnt_set_nick(self):
511
449
        # using the Commit object directly does not set the branch nick.
512
450
        wt = self.make_branch_and_tree('.')
513
451
        c = Commit()
514
452
        c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
515
 
        self.assertEqual(wt.branch.revno(), 1)
 
453
        self.assertEquals(wt.branch.revno(), 1)
516
454
        self.assertEqual({},
517
455
                         wt.branch.repository.get_revision(
518
 
            wt.branch.last_revision()).properties)
 
456
                            wt.branch.last_revision()).properties)
519
457
 
520
458
    def test_safe_master_lock(self):
521
459
        os.mkdir('master')
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
 
680
617
        self.requireFeature(SymlinkFeature)
681
618
        tree = self.make_branch_and_tree('.')
682
619
        os.symlink('target', 'name')
683
 
        tree.add('name', b'a-file-id')
 
620
        tree.add('name', 'a-file-id')
684
621
        tree.commit('Added a symlink')
685
 
        self.assertBasisTreeKind('symlink', tree, 'name')
 
622
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
686
623
 
687
624
        os.unlink('name')
688
625
        self.build_tree(['name'])
689
626
        tree.commit('Changed symlink to file')
690
 
        self.assertBasisTreeKind('file', tree, 'name')
 
627
        self.assertBasisTreeKind('file', tree, 'a-file-id')
691
628
 
692
629
        os.unlink('name')
693
630
        os.symlink('target', 'name')
694
631
        tree.commit('file to symlink')
695
 
        self.assertBasisTreeKind('symlink', tree, 'name')
 
632
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
696
633
 
697
634
        os.unlink('name')
698
635
        os.mkdir('name')
699
636
        tree.commit('symlink to directory')
700
 
        self.assertBasisTreeKind('directory', tree, 'name')
 
637
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
701
638
 
702
639
        os.rmdir('name')
703
640
        os.symlink('target', 'name')
704
641
        tree.commit('directory to symlink')
705
 
        self.assertBasisTreeKind('symlink', tree, 'name')
 
642
        self.assertBasisTreeKind('symlink', tree, 'a-file-id')
706
643
 
707
644
        # prepare for directory <-> file tests
708
645
        os.unlink('name')
709
646
        os.mkdir('name')
710
647
        tree.commit('symlink to directory')
711
 
        self.assertBasisTreeKind('directory', tree, 'name')
 
648
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
712
649
 
713
650
        os.rmdir('name')
714
651
        self.build_tree(['name'])
715
652
        tree.commit('Changed directory to file')
716
 
        self.assertBasisTreeKind('file', tree, 'name')
 
653
        self.assertBasisTreeKind('file', tree, 'a-file-id')
717
654
 
718
655
        os.unlink('name')
719
656
        os.mkdir('name')
720
657
        tree.commit('file to directory')
721
 
        self.assertBasisTreeKind('directory', tree, 'name')
 
658
        self.assertBasisTreeKind('directory', tree, 'a-file-id')
722
659
 
723
660
    def test_commit_unversioned_specified(self):
724
661
        """Commit should raise if specified files isn't in basis or worktree"""
744
681
        tree = self.make_branch_and_tree('.')
745
682
        try:
746
683
            tree.commit()
747
 
        except Exception as e:
 
684
        except Exception, e:
748
685
            self.assertTrue(isinstance(e, BzrError))
749
686
            self.assertEqual('The message or message_callback keyword'
750
687
                             ' parameter is required for commit().', str(e))
771
708
        cb = self.Callback(u'commit 2', self)
772
709
        repository = tree.branch.repository
773
710
        # simulate network failure
774
 
 
775
711
        def raise_(self, arg, arg2, arg3=None, arg4=None):
776
712
            raise errors.NoSuchFile('foo')
777
713
        repository.add_inventory = raise_
784
720
        tree = self.make_branch_and_tree('foo')
785
721
        # pending merge would turn into a left parent
786
722
        tree.commit('commit 1')
787
 
        tree.add_parent_tree_id(b'example')
 
723
        tree.add_parent_tree_id('example')
788
724
        self.build_tree(['foo/bar', 'foo/baz'])
789
725
        tree.add(['bar', 'baz'])
790
 
        err = self.assertRaises(CannotCommitSelectedFileMerge,
791
 
                                tree.commit, 'commit 2', specific_files=['bar', 'baz'])
 
726
        err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
 
727
            tree.commit, 'commit 2', specific_files=['bar', 'baz'])
792
728
        self.assertEqual(['bar', 'baz'], err.files)
793
729
        self.assertEqual('Selected-file commit of merges is not supported'
794
730
                         ' yet: files bar, baz', str(err))
815
751
        self.assertFalse('authors' in rev.properties)
816
752
 
817
753
    def test_commit_author(self):
818
 
        """Passing a non-empty authors kwarg to MutableTree.commit should add
 
754
        """Passing a non-empty author kwarg to MutableTree.commit should add
819
755
        the 'author' revision property.
820
756
        """
821
757
        tree = self.make_branch_and_tree('foo')
822
 
        rev_id = tree.commit(
823
 
            'commit 1',
824
 
            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>')
825
761
        rev = tree.branch.repository.get_revision(rev_id)
826
762
        self.assertEqual('John Doe <jdoe@example.com>',
827
763
                         rev.properties['authors'])
838
774
    def test_multiple_authors(self):
839
775
        tree = self.make_branch_and_tree('foo')
840
776
        rev_id = tree.commit('commit 1',
841
 
                             authors=['John Doe <jdoe@example.com>',
842
 
                                      'Jane Rey <jrey@example.com>'])
 
777
                authors=['John Doe <jdoe@example.com>',
 
778
                         'Jane Rey <jrey@example.com>'])
843
779
        rev = tree.branch.repository.get_revision(rev_id)
844
780
        self.assertEqual('John Doe <jdoe@example.com>\n'
845
 
                         'Jane Rey <jrey@example.com>', rev.properties['authors'])
 
781
                'Jane Rey <jrey@example.com>', rev.properties['authors'])
846
782
        self.assertFalse('author' in rev.properties)
847
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
 
848
791
    def test_author_with_newline_rejected(self):
849
792
        tree = self.make_branch_and_tree('foo')
850
793
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
851
 
                          authors=['John\nDoe <jdoe@example.com>'])
 
794
                authors=['John\nDoe <jdoe@example.com>'])
852
795
 
853
796
    def test_commit_with_checkout_and_branch_sharing_repo(self):
854
797
        repo = self.make_repository('repo', shared=True)
855
798
        # make_branch_and_tree ignores shared repos
856
 
        branch = controldir.ControlDir.create_branch_convenience('repo/branch')
 
799
        branch = bzrdir.BzrDir.create_branch_convenience('repo/branch')
857
800
        tree2 = branch.create_checkout('repo/tree2')
858
 
        tree2.commit('message', rev_id=b'rev1')
859
 
        self.assertTrue(tree2.branch.repository.has_revision(b'rev1'))
860
 
 
861
 
 
862
 
class FilterExcludedTests(TestCase):
863
 
 
864
 
    def test_add_file_not_excluded(self):
865
 
        changes = [
866
 
            ('fid', (None, 'newpath'),
867
 
             0, (False, False), ('pid', 'pid'), ('newpath', 'newpath'),
868
 
             ('file', 'file'), (True, True))]
869
 
        self.assertEqual(changes, list(
870
 
            filter_excluded(changes, ['otherpath'])))
871
 
 
872
 
    def test_add_file_excluded(self):
873
 
        changes = [
874
 
            ('fid', (None, 'newpath'),
875
 
             0, (False, False), ('pid', 'pid'), ('newpath', 'newpath'),
876
 
             ('file', 'file'), (True, True))]
877
 
        self.assertEqual([], list(filter_excluded(changes, ['newpath'])))
878
 
 
879
 
    def test_delete_file_excluded(self):
880
 
        changes = [
881
 
            ('fid', ('somepath', None),
882
 
             0, (False, None), ('pid', None), ('newpath', None),
883
 
             ('file', None), (True, None))]
884
 
        self.assertEqual([], list(filter_excluded(changes, ['somepath'])))
885
 
 
886
 
    def test_move_from_or_to_excluded(self):
887
 
        changes = [
888
 
            ('fid', ('oldpath', 'newpath'),
889
 
             0, (False, False), ('pid', 'pid'), ('oldpath', 'newpath'),
890
 
             ('file', 'file'), (True, True))]
891
 
        self.assertEqual([], list(filter_excluded(changes, ['oldpath'])))
892
 
        self.assertEqual([], list(filter_excluded(changes, ['newpath'])))
 
801
        tree2.commit('message', rev_id='rev1')
 
802
        self.assertTrue(tree2.branch.repository.has_revision('rev1'))