7
7
from bzrlib.add import smart_add_tree
8
8
from bzrlib.builtins import merge
9
from bzrlib.conflicts import ContentsConflict, TextConflict, PathConflict
9
10
from bzrlib.errors import (NotBranchError, NotVersionedError,
10
11
WorkingTreeNotRevision, BzrCommandError, NoDiff3)
11
12
from bzrlib.inventory import RootEntry
37
38
return pathjoin(self.cset.entries[parent].path, name)
39
def add_file(self, id, parent, name, contents, executable):
40
def add_file(self, id, parent, name, contents, executable, this=True,
41
base=True, other=True):
41
43
parent_id = tt.trans_id_file_id(parent)
42
44
tt.new_file(name, parent_id, contents, id, executable)
43
for tt in (self.this_tt, self.base_tt, self.other_tt):
45
for option, tt in self.selected_transforms(this, base, other):
46
def merge(self, merge_type=Merge3Merger, interesting_ids=None):
49
def merge(self, merge_type=Merge3Merger, interesting_ids=None, **kwargs):
47
50
self.base_tt.apply()
48
51
self.base.commit('base commit')
49
52
for tt, wt in ((self.this_tt, self.this), (self.other_tt, self.other)):
50
53
wt.branch.pull(self.base.branch)
54
wt.set_last_revision(wt.branch.last_revision())
52
56
wt.commit('branch commit')
53
57
assert len(wt.branch.revision_history()) == 2
54
58
self.this.branch.fetch(self.other.branch)
55
59
other_basis = self.other.branch.basis_tree()
56
60
merger = merge_type(self.this, self.this, self.base, other_basis,
57
interesting_ids=interesting_ids)
61
interesting_ids=interesting_ids, **kwargs)
58
62
return merger.cooked_conflicts
60
64
def list_transforms(self):
191
196
builder.add_file("1", "TREE_ROOT", "name1", "hello1", False)
192
197
builder.change_name("1", other="name2", this="name3")
193
198
conflicts = builder.merge()
194
self.assertEqual(conflicts, [('path conflict', '1', 'name3', 'name2')])
199
self.assertEqual(conflicts, [PathConflict('name3', 'name2', '1')])
195
200
builder.cleanup()
197
202
def test_merge_one(self):
227
232
conflicts = builder.merge()
228
233
path2 = pathjoin('dir2', 'file1')
229
234
path3 = pathjoin('dir3', 'file1')
230
self.assertEqual(conflicts, [('path conflict', '4', path3, path2)])
235
self.assertEqual(conflicts, [PathConflict(path3, path2, '4')])
231
236
builder.cleanup()
233
238
def test_contents_merge(self):
245
250
"""Test diff3 merging"""
246
251
self.do_contents_test(WeaveMerger)
253
def test_reprocess_weave(self):
254
# Reprocess works on weaves, and behaves as expected
255
builder = MergeBuilder()
256
builder.add_file('a', 'TREE_ROOT', 'blah', 'a', False)
257
builder.change_contents('a', this='b\nc\nd\ne\n', other='z\nc\nd\ny\n')
258
builder.merge(WeaveMerger, reprocess=True)
259
expected = """<<<<<<< TREE
272
self.assertEqualDiff(builder.this.get_file("a").read(), expected)
248
276
def do_contents_test(self, merge_factory):
249
277
"""Test merging with specified ContentsChange factory"""
250
278
builder = self.contents_test_success(merge_factory)
260
288
builder.add_file("3", "TREE_ROOT", "name5", "text3", True)
261
289
builder.add_file("4", "TREE_ROOT", "name6", "text4", True)
262
290
builder.remove_file("4", base=True)
291
builder.add_file("5", "TREE_ROOT", "name7", "a\nb\nc\nd\ne\nf\n", True)
292
builder.change_contents("5", other="a\nz\nc\nd\ne\nf\n",
293
this="a\nb\nc\nd\ne\nz\n")
294
builder.merge(merge_factory)
264
295
self.assertEqual(builder.this.get_file("1").read(), "text4" )
265
296
self.assertEqual(builder.this.get_file("2").read(), "text2" )
297
self.assertEqual(builder.this.get_file("5").read(),
298
"a\nz\nc\nd\ne\nz\n")
266
299
self.assertIs(builder.this.is_executable("1"), True)
267
300
self.assertIs(builder.this.is_executable("2"), False)
268
301
self.assertIs(builder.this.is_executable("3"), True)
272
305
builder = MergeBuilder()
273
306
builder.add_file("1", "TREE_ROOT", "name1", "text1", True)
274
307
builder.change_contents("1", other="text4", this="text3")
308
builder.add_file("2", "TREE_ROOT", "name2", "text1", True)
309
builder.change_contents("2", other="\x00", this="text3")
275
310
conflicts = builder.merge(merge_factory)
276
self.assertEqual(conflicts, [('text conflict', '1', 'name1')])
311
self.assertEqual(conflicts, [TextConflict('name1', file_id='1'),
312
ContentsConflict('name2', file_id='2')])
313
self.assertEqual(builder.this.get_file('2').read(), '\x00')
277
314
builder.cleanup()
279
316
def test_symlink_conflicts(self):
282
319
builder.add_symlink("2", "TREE_ROOT", "name2", "target1")
283
320
builder.change_target("2", other="target4", base="text3")
284
321
conflicts = builder.merge()
285
self.assertEqual(conflicts, [('contents conflict', '2', 'name2')])
322
self.assertEqual(conflicts, [ContentsConflict('name2',
286
324
builder.cleanup()
288
326
def test_symlink_merge(self):
333
371
os.lstat(builder.this.id2abspath("2"))
334
372
builder.cleanup()
374
def test_spurious_conflict(self):
375
builder = MergeBuilder()
376
builder.add_file("1", "TREE_ROOT", "name1", "text1", False)
377
builder.remove_file("1", other=True)
378
builder.add_file("2", "TREE_ROOT", "name1", "text1", False, this=False,
380
conflicts = builder.merge()
381
self.assertEqual(conflicts, [])
337
384
class FunctionalMergeTest(TestCaseWithTransport):
393
440
[None, None], this_dir='b', check_clean=False,
394
441
merge_type=WeaveMerger)
396
os.unlink('b/file.THIS')
397
os.unlink('b/file.OTHER')
398
os.unlink('b/file.BASE')
399
443
self.assertEqual(merge(['a', -1], [None, None], this_dir='b',
400
444
check_clean=False, merge_type=WeaveMerger), 1)
401
445
self.assert_(os.path.lexists('b/file'))