/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 breezy/tests/test_commit.py

  • Committer: Breezy landing bot
  • Author(s): Colin Watson
  • Date: 2020-11-16 21:47:08 UTC
  • mfrom: (7521.1.1 remove-lp-workaround)
  • Revision ID: breezy.the.bot@gmail.com-20201116214708-jos209mgxi41oy15
Remove breezy.git workaround for bazaar.launchpad.net.

Merged from https://code.launchpad.net/~cjwatson/brz/remove-lp-workaround/+merge/393710

Show diffs side-by-side

added added

removed removed

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