21
21
from bzrlib import (
25
26
from bzrlib.branch import Branch
26
27
from bzrlib.bzrdir import BzrDirMetaFormat1
27
28
from bzrlib.commit import Commit, NullCommitReporter
28
from bzrlib.config import BranchConfig
29
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed,
31
from bzrlib.tests import SymlinkFeature, TestCaseWithTransport
29
from bzrlib.errors import (
35
from bzrlib.tests import (
36
TestCaseWithTransport,
39
from bzrlib.tests.features import (
42
from bzrlib.tests.matchers import MatchesAncestry
34
45
# TODO: Test commit with some added, and added-but-missing files
36
class MustSignConfig(BranchConfig):
38
def signature_needed(self):
41
def gpg_signing_command(self):
45
class BranchWithHooks(BranchConfig):
47
def post_commit(self):
48
return "bzrlib.ahook bzrlib.ahook"
47
class MustSignConfig(config.MemoryStack):
50
super(MustSignConfig, self).__init__('''
51
gpg_signing_command=cat -
52
create_signatures=always
51
56
class CapturingReporter(NullCommitReporter):
77
82
"""Commit and check two versions of a single file."""
78
83
wt = self.make_branch_and_tree('.')
80
file('hello', 'w').write('hello world')
85
with file('hello', 'w') as f: f.write('hello world')
82
wt.commit(message='add hello')
87
rev1 = wt.commit(message='add hello')
83
88
file_id = wt.path2id('hello')
85
file('hello', 'w').write('version 2')
86
wt.commit(message='commit 2')
90
with file('hello', 'w') as f: f.write('version 2')
91
rev2 = wt.commit(message='commit 2')
88
93
eq = self.assertEquals
90
rh = b.revision_history()
91
rev = b.repository.get_revision(rh[0])
95
rev = b.repository.get_revision(rev1)
92
96
eq(rev.message, 'add hello')
94
tree1 = b.repository.revision_tree(rh[0])
98
tree1 = b.repository.revision_tree(rev1)
96
100
text = tree1.get_file_text(file_id)
98
102
self.assertEqual('hello world', text)
100
tree2 = b.repository.revision_tree(rh[1])
104
tree2 = b.repository.revision_tree(rev2)
101
105
tree2.lock_read()
102
106
text = tree2.get_file_text(file_id)
104
108
self.assertEqual('version 2', text)
110
def test_commit_lossy_native(self):
111
"""Attempt a lossy commit to a native branch."""
112
wt = self.make_branch_and_tree('.')
114
with file('hello', 'w') as f: f.write('hello world')
116
revid = wt.commit(message='add hello', rev_id='revid', lossy=True)
117
self.assertEquals('revid', revid)
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())
125
with file('hello', 'w') as f: f.write('hello world')
127
revid = wt.commit(message='add hello', lossy=True,
128
timestamp=1302659388, timezone=0)
129
self.assertEquals('dummy-v1:1302659388.0-0-UNKNOWN', revid)
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")
138
with file('local/hello', 'w') as f: f.write('hello world')
140
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())
106
148
def test_missing_commit(self):
107
149
"""Test a commit with a missing file"""
108
150
wt = self.make_branch_and_tree('.')
110
file('hello', 'w').write('hello world')
152
with file('hello', 'w') as f: f.write('hello world')
111
153
wt.add(['hello'], ['hello-id'])
112
154
wt.commit(message='add hello')
114
156
os.remove('hello')
115
wt.commit('removed hello', rev_id='rev2')
157
reporter = CapturingReporter()
158
wt.commit('removed hello', rev_id='rev2', reporter=reporter)
160
[('missing', u'hello'), ('deleted', u'hello')],
117
163
tree = b.repository.revision_tree('rev2')
118
164
self.assertFalse(tree.has_id('hello-id'))
167
213
"""Selective commit in tree with deletions"""
168
214
wt = self.make_branch_and_tree('.')
170
file('hello', 'w').write('hello')
171
file('buongia', 'w').write('buongia')
216
with file('hello', 'w') as f: f.write('hello')
217
with file('buongia', 'w') as f: f.write('buongia')
172
218
wt.add(['hello', 'buongia'],
173
219
['hello-id', 'buongia-id'])
174
220
wt.commit(message='add files',
175
221
rev_id='test@rev-1')
177
223
os.remove('hello')
178
file('buongia', 'w').write('new text')
224
with file('buongia', 'w') as f: f.write('new text')
179
225
wt.commit(message='update text',
180
226
specific_files=['buongia'],
181
227
allow_pointless=False,
220
266
eq(tree1.id2path('hello-id'), 'hello')
221
267
eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
222
268
self.assertFalse(tree1.has_filename('fruity'))
223
self.check_inventory_shape(tree1.inventory, ['hello'])
224
ie = tree1.inventory['hello-id']
225
eq(ie.revision, 'test@rev-1')
269
self.check_tree_shape(tree1, ['hello'])
270
eq(tree1.get_file_revision('hello-id'), 'test@rev-1')
227
272
tree2 = b.repository.revision_tree('test@rev-2')
228
273
tree2.lock_read()
229
274
self.addCleanup(tree2.unlock)
230
275
eq(tree2.id2path('hello-id'), 'fruity')
231
276
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
232
self.check_inventory_shape(tree2.inventory, ['fruity'])
233
ie = tree2.inventory['hello-id']
234
eq(ie.revision, 'test@rev-2')
277
self.check_tree_shape(tree2, ['fruity'])
278
eq(tree2.get_file_revision('hello-id'), 'test@rev-2')
236
280
def test_reused_rev_id(self):
237
281
"""Test that a revision id cannot be reused in a branch"""
311
353
for i in range(4):
312
file('hello', 'w').write((str(i) * 4) + '\n')
354
with file('hello', 'w') as f: f.write((str(i) * 4) + '\n')
314
356
wt.add(['hello'], ['hello-id'])
315
357
rev_id = 'test@rev-%d' % (i+1)
316
358
rev_ids.append(rev_id)
317
359
wt.commit(message='rev %d' % (i+1),
319
eq = self.assertEquals
320
eq(b.revision_history(), rev_ids)
321
361
for i in range(4):
322
anc = b.repository.get_ancestry(rev_ids[i])
323
eq(anc, [None] + rev_ids[:i+1])
362
self.assertThat(rev_ids[:i+1],
363
MatchesAncestry(b.repository, rev_ids[i]))
325
365
def test_commit_new_subdir_child_selective(self):
326
366
wt = self.make_branch_and_tree('.')
340
380
from bzrlib.errors import StrictCommitFailed
341
381
wt = self.make_branch_and_tree('.')
343
file('hello', 'w').write('hello world')
383
with file('hello', 'w') as f: f.write('hello world')
345
file('goodbye', 'w').write('goodbye cruel world!')
385
with file('goodbye', 'w') as f: f.write('goodbye cruel world!')
346
386
self.assertRaises(StrictCommitFailed, wt.commit,
347
387
message='add hello but not goodbye', strict=True)
349
389
def test_strict_commit_without_unknowns(self):
350
390
"""Try and commit with no unknown files and strict = True,
352
from bzrlib.errors import StrictCommitFailed
353
392
wt = self.make_branch_and_tree('.')
355
file('hello', 'w').write('hello world')
394
with file('hello', 'w') as f: f.write('hello world')
357
396
wt.commit(message='add hello', strict=True)
381
420
wt = self.make_branch_and_tree('.')
382
421
branch = wt.branch
383
422
wt.commit("base", allow_pointless=True, rev_id='A')
384
self.failIf(branch.repository.has_signature_for_revision_id('A'))
423
self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
386
425
from bzrlib.testament import Testament
387
426
# monkey patch gpg signing mechanism
388
427
bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
389
commit.Commit(config=MustSignConfig(branch)).commit(message="base",
390
allow_pointless=True,
428
conf = config.MemoryStack('''
429
gpg_signing_command=cat -
430
create_signatures=always
432
commit.Commit(config_stack=conf).commit(
433
message="base", allow_pointless=True, rev_id='B',
394
436
return bzrlib.gpg.LoopbackGPGStrategy(None).sign(text)
395
437
self.assertEqual(sign(Testament.from_revision(branch.repository,
396
'B').as_short_text()),
438
'B').as_short_text()),
397
439
branch.repository.get_signature_text('B'))
399
441
bzrlib.gpg.GPGStrategy = oldstrategy
405
447
wt = self.make_branch_and_tree('.')
406
448
branch = wt.branch
407
449
wt.commit("base", allow_pointless=True, rev_id='A')
408
self.failIf(branch.repository.has_signature_for_revision_id('A'))
450
self.assertFalse(branch.repository.has_signature_for_revision_id('A'))
410
from bzrlib.testament import Testament
411
452
# monkey patch gpg signing mechanism
412
453
bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
413
config = MustSignConfig(branch)
454
conf = config.MemoryStack('''
455
gpg_signing_command=cat -
456
create_signatures=always
414
458
self.assertRaises(SigningFailed,
415
commit.Commit(config=config).commit,
459
commit.Commit(config_stack=conf).commit,
417
461
allow_pointless=True,
420
464
branch = Branch.open(self.get_url('.'))
421
self.assertEqual(branch.revision_history(), ['A'])
422
self.failIf(branch.repository.has_revision('B'))
465
self.assertEqual(branch.last_revision(), 'A')
466
self.assertFalse(branch.repository.has_revision('B'))
424
468
bzrlib.gpg.GPGStrategy = oldstrategy