1302
1304
# This is a contents conflict, because none of the available
1303
1305
# functions could merge it.
1304
1306
file_group = self._dump_conflicts(
1305
name, (base_path, other_path, this_path), parent_id,
1306
file_id, set_version=True)
1307
name, (base_path, other_path, this_path), parent_id)
1308
for tid in file_group:
1309
self.tt.version_file(tid, file_id=file_id)
1307
1311
self._raw_conflicts.append(('contents conflict', file_group))
1308
1312
elif hook_status == 'success':
1309
1313
self.tt.create_file(lines, trans_id)
1315
1319
name = self.tt.final_name(trans_id)
1316
1320
parent_id = self.tt.final_parent(trans_id)
1317
1321
self._dump_conflicts(
1318
name, (base_path, other_path, this_path), parent_id, file_id)
1322
name, (base_path, other_path, this_path), parent_id)
1319
1323
elif hook_status == 'delete':
1320
1324
self.tt.unversion_file(trans_id)
1321
1325
result = "deleted"
1421
1425
self._raw_conflicts.append(('text conflict', trans_id))
1422
1426
name = self.tt.final_name(trans_id)
1423
1427
parent_id = self.tt.final_parent(trans_id)
1424
file_id = self.tt.final_file_id(trans_id)
1425
file_group = self._dump_conflicts(name, paths, parent_id, file_id,
1426
this_lines, base_lines,
1428
file_group = self._dump_conflicts(
1429
name, paths, parent_id,
1430
lines=(base_lines, other_lines, this_lines))
1428
1431
file_group.append(trans_id)
1430
1433
def _get_filter_tree_path(self, path):
1441
1444
# Skip the lookup for older formats
1444
def _dump_conflicts(self, name, paths, parent_id, file_id, this_lines=None,
1445
base_lines=None, other_lines=None, set_version=False,
1447
def _dump_conflicts(self, name, paths, parent_id, lines=None,
1446
1448
no_base=False):
1447
1449
"""Emit conflict files.
1448
1450
If this_lines, base_lines, or other_lines are omitted, they will be
1450
1452
or .BASE (in that order) will be created as versioned files.
1452
1454
base_path, other_path, this_path = paths
1456
base_lines, other_lines, this_lines = lines
1458
base_lines = other_lines = this_lines = None
1453
1459
data = [('OTHER', self.other_tree, other_path, other_lines),
1454
1460
('THIS', self.this_tree, this_path, this_lines)]
1455
1461
if not no_base:
1470
1475
name, parent_id, path, tree, suffix, lines,
1471
1476
filter_tree_path)
1472
1477
file_group.append(trans_id)
1473
if set_version and not versioned:
1474
self.tt.version_file(trans_id, file_id=file_id)
1476
1478
return file_group
1478
1480
def _conflict_file(self, name, parent_id, path, tree, suffix,
1520
1522
def cook_conflicts(self, fs_conflicts):
1521
1523
"""Convert all conflicts into a form that doesn't depend on trans_id"""
1522
content_conflict_file_ids = set()
1523
cooked_conflicts = transform.cook_conflicts(fs_conflicts, self.tt)
1524
fp = transform.FinalPaths(self.tt)
1525
for conflict in self._raw_conflicts:
1526
conflict_type = conflict[0]
1527
if conflict_type == 'path conflict':
1529
this_parent, this_name,
1530
other_parent, other_name) = conflict[1:]
1531
if this_parent is None or this_name is None:
1532
this_path = '<deleted>'
1534
parent_path = fp.get_path(
1535
self.tt.trans_id_file_id(this_parent))
1536
this_path = osutils.pathjoin(parent_path, this_name)
1537
if other_parent is None or other_name is None:
1538
other_path = '<deleted>'
1540
if other_parent == self.other_tree.path2id(''):
1541
# The tree transform doesn't know about the other root,
1542
# so we special case here to avoid a NoFinalPath
1546
parent_path = fp.get_path(
1547
self.tt.trans_id_file_id(other_parent))
1548
other_path = osutils.pathjoin(parent_path, other_name)
1549
c = _mod_conflicts.Conflict.factory(
1550
'path conflict', path=this_path,
1551
conflict_path=other_path,
1553
elif conflict_type == 'contents conflict':
1554
for trans_id in conflict[1]:
1555
file_id = self.tt.final_file_id(trans_id)
1556
if file_id is not None:
1557
# Ok we found the relevant file-id
1559
path = fp.get_path(trans_id)
1560
for suffix in ('.BASE', '.THIS', '.OTHER'):
1561
if path.endswith(suffix):
1562
# Here is the raw path
1563
path = path[:-len(suffix)]
1565
c = _mod_conflicts.Conflict.factory(conflict_type,
1566
path=path, file_id=file_id)
1567
content_conflict_file_ids.add(file_id)
1568
elif conflict_type == 'text conflict':
1569
trans_id = conflict[1]
1570
path = fp.get_path(trans_id)
1571
file_id = self.tt.final_file_id(trans_id)
1572
c = _mod_conflicts.Conflict.factory(conflict_type,
1573
path=path, file_id=file_id)
1575
raise AssertionError('bad conflict type: %r' % (conflict,))
1576
cooked_conflicts.append(c)
1578
self.cooked_conflicts = []
1579
# We want to get rid of path conflicts when a corresponding contents
1580
# conflict exists. This can occur when one branch deletes a file while
1581
# the other renames *and* modifies it. In this case, the content
1582
# conflict is enough.
1583
for c in cooked_conflicts:
1584
if (c.typestring == 'path conflict'
1585
and c.file_id in content_conflict_file_ids):
1587
self.cooked_conflicts.append(c)
1588
self.cooked_conflicts.sort(key=_mod_conflicts.Conflict.sort_key)
1524
self.cooked_conflicts = list(self.tt.cook_conflicts(
1525
list(fs_conflicts) + self._raw_conflicts))
1591
1528
class WeaveMerger(Merge3Merger):
1642
1579
self._raw_conflicts.append(('text conflict', trans_id))
1643
1580
name = self.tt.final_name(trans_id)
1644
1581
parent_id = self.tt.final_parent(trans_id)
1645
file_id = self.tt.final_file_id(trans_id)
1646
file_group = self._dump_conflicts(name, paths, parent_id, file_id,
1648
base_lines=base_lines)
1582
file_group = self._dump_conflicts(name, paths, parent_id,
1583
(base_lines, None, None),
1649
1585
file_group.append(trans_id)