/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: Jelmer Vernooij
  • Date: 2017-07-23 22:06:41 UTC
  • mfrom: (6738 trunk)
  • mto: This revision was merged to the branch mainline in revision 6739.
  • Revision ID: jelmer@jelmer.uk-20170723220641-69eczax9bmv8d6kk
Merge trunk, address review comments.

Show diffs side-by-side

added added

removed removed

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