21
from bzrlib.tests import TestCaseWithTransport
20
from bzrlib.selftest import TestCaseInTempDir
22
21
from bzrlib.branch import Branch
23
from bzrlib.bzrdir import BzrDir, BzrDirMetaFormat1
24
from bzrlib.workingtree import WorkingTree
25
22
from bzrlib.commit import Commit
26
from bzrlib.config import BranchConfig
27
from bzrlib.errors import (PointlessCommit, BzrError, SigningFailed,
23
from bzrlib.errors import PointlessCommit, BzrError
31
26
# TODO: Test commit with some added, and added-but-missing files
33
class MustSignConfig(BranchConfig):
35
def signature_needed(self):
38
def gpg_signing_command(self):
42
class BranchWithHooks(BranchConfig):
44
def post_commit(self):
45
return "bzrlib.ahook bzrlib.ahook"
48
class TestCommit(TestCaseWithTransport):
28
class TestCommit(TestCaseInTempDir):
50
30
def test_simple_commit(self):
51
31
"""Commit and check two versions of a single file."""
52
wt = self.make_branch_and_tree('.')
32
b = Branch.initialize('.')
54
33
file('hello', 'w').write('hello world')
56
wt.commit(message='add hello')
57
file_id = wt.path2id('hello')
35
b.commit(message='add hello')
36
file_id = b.working_tree().path2id('hello')
59
38
file('hello', 'w').write('version 2')
60
wt.commit(message='commit 2')
39
b.commit(message='commit 2')
62
41
eq = self.assertEquals
64
43
rh = b.revision_history()
65
rev = b.repository.get_revision(rh[0])
44
rev = b.get_revision(rh[0])
66
45
eq(rev.message, 'add hello')
68
tree1 = b.repository.revision_tree(rh[0])
47
tree1 = b.revision_tree(rh[0])
69
48
text = tree1.get_file_text(file_id)
70
49
eq(text, 'hello world')
72
tree2 = b.repository.revision_tree(rh[1])
51
tree2 = b.revision_tree(rh[1])
73
52
eq(tree2.get_file_text(file_id), 'version 2')
75
55
def test_delete_commit(self):
76
56
"""Test a commit with a deleted file"""
77
wt = self.make_branch_and_tree('.')
57
b = Branch.initialize('.')
79
58
file('hello', 'w').write('hello world')
80
wt.add(['hello'], ['hello-id'])
81
wt.commit(message='add hello')
59
b.add(['hello'], ['hello-id'])
60
b.commit(message='add hello')
84
wt.commit('removed hello', rev_id='rev2')
63
b.commit('removed hello', rev_id='rev2')
86
tree = b.repository.revision_tree('rev2')
65
tree = b.revision_tree('rev2')
87
66
self.assertFalse(tree.has_id('hello-id'))
89
69
def test_pointless_commit(self):
90
70
"""Commit refuses unless there are changes or it's forced."""
91
wt = self.make_branch_and_tree('.')
71
b = Branch.initialize('.')
93
72
file('hello', 'w').write('hello')
95
wt.commit(message='add hello')
74
b.commit(message='add hello')
96
75
self.assertEquals(b.revno(), 1)
97
76
self.assertRaises(PointlessCommit,
100
79
allow_pointless=False)
101
80
self.assertEquals(b.revno(), 1)
103
84
def test_commit_empty(self):
104
85
"""Commiting an empty tree works."""
105
wt = self.make_branch_and_tree('.')
107
wt.commit(message='empty tree', allow_pointless=True)
86
b = Branch.initialize('.')
87
b.commit(message='empty tree', allow_pointless=True)
108
88
self.assertRaises(PointlessCommit,
110
90
message='empty tree',
111
91
allow_pointless=False)
112
wt.commit(message='empty tree', allow_pointless=True)
92
b.commit(message='empty tree', allow_pointless=True)
113
93
self.assertEquals(b.revno(), 2)
115
96
def test_selective_delete(self):
116
97
"""Selective commit in tree with deletions"""
117
wt = self.make_branch_and_tree('.')
98
b = Branch.initialize('.')
119
99
file('hello', 'w').write('hello')
120
100
file('buongia', 'w').write('buongia')
121
wt.add(['hello', 'buongia'],
101
b.add(['hello', 'buongia'],
122
102
['hello-id', 'buongia-id'])
123
wt.commit(message='add files',
103
b.commit(message='add files',
124
104
rev_id='test@rev-1')
126
106
os.remove('hello')
127
107
file('buongia', 'w').write('new text')
128
wt.commit(message='update text',
108
b.commit(message='update text',
129
109
specific_files=['buongia'],
130
110
allow_pointless=False,
131
111
rev_id='test@rev-2')
133
wt.commit(message='remove hello',
113
b.commit(message='remove hello',
134
114
specific_files=['hello'],
135
115
allow_pointless=False,
136
116
rev_id='test@rev-3')
167
147
ie = tree1.inventory['hello-id']
168
148
eq(ie.revision, 'test@rev-1')
170
tree2 = b.repository.revision_tree('test@rev-2')
150
tree2 = b.revision_tree('test@rev-2')
171
151
eq(tree2.id2path('hello-id'), 'fruity')
172
152
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
173
153
self.check_inventory_shape(tree2.inventory, ['fruity'])
174
154
ie = tree2.inventory['hello-id']
175
155
eq(ie.revision, 'test@rev-2')
177
158
def test_reused_rev_id(self):
178
159
"""Test that a revision id cannot be reused in a branch"""
179
wt = self.make_branch_and_tree('.')
181
wt.commit('initial', rev_id='test@rev-1', allow_pointless=True)
160
b = Branch.initialize('.')
161
b.commit('initial', rev_id='test@rev-1', allow_pointless=True)
182
162
self.assertRaises(Exception,
184
164
message='reused id',
185
165
rev_id='test@rev-1',
186
166
allow_pointless=True)
188
170
def test_commit_move(self):
189
171
"""Test commit of revisions with moved files and directories"""
190
172
eq = self.assertEquals
191
wt = self.make_branch_and_tree('.')
173
b = Branch.initialize('.')
193
174
r1 = 'test@rev-1'
194
175
self.build_tree(['hello', 'a/', 'b/'])
195
wt.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
196
wt.commit('initial', rev_id=r1, allow_pointless=False)
197
wt.move(['hello'], 'a')
176
b.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
177
b.commit('initial', rev_id=r1, allow_pointless=False)
179
b.move(['hello'], 'a')
198
180
r2 = 'test@rev-2'
199
wt.commit('two', rev_id=r2, allow_pointless=False)
200
self.check_inventory_shape(wt.read_working_inventory(),
181
b.commit('two', rev_id=r2, allow_pointless=False)
182
self.check_inventory_shape(b.inventory,
201
183
['a', 'a/hello', 'b'])
204
186
r3 = 'test@rev-3'
205
wt.commit('three', rev_id=r3, allow_pointless=False)
206
self.check_inventory_shape(wt.read_working_inventory(),
187
b.commit('three', rev_id=r3, allow_pointless=False)
188
self.check_inventory_shape(b.inventory,
207
189
['a', 'a/hello', 'a/b'])
208
self.check_inventory_shape(b.repository.get_revision_inventory(r3),
190
self.check_inventory_shape(b.get_revision_inventory(r3),
209
191
['a', 'a/hello', 'a/b'])
211
wt.move(['a/hello'], 'a/b')
193
b.move([os.sep.join(['a', 'hello'])],
194
os.sep.join(['a', 'b']))
212
195
r4 = 'test@rev-4'
213
wt.commit('four', rev_id=r4, allow_pointless=False)
214
self.check_inventory_shape(wt.read_working_inventory(),
196
b.commit('four', rev_id=r4, allow_pointless=False)
197
self.check_inventory_shape(b.inventory,
215
198
['a', 'a/b/hello', 'a/b'])
217
inv = b.repository.get_revision_inventory(r4)
200
inv = b.get_revision_inventory(r4)
218
201
eq(inv['hello-id'].revision, r4)
219
202
eq(inv['a-id'].revision, r1)
220
203
eq(inv['b-id'].revision, r3)
222
206
def test_removed_commit(self):
223
"""Commit with a removed file"""
224
wt = self.make_branch_and_tree('.')
207
"""Test a commit with a removed file"""
208
b = Branch.initialize('.')
226
209
file('hello', 'w').write('hello world')
227
wt.add(['hello'], ['hello-id'])
228
wt.commit(message='add hello')
230
wt.commit('removed hello', rev_id='rev2')
232
tree = b.repository.revision_tree('rev2')
210
b.add(['hello'], ['hello-id'])
211
b.commit(message='add hello')
214
b.commit('removed hello', rev_id='rev2')
216
tree = b.revision_tree('rev2')
233
217
self.assertFalse(tree.has_id('hello-id'))
235
220
def test_committed_ancestry(self):
236
221
"""Test commit appends revisions to ancestry."""
237
wt = self.make_branch_and_tree('.')
222
b = Branch.initialize('.')
240
224
for i in range(4):
241
225
file('hello', 'w').write((str(i) * 4) + '\n')
243
wt.add(['hello'], ['hello-id'])
227
b.add(['hello'], ['hello-id'])
244
228
rev_id = 'test@rev-%d' % (i+1)
245
229
rev_ids.append(rev_id)
246
wt.commit(message='rev %d' % (i+1),
230
b.commit(message='rev %d' % (i+1),
248
232
eq = self.assertEquals
249
233
eq(b.revision_history(), rev_ids)
250
234
for i in range(4):
251
anc = b.repository.get_ancestry(rev_ids[i])
235
anc = b.get_ancestry(rev_ids[i])
252
236
eq(anc, [None] + rev_ids[:i+1])
254
238
def test_commit_new_subdir_child_selective(self):
255
wt = self.make_branch_and_tree('.')
239
b = Branch.initialize('.')
257
240
self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
258
wt.add(['dir', 'dir/file1', 'dir/file2'],
241
b.add(['dir', 'dir/file1', 'dir/file2'],
259
242
['dirid', 'file1id', 'file2id'])
260
wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
261
inv = b.repository.get_inventory('1')
243
b.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
244
inv = b.get_inventory('1')
262
245
self.assertEqual('1', inv['dirid'].revision)
263
246
self.assertEqual('1', inv['file1id'].revision)
264
247
# FIXME: This should raise a KeyError I think, rbc20051006
265
248
self.assertRaises(BzrError, inv.__getitem__, 'file2id')
267
def test_strict_commit(self):
268
"""Try and commit with unknown files and strict = True, should fail."""
269
from bzrlib.errors import StrictCommitFailed
270
wt = self.make_branch_and_tree('.')
272
file('hello', 'w').write('hello world')
274
file('goodbye', 'w').write('goodbye cruel world!')
275
self.assertRaises(StrictCommitFailed, wt.commit,
276
message='add hello but not goodbye', strict=True)
278
def test_strict_commit_without_unknowns(self):
279
"""Try and commit with no unknown files and strict = True,
281
from bzrlib.errors import StrictCommitFailed
282
wt = self.make_branch_and_tree('.')
284
file('hello', 'w').write('hello world')
286
wt.commit(message='add hello', strict=True)
288
def test_nonstrict_commit(self):
289
"""Try and commit with unknown files and strict = False, should work."""
290
wt = self.make_branch_and_tree('.')
292
file('hello', 'w').write('hello world')
294
file('goodbye', 'w').write('goodbye cruel world!')
295
wt.commit(message='add hello but not goodbye', strict=False)
297
def test_nonstrict_commit_without_unknowns(self):
298
"""Try and commit with no unknown files and strict = False,
300
wt = self.make_branch_and_tree('.')
302
file('hello', 'w').write('hello world')
304
wt.commit(message='add hello', strict=False)
306
def test_signed_commit(self):
308
import bzrlib.commit as commit
309
oldstrategy = bzrlib.gpg.GPGStrategy
310
wt = self.make_branch_and_tree('.')
312
wt.commit("base", allow_pointless=True, rev_id='A')
313
self.failIf(branch.repository.has_signature_for_revision_id('A'))
315
from bzrlib.testament import Testament
316
# monkey patch gpg signing mechanism
317
bzrlib.gpg.GPGStrategy = bzrlib.gpg.LoopbackGPGStrategy
318
commit.Commit(config=MustSignConfig(branch)).commit(message="base",
319
allow_pointless=True,
322
self.assertEqual(Testament.from_revision(branch.repository,
323
'B').as_short_text(),
324
branch.repository.get_signature_text('B'))
326
bzrlib.gpg.GPGStrategy = oldstrategy
328
def test_commit_failed_signature(self):
330
import bzrlib.commit as commit
331
oldstrategy = bzrlib.gpg.GPGStrategy
332
wt = self.make_branch_and_tree('.')
334
wt.commit("base", allow_pointless=True, rev_id='A')
335
self.failIf(branch.repository.has_signature_for_revision_id('A'))
337
from bzrlib.testament import Testament
338
# monkey patch gpg signing mechanism
339
bzrlib.gpg.GPGStrategy = bzrlib.gpg.DisabledGPGStrategy
340
config = MustSignConfig(branch)
341
self.assertRaises(SigningFailed,
342
commit.Commit(config=config).commit,
344
allow_pointless=True,
347
branch = Branch.open(self.get_url('.'))
348
self.assertEqual(branch.revision_history(), ['A'])
349
self.failIf(branch.repository.has_revision('B'))
351
bzrlib.gpg.GPGStrategy = oldstrategy
353
def test_commit_invokes_hooks(self):
354
import bzrlib.commit as commit
355
wt = self.make_branch_and_tree('.')
358
def called(branch, rev_id):
359
calls.append('called')
360
bzrlib.ahook = called
362
config = BranchWithHooks(branch)
363
commit.Commit(config=config).commit(
365
allow_pointless=True,
366
rev_id='A', working_tree = wt)
367
self.assertEqual(['called', 'called'], calls)
371
def test_commit_object_doesnt_set_nick(self):
372
# using the Commit object directly does not set the branch nick.
373
wt = self.make_branch_and_tree('.')
375
c.commit(working_tree=wt, message='empty tree', allow_pointless=True)
376
self.assertEquals(wt.branch.revno(), 1)
378
wt.branch.repository.get_revision(
379
wt.branch.last_revision()).properties)
381
def test_safe_master_lock(self):
383
master = BzrDirMetaFormat1().initialize('master')
384
master.create_repository()
385
master_branch = master.create_branch()
386
master.create_workingtree()
387
bound = master.sprout('bound')
388
wt = bound.open_workingtree()
389
wt.branch.set_bound_location(os.path.realpath('master'))
390
master_branch.lock_write()
392
self.assertRaises(LockContention, wt.commit, 'silly')
394
master_branch.unlock()