~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_commit.py

  • Committer: Martin Pool
  • Date: 2007-03-22 05:27:08 UTC
  • mto: (2323.5.2 0.15)
  • mto: This revision was merged to the branch mainline in revision 2390.
  • Revision ID: mbp@sourcefrog.net-20070322052708-t4g4iv46n2dcjjaa
(broken) Give a message when opening old workingtree formats suggesting upgrade

This breaks some blackbox tests of old formats that don't expect to see this
message.

Add WorkingTree._after_opening callback

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2012, 2016 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
 
18
18
import os
19
19
 
20
20
import bzrlib
21
21
from bzrlib import (
22
 
    config,
23
 
    controldir,
24
22
    errors,
 
23
    lockdir,
 
24
    osutils,
 
25
    tests,
25
26
    )
26
27
from bzrlib.branch import Branch
27
 
from bzrlib.bzrdir import BzrDirMetaFormat1
 
28
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
28
29
from bzrlib.commit import Commit, NullCommitReporter
29
 
from bzrlib.errors import (
30
 
    PointlessCommit,
31
 
    BzrError,
32
 
    SigningFailed,
33
 
    LockContention,
34
 
    )
35
 
from bzrlib.tests import (
36
 
    TestCaseWithTransport,
37
 
    test_foreign,
38
 
    )
39
 
from bzrlib.tests.features import (
40
 
    SymlinkFeature,
41
 
    )
42
 
from bzrlib.tests.matchers import MatchesAncestry
 
30
from bzrlib.config import BranchConfig
 
31
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed, 
 
32
                           LockContention)
 
33
from bzrlib.tests import TestCaseWithTransport
 
34
from bzrlib.workingtree import WorkingTree
43
35
 
44
36
 
45
37
# TODO: Test commit with some added, and added-but-missing files
46
38
 
47
 
class MustSignConfig(config.MemoryStack):
48
 
 
49
 
    def __init__(self):
50
 
        super(MustSignConfig, self).__init__('''
51
 
gpg_signing_command=cat -
52
 
create_signatures=always
53
 
''')
 
39
class MustSignConfig(BranchConfig):
 
40
 
 
41
    def signature_needed(self):
 
42
        return True
 
43
 
 
44
    def gpg_signing_command(self):
 
45
        return ['cat', '-']
 
46
 
 
47
 
 
48
class BranchWithHooks(BranchConfig):
 
49
 
 
50
    def post_commit(self):
 
51
        return "bzrlib.ahook bzrlib.ahook"
54
52
 
55
53
 
56
54
class CapturingReporter(NullCommitReporter):
72
70
    def renamed(self, change, old_path, new_path):
73
71
        self.calls.append(('renamed', change, old_path, new_path))
74
72
 
75
 
    def is_verbose(self):
76
 
        return True
77
 
 
78
73
 
79
74
class TestCommit(TestCaseWithTransport):
80
75
 
82
77
        """Commit and check two versions of a single file."""
83
78
        wt = self.make_branch_and_tree('.')
84
79
        b = wt.branch
85
 
        with file('hello', 'w') as f: f.write('hello world')
 
80
        file('hello', 'w').write('hello world')
86
81
        wt.add('hello')
87
 
        rev1 = wt.commit(message='add hello')
 
82
        wt.commit(message='add hello')
88
83
        file_id = wt.path2id('hello')
89
84
 
90
 
        with file('hello', 'w') as f: f.write('version 2')
91
 
        rev2 = wt.commit(message='commit 2')
 
85
        file('hello', 'w').write('version 2')
 
86
        wt.commit(message='commit 2')
92
87
 
93
 
        eq = self.assertEqual
 
88
        eq = self.assertEquals
94
89
        eq(b.revno(), 2)
95
 
        rev = b.repository.get_revision(rev1)
 
90
        rh = b.revision_history()
 
91
        rev = b.repository.get_revision(rh[0])
96
92
        eq(rev.message, 'add hello')
97
93
 
98
 
        tree1 = b.repository.revision_tree(rev1)
99
 
        tree1.lock_read()
 
94
        tree1 = b.repository.revision_tree(rh[0])
100
95
        text = tree1.get_file_text(file_id)
101
 
        tree1.unlock()
102
 
        self.assertEqual('hello world', text)
103
 
 
104
 
        tree2 = b.repository.revision_tree(rev2)
105
 
        tree2.lock_read()
106
 
        text = tree2.get_file_text(file_id)
107
 
        tree2.unlock()
108
 
        self.assertEqual('version 2', text)
109
 
 
110
 
    def test_commit_lossy_native(self):
111
 
        """Attempt a lossy commit to a native branch."""
112
 
        wt = self.make_branch_and_tree('.')
113
 
        b = wt.branch
114
 
        with file('hello', 'w') as f: f.write('hello world')
115
 
        wt.add('hello')
116
 
        revid = wt.commit(message='add hello', rev_id='revid', lossy=True)
117
 
        self.assertEqual('revid', revid)
118
 
 
119
 
    def test_commit_lossy_foreign(self):
120
 
        """Attempt a lossy commit to a foreign branch."""
121
 
        test_foreign.register_dummy_foreign_for_test(self)
122
 
        wt = self.make_branch_and_tree('.',
123
 
            format=test_foreign.DummyForeignVcsDirFormat())
124
 
        b = wt.branch
125
 
        with file('hello', 'w') as f: f.write('hello world')
126
 
        wt.add('hello')
127
 
        revid = wt.commit(message='add hello', lossy=True,
128
 
            timestamp=1302659388, timezone=0)
129
 
        self.assertEqual('dummy-v1:1302659388.0-0-UNKNOWN', revid)
130
 
 
131
 
    def test_commit_bound_lossy_foreign(self):
132
 
        """Attempt a lossy commit to a bzr branch bound to a foreign branch."""
133
 
        test_foreign.register_dummy_foreign_for_test(self)
134
 
        foreign_branch = self.make_branch('foreign',
135
 
            format=test_foreign.DummyForeignVcsDirFormat())
136
 
        wt = foreign_branch.create_checkout("local")
137
 
        b = wt.branch
138
 
        with file('local/hello', 'w') as f: f.write('hello world')
139
 
        wt.add('hello')
140
 
        revid = wt.commit(message='add hello', lossy=True,
141
 
            timestamp=1302659388, timezone=0)
142
 
        self.assertEqual('dummy-v1:1302659388.0-0-0', revid)
143
 
        self.assertEqual('dummy-v1:1302659388.0-0-0',
144
 
            foreign_branch.last_revision())
145
 
        self.assertEqual('dummy-v1:1302659388.0-0-0',
146
 
            wt.branch.last_revision())
147
 
 
148
 
    def test_missing_commit(self):
149
 
        """Test a commit with a missing file"""
150
 
        wt = self.make_branch_and_tree('.')
151
 
        b = wt.branch
152
 
        with file('hello', 'w') as f: f.write('hello world')
 
96
        eq(text, 'hello world')
 
97
 
 
98
        tree2 = b.repository.revision_tree(rh[1])
 
99
        eq(tree2.get_file_text(file_id), 'version 2')
 
100
 
 
101
    def test_delete_commit(self):
 
102
        """Test a commit with a deleted file"""
 
103
        wt = self.make_branch_and_tree('.')
 
104
        b = wt.branch
 
105
        file('hello', 'w').write('hello world')
153
106
        wt.add(['hello'], ['hello-id'])
154
107
        wt.commit(message='add hello')
155
108
 
156
109
        os.remove('hello')
157
 
        reporter = CapturingReporter()
158
 
        wt.commit('removed hello', rev_id='rev2', reporter=reporter)
159
 
        self.assertEqual(
160
 
            [('missing', u'hello'), ('deleted', u'hello')],
161
 
            reporter.calls)
 
110
        wt.commit('removed hello', rev_id='rev2')
162
111
 
163
112
        tree = b.repository.revision_tree('rev2')
164
113
        self.assertFalse(tree.has_id('hello-id'))
165
114
 
166
 
    def test_partial_commit_move(self):
167
 
        """Test a partial commit where a file was renamed but not committed.
168
 
 
169
 
        https://bugs.launchpad.net/bzr/+bug/83039
170
 
 
171
 
        If not handled properly, commit will try to snapshot
172
 
        dialog.py with olive/ as a parent, while
173
 
        olive/ has not been snapshotted yet.
174
 
        """
175
 
        wt = self.make_branch_and_tree('.')
176
 
        b = wt.branch
177
 
        self.build_tree(['annotate/', 'annotate/foo.py',
178
 
                         'olive/', 'olive/dialog.py'
179
 
                        ])
180
 
        wt.add(['annotate', 'olive', 'annotate/foo.py', 'olive/dialog.py'])
181
 
        wt.commit(message='add files')
182
 
        wt.rename_one("olive/dialog.py", "aaa")
183
 
        self.build_tree_contents([('annotate/foo.py', 'modified\n')])
184
 
        wt.commit('renamed hello', specific_files=["annotate"])
185
 
 
186
115
    def test_pointless_commit(self):
187
116
        """Commit refuses unless there are changes or it's forced."""
188
117
        wt = self.make_branch_and_tree('.')
189
118
        b = wt.branch
190
 
        with file('hello', 'w') as f: f.write('hello')
 
119
        file('hello', 'w').write('hello')
191
120
        wt.add(['hello'])
192
121
        wt.commit(message='add hello')
193
 
        self.assertEqual(b.revno(), 1)
 
122
        self.assertEquals(b.revno(), 1)
194
123
        self.assertRaises(PointlessCommit,
195
124
                          wt.commit,
196
125
                          message='fails',
197
126
                          allow_pointless=False)
198
 
        self.assertEqual(b.revno(), 1)
199
 
 
 
127
        self.assertEquals(b.revno(), 1)
 
128
        
200
129
    def test_commit_empty(self):
201
130
        """Commiting an empty tree works."""
202
131
        wt = self.make_branch_and_tree('.')
207
136
                          message='empty tree',
208
137
                          allow_pointless=False)
209
138
        wt.commit(message='empty tree', allow_pointless=True)
210
 
        self.assertEqual(b.revno(), 2)
 
139
        self.assertEquals(b.revno(), 2)
211
140
 
212
141
    def test_selective_delete(self):
213
142
        """Selective commit in tree with deletions"""
214
143
        wt = self.make_branch_and_tree('.')
215
144
        b = wt.branch
216
 
        with file('hello', 'w') as f: f.write('hello')
217
 
        with file('buongia', 'w') as f: f.write('buongia')
 
145
        file('hello', 'w').write('hello')
 
146
        file('buongia', 'w').write('buongia')
218
147
        wt.add(['hello', 'buongia'],
219
148
              ['hello-id', 'buongia-id'])
220
149
        wt.commit(message='add files',
221
150
                 rev_id='test@rev-1')
222
 
 
 
151
        
223
152
        os.remove('hello')
224
 
        with file('buongia', 'w') as f: f.write('new text')
 
153
        file('buongia', 'w').write('new text')
225
154
        wt.commit(message='update text',
226
155
                 specific_files=['buongia'],
227
156
                 allow_pointless=False,
232
161
                 allow_pointless=False,
233
162
                 rev_id='test@rev-3')
234
163
 
235
 
        eq = self.assertEqual
 
164
        eq = self.assertEquals
236
165
        eq(b.revno(), 3)
237
166
 
238
167
        tree2 = b.repository.revision_tree('test@rev-2')
239
 
        tree2.lock_read()
240
 
        self.addCleanup(tree2.unlock)
241
168
        self.assertTrue(tree2.has_filename('hello'))
242
 
        self.assertEqual(tree2.get_file_text('hello-id'), 'hello')
243
 
        self.assertEqual(tree2.get_file_text('buongia-id'), 'new text')
244
 
 
 
169
        self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
 
170
        self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
 
171
        
245
172
        tree3 = b.repository.revision_tree('test@rev-3')
246
 
        tree3.lock_read()
247
 
        self.addCleanup(tree3.unlock)
248
173
        self.assertFalse(tree3.has_filename('hello'))
249
 
        self.assertEqual(tree3.get_file_text('buongia-id'), 'new text')
 
174
        self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
250
175
 
251
176
    def test_commit_rename(self):
252
177
        """Test commit of a revision where a file is renamed."""
259
184
        tree.rename_one('hello', 'fruity')
260
185
        tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
261
186
 
262
 
        eq = self.assertEqual
 
187
        eq = self.assertEquals
263
188
        tree1 = b.repository.revision_tree('test@rev-1')
264
 
        tree1.lock_read()
265
 
        self.addCleanup(tree1.unlock)
266
189
        eq(tree1.id2path('hello-id'), 'hello')
267
190
        eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
268
191
        self.assertFalse(tree1.has_filename('fruity'))
269
 
        self.check_tree_shape(tree1, ['hello'])
270
 
        eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
 
192
        self.check_inventory_shape(tree1.inventory, ['hello'])
 
193
        ie = tree1.inventory['hello-id']
 
194
        eq(ie.revision, 'test@rev-1')
271
195
 
272
196
        tree2 = b.repository.revision_tree('test@rev-2')
273
 
        tree2.lock_read()
274
 
        self.addCleanup(tree2.unlock)
275
197
        eq(tree2.id2path('hello-id'), 'fruity')
276
198
        eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
277
 
        self.check_tree_shape(tree2, ['fruity'])
278
 
        eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
 
199
        self.check_inventory_shape(tree2.inventory, ['fruity'])
 
200
        ie = tree2.inventory['hello-id']
 
201
        eq(ie.revision, 'test@rev-2')
279
202
 
280
203
    def test_reused_rev_id(self):
281
204
        """Test that a revision id cannot be reused in a branch"""
290
213
 
291
214
    def test_commit_move(self):
292
215
        """Test commit of revisions with moved files and directories"""
293
 
        eq = self.assertEqual
 
216
        eq = self.assertEquals
294
217
        wt = self.make_branch_and_tree('.')
295
218
        b = wt.branch
296
219
        r1 = 'test@rev-1'
302
225
        wt.commit('two', rev_id=r2, allow_pointless=False)
303
226
        wt.lock_read()
304
227
        try:
305
 
            self.check_tree_shape(wt, ['a/', 'a/hello', 'b/'])
 
228
            self.check_inventory_shape(wt.read_working_inventory(),
 
229
                                       ['a', 'a/hello', 'b'])
306
230
        finally:
307
231
            wt.unlock()
308
232
 
311
235
        wt.commit('three', rev_id=r3, allow_pointless=False)
312
236
        wt.lock_read()
313
237
        try:
314
 
            self.check_tree_shape(wt,
315
 
                                       ['a/', 'a/hello', 'a/b/'])
316
 
            self.check_tree_shape(b.repository.revision_tree(r3),
317
 
                                       ['a/', 'a/hello', 'a/b/'])
 
238
            self.check_inventory_shape(wt.read_working_inventory(),
 
239
                                       ['a', 'a/hello', 'a/b'])
 
240
            self.check_inventory_shape(b.repository.get_revision_inventory(r3),
 
241
                                       ['a', 'a/hello', 'a/b'])
318
242
        finally:
319
243
            wt.unlock()
320
244
 
323
247
        wt.commit('four', rev_id=r4, allow_pointless=False)
324
248
        wt.lock_read()
325
249
        try:
326
 
            self.check_tree_shape(wt, ['a/', 'a/b/hello', 'a/b/'])
 
250
            self.check_inventory_shape(wt.read_working_inventory(),
 
251
                                       ['a', 'a/b/hello', 'a/b'])
327
252
        finally:
328
253
            wt.unlock()
329
254
 
330
 
        inv = b.repository.get_inventory(r4)
 
255
        inv = b.repository.get_revision_inventory(r4)
331
256
        eq(inv['hello-id'].revision, r4)
332
257
        eq(inv['a-id'].revision, r1)
333
258
        eq(inv['b-id'].revision, r3)
336
261
        """Commit with a removed file"""
337
262
        wt = self.make_branch_and_tree('.')
338
263
        b = wt.branch
339
 
        with file('hello', 'w') as f: f.write('hello world')
 
264
        file('hello', 'w').write('hello world')
340
265
        wt.add(['hello'], ['hello-id'])
341
266
        wt.commit(message='add hello')
342
267
        wt.remove('hello')
351
276
        b = wt.branch
352
277
        rev_ids = []
353
278
        for i in range(4):
354
 
            with file('hello', 'w') as f: f.write((str(i) * 4) + '\n')
 
279
            file('hello', 'w').write((str(i) * 4) + '\n')
355
280
            if i == 0:
356
281
                wt.add(['hello'], ['hello-id'])
357
282
            rev_id = 'test@rev-%d' % (i+1)
358
283
            rev_ids.append(rev_id)
359
284
            wt.commit(message='rev %d' % (i+1),
360
285
                     rev_id=rev_id)
 
286
        eq = self.assertEquals
 
287
        eq(b.revision_history(), rev_ids)
361
288
        for i in range(4):
362
 
            self.assertThat(rev_ids[:i+1],
363
 
                MatchesAncestry(b.repository, rev_ids[i]))
 
289
            anc = b.repository.get_ancestry(rev_ids[i])
 
290
            eq(anc, [None] + rev_ids[:i+1])
364
291
 
365
292
    def test_commit_new_subdir_child_selective(self):
366
293
        wt = self.make_branch_and_tree('.')
380
307
        from bzrlib.errors import StrictCommitFailed
381
308
        wt = self.make_branch_and_tree('.')
382
309
        b = wt.branch
383
 
        with file('hello', 'w') as f: f.write('hello world')
 
310
        file('hello', 'w').write('hello world')
384
311
        wt.add('hello')
385
 
        with file('goodbye', 'w') as f: f.write('goodbye cruel world!')
 
312
        file('goodbye', 'w').write('goodbye cruel world!')
386
313
        self.assertRaises(StrictCommitFailed, wt.commit,
387
314
            message='add hello but not goodbye', strict=True)
388
315
 
389
316
    def test_strict_commit_without_unknowns(self):
390
317
        """Try and commit with no unknown files and strict = True,
391
318
        should work."""
 
319
        from bzrlib.errors import StrictCommitFailed
392
320
        wt = self.make_branch_and_tree('.')
393
321
        b = wt.branch
394
 
        with file('hello', 'w') as f: f.write('hello world')
 
322
        file('hello', 'w').write('hello world')
395
323
        wt.add('hello')
396
324
        wt.commit(message='add hello', strict=True)
397
325
 
399
327
        """Try and commit with unknown files and strict = False, should work."""
400
328
        wt = self.make_branch_and_tree('.')
401
329
        b = wt.branch
402
 
        with file('hello', 'w') as f: f.write('hello world')
 
330
        file('hello', 'w').write('hello world')
403
331
        wt.add('hello')
404
 
        with file('goodbye', 'w') as f: f.write('goodbye cruel world!')
 
332
        file('goodbye', 'w').write('goodbye cruel world!')
405
333
        wt.commit(message='add hello but not goodbye', strict=False)
406
334
 
407
335
    def test_nonstrict_commit_without_unknowns(self):
409
337
        should work."""
410
338
        wt = self.make_branch_and_tree('.')
411
339
        b = wt.branch
412
 
        with file('hello', 'w') as f: f.write('hello world')
 
340
        file('hello', 'w').write('hello world')
413
341
        wt.add('hello')
414
342
        wt.commit(message='add hello', strict=False)
415
343
 
420
348
        wt = self.make_branch_and_tree('.')
421
349
        branch = wt.branch
422
350
        wt.commit("base", allow_pointless=True, rev_id='A')
423
 
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
 
351
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
424
352
        try:
425
353
            from bzrlib.testament import Testament
426
354
            # monkey patch gpg signing mechanism
427
355
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
428
 
            conf = config.MemoryStack('''
429
 
gpg_signing_command=cat -
430
 
create_signatures=always
431
 
''')
432
 
            commit.Commit(config_stack=conf).commit(
433
 
                message="base", allow_pointless=True, rev_id='B',
434
 
                working_tree=wt)
 
356
            commit.Commit(config=MustSignConfig(branch)).commit(message="base",
 
357
                                                      allow_pointless=True,
 
358
                                                      rev_id='B',
 
359
                                                      working_tree=wt)
435
360
            def sign(text):
436
361
                return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
437
362
            self.assertEqual(sign(Testament.from_revision(branch.repository,
438
 
                                                          'B').as_short_text()),
 
363
                             'B').as_short_text()),
439
364
                             branch.repository.get_signature_text('B'))
440
365
        finally:
441
366
            bzrlib.gpg.GPGStrategy = oldstrategy
447
372
        wt = self.make_branch_and_tree('.')
448
373
        branch = wt.branch
449
374
        wt.commit("base", allow_pointless=True, rev_id='A')
450
 
        self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
 
375
        self.failIf(branch.repository.has_signature_for_revision_id('A'))
451
376
        try:
 
377
            from bzrlib.testament import Testament
452
378
            # monkey patch gpg signing mechanism
453
379
            bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
454
 
            conf = config.MemoryStack('''
455
 
gpg_signing_command=cat -
456
 
create_signatures=always
457
 
''')
 
380
            config = MustSignConfig(branch)
458
381
            self.assertRaises(SigningFailed,
459
 
                              commit.Commit(config_stack=conf).commit,
 
382
                              commit.Commit(config=config).commit,
460
383
                              message="base",
461
384
                              allow_pointless=True,
462
385
                              rev_id='B',
463
386
                              working_tree=wt)
464
387
            branch = Branch.open(self.get_url('.'))
465
 
            self.assertEqual(branch.last_revision(), 'A')
466
 
            self.assertFalse(branch.repository.has_revision('B'))
 
388
            self.assertEqual(branch.revision_history(), ['A'])
 
389
            self.failIf(branch.repository.has_revision('B'))
467
390
        finally:
468
391
            bzrlib.gpg.GPGStrategy = oldstrategy
469
392
 
476
399
            calls.append('called')
477
400
        bzrlib.ahook = called
478
401
        try:
479
 
            conf = config.MemoryStack('post_commit=bzrlib.ahook bzrlib.ahook')
480
 
            commit.Commit(config_stack=conf).commit(
481
 
                message = "base", allow_pointless=True, rev_id='A',
482
 
                working_tree = wt)
 
402
            config = BranchWithHooks(branch)
 
403
            commit.Commit(config=config).commit(
 
404
                            message = "base",
 
405
                            allow_pointless=True,
 
406
                            rev_id='A', working_tree = wt)
483
407
            self.assertEqual(['called', 'called'], calls)
484
408
        finally:
485
409
            del bzrlib.ahook
489
413
        wt = self.make_branch_and_tree('.')
490
414
        c = Commit()
491
415
        c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
492
 
        self.assertEqual(wt.branch.revno(), 1)
 
416
        self.assertEquals(wt.branch.revno(), 1)
493
417
        self.assertEqual({},
494
418
                         wt.branch.repository.get_revision(
495
419
                            wt.branch.last_revision()).properties)
503
427
        bound = master.sprout('bound')
504
428
        wt = bound.open_workingtree()
505
429
        wt.branch.set_bound_location(os.path.realpath('master'))
 
430
 
 
431
        orig_default = lockdir._DEFAULT_TIMEOUT_SECONDS
506
432
        master_branch.lock_write()
507
433
        try:
 
434
            lockdir._DEFAULT_TIMEOUT_SECONDS = 1
508
435
            self.assertRaises(LockContention, wt.commit, 'silly')
509
436
        finally:
 
437
            lockdir._DEFAULT_TIMEOUT_SECONDS = orig_default
510
438
            master_branch.unlock()
511
439
 
512
440
    def test_commit_bound_merge(self):
523
451
        other_bzrdir = master_branch.bzrdir.sprout('other')
524
452
        other_tree = other_bzrdir.open_workingtree()
525
453
 
526
 
        # do a commit to the other branch changing the content file so
 
454
        # do a commit to the the other branch changing the content file so
527
455
        # that our commit after merging will have a merged revision in the
528
456
        # content file history.
529
457
        self.build_tree_contents([('other/content_file', 'change in other\n')])
540
468
        bound_tree.commit(message='commit of merge in bound tree')
541
469
 
542
470
    def test_commit_reporting_after_merge(self):
543
 
        # when doing a commit of a merge, the reporter needs to still
 
471
        # when doing a commit of a merge, the reporter needs to still 
544
472
        # be called for each item that is added/removed/deleted.
545
473
        this_tree = self.make_branch_and_tree('this')
546
474
        # we need a bunch of files and dirs, to perform one action on each.
589
517
        this_tree.merge_from_branch(other_tree.branch)
590
518
        reporter = CapturingReporter()
591
519
        this_tree.commit('do the commit', reporter=reporter)
592
 
        expected = set([
 
520
        self.assertEqual([
 
521
            ('change', 'unchanged', ''),
 
522
            ('change', 'unchanged', 'dirtoleave'),
 
523
            ('change', 'unchanged', 'filetoleave'),
593
524
            ('change', 'modified', 'filetomodify'),
594
525
            ('change', 'added', 'newdir'),
595
526
            ('change', 'added', 'newfile'),
596
527
            ('renamed', 'renamed', 'dirtorename', 'renameddir'),
597
 
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
598
528
            ('renamed', 'renamed', 'dirtoreparent', 'renameddir/reparenteddir'),
599
529
            ('renamed', 'renamed', 'filetoreparent', 'renameddir/reparentedfile'),
 
530
            ('renamed', 'renamed', 'filetorename', 'renamedfile'),
600
531
            ('deleted', 'dirtoremove'),
601
532
            ('deleted', 'filetoremove'),
602
 
            ])
603
 
        result = set(reporter.calls)
604
 
        missing = expected - result
605
 
        new = result - expected
606
 
        self.assertEqual((set(), set()), (missing, new))
 
533
            ],
 
534
            reporter.calls)
607
535
 
608
536
    def test_commit_removals_respects_filespec(self):
609
537
        """Commit respects the specified_files for removals."""
653
581
            basis.unlock()
654
582
 
655
583
    def test_commit_kind_changes(self):
656
 
        self.requireFeature(SymlinkFeature)
 
584
        if not osutils.has_symlinks():
 
585
            raise tests.TestSkipped('Test requires symlink support')
657
586
        tree = self.make_branch_and_tree('.')
658
587
        os.symlink('target', 'name')
659
588
        tree.add('name', 'a-file-id')
699
628
    def test_commit_unversioned_specified(self):
700
629
        """Commit should raise if specified files isn't in basis or worktree"""
701
630
        tree = self.make_branch_and_tree('.')
702
 
        self.assertRaises(errors.PathsNotVersionedError, tree.commit,
 
631
        self.assertRaises(errors.PathsNotVersionedError, tree.commit, 
703
632
                          'message', specific_files=['bogus'])
704
633
 
705
634
    class Callback(object):
706
 
 
 
635
        
707
636
        def __init__(self, message, testcase):
708
637
            self.called = False
709
638
            self.message = message
737
666
        """Callback should not be invoked for pointless commit"""
738
667
        tree = self.make_branch_and_tree('.')
739
668
        cb = self.Callback(u'commit 2', self)
740
 
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb,
 
669
        self.assertRaises(PointlessCommit, tree.commit, message_callback=cb, 
741
670
                          allow_pointless=False)
742
671
        self.assertFalse(cb.called)
743
672
 
747
676
        cb = self.Callback(u'commit 2', self)
748
677
        repository = tree.branch.repository
749
678
        # simulate network failure
750
 
        def raise_(self, arg, arg2, arg3=None, arg4=None):
 
679
        def raise_(self, arg, arg2):
751
680
            raise errors.NoSuchFile('foo')
752
681
        repository.add_inventory = raise_
753
 
        repository.add_inventory_by_delta = raise_
754
682
        self.assertRaises(errors.NoSuchFile, tree.commit, message_callback=cb)
755
683
        self.assertFalse(cb.called)
756
 
 
757
 
    def test_selected_file_merge_commit(self):
758
 
        """Ensure the correct error is raised"""
759
 
        tree = self.make_branch_and_tree('foo')
760
 
        # pending merge would turn into a left parent
761
 
        tree.commit('commit 1')
762
 
        tree.add_parent_tree_id('example')
763
 
        self.build_tree(['foo/bar', 'foo/baz'])
764
 
        tree.add(['bar', 'baz'])
765
 
        err = self.assertRaises(errors.CannotCommitSelectedFileMerge,
766
 
            tree.commit, 'commit 2', specific_files=['bar', 'baz'])
767
 
        self.assertEqual(['bar', 'baz'], err.files)
768
 
        self.assertEqual('Selected-file commit of merges is not supported'
769
 
                         ' yet: files bar, baz', str(err))
770
 
 
771
 
    def test_commit_ordering(self):
772
 
        """Test of corner-case commit ordering error"""
773
 
        tree = self.make_branch_and_tree('.')
774
 
        self.build_tree(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
775
 
        tree.add(['a/', 'a/z/', 'a/c/', 'a/z/x', 'a/z/y'])
776
 
        tree.commit('setup')
777
 
        self.build_tree(['a/c/d/'])
778
 
        tree.add('a/c/d')
779
 
        tree.rename_one('a/z/x', 'a/c/d/x')
780
 
        tree.commit('test', specific_files=['a/z/y'])
781
 
 
782
 
    def test_commit_no_author(self):
783
 
        """The default kwarg author in MutableTree.commit should not add
784
 
        the 'author' revision property.
785
 
        """
786
 
        tree = self.make_branch_and_tree('foo')
787
 
        rev_id = tree.commit('commit 1')
788
 
        rev = tree.branch.repository.get_revision(rev_id)
789
 
        self.assertFalse('author' in rev.properties)
790
 
        self.assertFalse('authors' in rev.properties)
791
 
 
792
 
    def test_commit_author(self):
793
 
        """Passing a non-empty author kwarg to MutableTree.commit should add
794
 
        the 'author' revision property.
795
 
        """
796
 
        tree = self.make_branch_and_tree('foo')
797
 
        rev_id = self.callDeprecated(['The parameter author was '
798
 
                'deprecated in version 1.13. Use authors instead'],
799
 
                tree.commit, 'commit 1', author='John Doe <jdoe@example.com>')
800
 
        rev = tree.branch.repository.get_revision(rev_id)
801
 
        self.assertEqual('John Doe <jdoe@example.com>',
802
 
                         rev.properties['authors'])
803
 
        self.assertFalse('author' in rev.properties)
804
 
 
805
 
    def test_commit_empty_authors_list(self):
806
 
        """Passing an empty list to authors shouldn't add the property."""
807
 
        tree = self.make_branch_and_tree('foo')
808
 
        rev_id = tree.commit('commit 1', authors=[])
809
 
        rev = tree.branch.repository.get_revision(rev_id)
810
 
        self.assertFalse('author' in rev.properties)
811
 
        self.assertFalse('authors' in rev.properties)
812
 
 
813
 
    def test_multiple_authors(self):
814
 
        tree = self.make_branch_and_tree('foo')
815
 
        rev_id = tree.commit('commit 1',
816
 
                authors=['John Doe <jdoe@example.com>',
817
 
                         'Jane Rey <jrey@example.com>'])
818
 
        rev = tree.branch.repository.get_revision(rev_id)
819
 
        self.assertEqual('John Doe <jdoe@example.com>\n'
820
 
                'Jane Rey <jrey@example.com>', rev.properties['authors'])
821
 
        self.assertFalse('author' in rev.properties)
822
 
 
823
 
    def test_author_and_authors_incompatible(self):
824
 
        tree = self.make_branch_and_tree('foo')
825
 
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
826
 
                authors=['John Doe <jdoe@example.com>',
827
 
                         'Jane Rey <jrey@example.com>'],
828
 
                author="Jack Me <jme@example.com>")
829
 
 
830
 
    def test_author_with_newline_rejected(self):
831
 
        tree = self.make_branch_and_tree('foo')
832
 
        self.assertRaises(AssertionError, tree.commit, 'commit 1',
833
 
                authors=['John\nDoe <jdoe@example.com>'])
834
 
 
835
 
    def test_commit_with_checkout_and_branch_sharing_repo(self):
836
 
        repo = self.make_repository('repo', shared=True)
837
 
        # make_branch_and_tree ignores shared repos
838
 
        branch = controldir.ControlDir.create_branch_convenience('repo/branch')
839
 
        tree2 = branch.create_checkout('repo/tree2')
840
 
        tree2.commit('message', rev_id='rev1')
841
 
        self.assertTrue(tree2.branch.repository.has_revision('rev1'))