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
29
def test_simple_commit(self):
51
30
"""Commit and check two versions of a single file."""
52
wt = self.make_branch_and_tree('.')
31
b = Branch('.', init=True)
54
32
file('hello', 'w').write('hello world')
56
wt.commit(message='add hello')
57
file_id = wt.path2id('hello')
34
b.commit(message='add hello')
35
file_id = b.working_tree().path2id('hello')
59
37
file('hello', 'w').write('version 2')
60
wt.commit(message='commit 2')
38
b.commit(message='commit 2')
62
40
eq = self.assertEquals
64
42
rh = b.revision_history()
65
rev = b.repository.get_revision(rh[0])
43
rev = b.get_revision(rh[0])
66
44
eq(rev.message, 'add hello')
68
tree1 = b.repository.revision_tree(rh[0])
46
tree1 = b.revision_tree(rh[0])
69
47
text = tree1.get_file_text(file_id)
70
48
eq(text, 'hello world')
72
tree2 = b.repository.revision_tree(rh[1])
50
tree2 = b.revision_tree(rh[1])
73
51
eq(tree2.get_file_text(file_id), 'version 2')
75
54
def test_delete_commit(self):
76
55
"""Test a commit with a deleted file"""
77
wt = self.make_branch_and_tree('.')
56
b = Branch('.', init=True)
79
57
file('hello', 'w').write('hello world')
80
wt.add(['hello'], ['hello-id'])
81
wt.commit(message='add hello')
58
b.add(['hello'], ['hello-id'])
59
b.commit(message='add hello')
84
wt.commit('removed hello', rev_id='rev2')
62
b.commit('removed hello', rev_id='rev2')
86
tree = b.repository.revision_tree('rev2')
64
tree = b.revision_tree('rev2')
87
65
self.assertFalse(tree.has_id('hello-id'))
89
68
def test_pointless_commit(self):
90
69
"""Commit refuses unless there are changes or it's forced."""
91
wt = self.make_branch_and_tree('.')
70
b = Branch('.', init=True)
93
71
file('hello', 'w').write('hello')
95
wt.commit(message='add hello')
73
b.commit(message='add hello')
96
74
self.assertEquals(b.revno(), 1)
97
75
self.assertRaises(PointlessCommit,
100
78
allow_pointless=False)
101
79
self.assertEquals(b.revno(), 1)
103
83
def test_commit_empty(self):
104
84
"""Commiting an empty tree works."""
105
wt = self.make_branch_and_tree('.')
107
wt.commit(message='empty tree', allow_pointless=True)
85
b = Branch('.', init=True)
86
b.commit(message='empty tree', allow_pointless=True)
108
87
self.assertRaises(PointlessCommit,
110
89
message='empty tree',
111
90
allow_pointless=False)
112
wt.commit(message='empty tree', allow_pointless=True)
91
b.commit(message='empty tree', allow_pointless=True)
113
92
self.assertEquals(b.revno(), 2)
115
95
def test_selective_delete(self):
116
96
"""Selective commit in tree with deletions"""
117
wt = self.make_branch_and_tree('.')
97
b = Branch('.', init=True)
119
98
file('hello', 'w').write('hello')
120
99
file('buongia', 'w').write('buongia')
121
wt.add(['hello', 'buongia'],
100
b.add(['hello', 'buongia'],
122
101
['hello-id', 'buongia-id'])
123
wt.commit(message='add files',
102
b.commit(message='add files',
124
103
rev_id='test@rev-1')
126
105
os.remove('hello')
127
106
file('buongia', 'w').write('new text')
128
wt.commit(message='update text',
107
b.commit(message='update text',
129
108
specific_files=['buongia'],
130
109
allow_pointless=False,
131
110
rev_id='test@rev-2')
133
wt.commit(message='remove hello',
112
b.commit(message='remove hello',
134
113
specific_files=['hello'],
135
114
allow_pointless=False,
136
115
rev_id='test@rev-3')
138
117
eq = self.assertEquals
141
tree2 = b.repository.revision_tree('test@rev-2')
120
tree2 = b.revision_tree('test@rev-2')
142
121
self.assertTrue(tree2.has_filename('hello'))
143
122
self.assertEquals(tree2.get_file_text('hello-id'), 'hello')
144
123
self.assertEquals(tree2.get_file_text('buongia-id'), 'new text')
146
tree3 = b.repository.revision_tree('test@rev-3')
125
tree3 = b.revision_tree('test@rev-3')
147
126
self.assertFalse(tree3.has_filename('hello'))
148
127
self.assertEquals(tree3.get_file_text('buongia-id'), 'new text')
150
130
def test_commit_rename(self):
151
131
"""Test commit of a revision where a file is renamed."""
152
tree = self.make_branch_and_tree('.')
154
self.build_tree(['hello'], line_endings='binary')
155
tree.add(['hello'], ['hello-id'])
156
tree.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
132
b = Branch('.', init=True)
133
self.build_tree(['hello'])
134
b.add(['hello'], ['hello-id'])
135
b.commit(message='one', rev_id='test@rev-1', allow_pointless=False)
158
tree.rename_one('hello', 'fruity')
159
tree.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
137
b.rename_one('hello', 'fruity')
138
b.commit(message='renamed', rev_id='test@rev-2', allow_pointless=False)
161
140
eq = self.assertEquals
162
tree1 = b.repository.revision_tree('test@rev-1')
141
tree1 = b.revision_tree('test@rev-1')
163
142
eq(tree1.id2path('hello-id'), 'hello')
164
143
eq(tree1.get_file_text('hello-id'), 'contents of hello\n')
165
144
self.assertFalse(tree1.has_filename('fruity'))
166
145
self.check_inventory_shape(tree1.inventory, ['hello'])
167
146
ie = tree1.inventory['hello-id']
168
eq(ie.revision, 'test@rev-1')
147
eq(ie.name_version, 'test@rev-1')
170
tree2 = b.repository.revision_tree('test@rev-2')
149
tree2 = b.revision_tree('test@rev-2')
171
150
eq(tree2.id2path('hello-id'), 'fruity')
172
151
eq(tree2.get_file_text('hello-id'), 'contents of hello\n')
173
152
self.check_inventory_shape(tree2.inventory, ['fruity'])
174
153
ie = tree2.inventory['hello-id']
175
eq(ie.revision, 'test@rev-2')
154
eq(ie.name_version, 'test@rev-2')
177
157
def test_reused_rev_id(self):
178
158
"""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)
159
b = Branch('.', init=True)
160
b.commit('initial', rev_id='test@rev-1', allow_pointless=True)
182
161
self.assertRaises(Exception,
184
163
message='reused id',
185
164
rev_id='test@rev-1',
186
165
allow_pointless=True)
188
169
def test_commit_move(self):
189
170
"""Test commit of revisions with moved files and directories"""
190
171
eq = self.assertEquals
191
wt = self.make_branch_and_tree('.')
172
b = Branch('.', init=True)
193
173
r1 = 'test@rev-1'
194
174
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')
175
b.add(['hello', 'a', 'b'], ['hello-id', 'a-id', 'b-id'])
176
b.commit('initial', rev_id=r1, allow_pointless=False)
178
b.move(['hello'], 'a')
198
179
r2 = 'test@rev-2'
199
wt.commit('two', rev_id=r2, allow_pointless=False)
200
self.check_inventory_shape(wt.read_working_inventory(),
180
b.commit('two', rev_id=r2, allow_pointless=False)
181
self.check_inventory_shape(b.inventory,
201
182
['a', 'a/hello', 'b'])
204
185
r3 = 'test@rev-3'
205
wt.commit('three', rev_id=r3, allow_pointless=False)
206
self.check_inventory_shape(wt.read_working_inventory(),
186
b.commit('three', rev_id=r3, allow_pointless=False)
187
self.check_inventory_shape(b.inventory,
207
188
['a', 'a/hello', 'a/b'])
208
self.check_inventory_shape(b.repository.get_revision_inventory(r3),
189
self.check_inventory_shape(b.get_revision_inventory(r3),
209
190
['a', 'a/hello', 'a/b'])
211
wt.move(['a/hello'], 'a/b')
192
b.move([os.sep.join(['a', 'hello'])],
193
os.sep.join(['a', 'b']))
212
194
r4 = 'test@rev-4'
213
wt.commit('four', rev_id=r4, allow_pointless=False)
214
self.check_inventory_shape(wt.read_working_inventory(),
195
b.commit('four', rev_id=r4, allow_pointless=False)
196
self.check_inventory_shape(b.inventory,
215
197
['a', 'a/b/hello', 'a/b'])
217
inv = b.repository.get_revision_inventory(r4)
218
eq(inv['hello-id'].revision, r4)
219
eq(inv['a-id'].revision, r1)
220
eq(inv['b-id'].revision, r3)
199
inv = b.get_revision_inventory(r4)
200
eq(inv['hello-id'].name_version, r4)
201
eq(inv['a-id'].name_version, r1)
202
eq(inv['b-id'].name_version, r3)
222
205
def test_removed_commit(self):
223
"""Commit with a removed file"""
224
wt = self.make_branch_and_tree('.')
206
"""Test a commit with a removed file"""
207
b = Branch('.', init=True)
226
208
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')
209
b.add(['hello'], ['hello-id'])
210
b.commit(message='add hello')
213
b.commit('removed hello', rev_id='rev2')
215
tree = b.revision_tree('rev2')
233
216
self.assertFalse(tree.has_id('hello-id'))
235
219
def test_committed_ancestry(self):
236
220
"""Test commit appends revisions to ancestry."""
237
wt = self.make_branch_and_tree('.')
221
b = Branch('.', init=True)
240
223
for i in range(4):
241
224
file('hello', 'w').write((str(i) * 4) + '\n')
243
wt.add(['hello'], ['hello-id'])
226
b.add(['hello'], ['hello-id'])
244
227
rev_id = 'test@rev-%d' % (i+1)
245
228
rev_ids.append(rev_id)
246
wt.commit(message='rev %d' % (i+1),
229
b.commit(message='rev %d' % (i+1),
248
231
eq = self.assertEquals
249
232
eq(b.revision_history(), rev_ids)
250
233
for i in range(4):
251
anc = b.repository.get_ancestry(rev_ids[i])
252
eq(anc, [None] + rev_ids[:i+1])
254
def test_commit_new_subdir_child_selective(self):
255
wt = self.make_branch_and_tree('.')
257
self.build_tree(['dir/', 'dir/file1', 'dir/file2'])
258
wt.add(['dir', 'dir/file1', 'dir/file2'],
259
['dirid', 'file1id', 'file2id'])
260
wt.commit('dir/file1', specific_files=['dir/file1'], rev_id='1')
261
inv = b.repository.get_inventory('1')
262
self.assertEqual('1', inv['dirid'].revision)
263
self.assertEqual('1', inv['file1id'].revision)
264
# FIXME: This should raise a KeyError I think, rbc20051006
265
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()
234
anc = b.get_ancestry(rev_ids[i])
235
eq(anc, rev_ids[:i+1])
240
if __name__ == '__main__':