863
859
names3 = change.name + (this_name,)
864
860
paths3 = change.path + (this_path, )
865
861
executable3 = change.executable + (this_executable,)
867
863
(change.file_id, change.changed_content, paths3,
868
864
parents3, names3, executable3))
871
866
def _entries_lca(self):
872
867
"""Gather data about files modified between multiple trees.
1311
1304
# This is a contents conflict, because none of the available
1312
1305
# functions could merge it.
1313
1306
file_group = self._dump_conflicts(
1314
name, (base_path, other_path, this_path), parent_id,
1315
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)
1316
1311
self._raw_conflicts.append(('contents conflict', file_group))
1317
1312
elif hook_status == 'success':
1318
1313
self.tt.create_file(lines, trans_id)
1324
1319
name = self.tt.final_name(trans_id)
1325
1320
parent_id = self.tt.final_parent(trans_id)
1326
1321
self._dump_conflicts(
1327
name, (base_path, other_path, this_path), parent_id, file_id)
1322
name, (base_path, other_path, this_path), parent_id)
1328
1323
elif hook_status == 'delete':
1329
1324
self.tt.unversion_file(trans_id)
1330
1325
result = "deleted"
1430
1425
self._raw_conflicts.append(('text conflict', trans_id))
1431
1426
name = self.tt.final_name(trans_id)
1432
1427
parent_id = self.tt.final_parent(trans_id)
1433
file_id = self.tt.final_file_id(trans_id)
1434
file_group = self._dump_conflicts(name, paths, parent_id, file_id,
1435
this_lines, base_lines,
1428
file_group = self._dump_conflicts(
1429
name, paths, parent_id,
1430
lines=(base_lines, other_lines, this_lines))
1437
1431
file_group.append(trans_id)
1439
1433
def _get_filter_tree_path(self, path):
1450
1444
# Skip the lookup for older formats
1453
def _dump_conflicts(self, name, paths, parent_id, file_id, this_lines=None,
1454
base_lines=None, other_lines=None, set_version=False,
1447
def _dump_conflicts(self, name, paths, parent_id, lines=None,
1455
1448
no_base=False):
1456
1449
"""Emit conflict files.
1457
1450
If this_lines, base_lines, or other_lines are omitted, they will be
1459
1452
or .BASE (in that order) will be created as versioned files.
1461
1454
base_path, other_path, this_path = paths
1456
base_lines, other_lines, this_lines = lines
1458
base_lines = other_lines = this_lines = None
1462
1459
data = [('OTHER', self.other_tree, other_path, other_lines),
1463
1460
('THIS', self.this_tree, this_path, this_lines)]
1464
1461
if not no_base:
1465
1462
data.append(('BASE', self.base_tree, base_path, base_lines))
1467
1464
# We need to use the actual path in the working tree of the file here,
1468
# ignoring the conflict suffixes
1470
if wt.supports_content_filtering():
1472
filter_tree_path = wt.id2path(file_id)
1473
except errors.NoSuchId:
1474
# file has been deleted
1475
filter_tree_path = None
1465
if self.this_tree.supports_content_filtering():
1466
filter_tree_path = this_path
1477
1468
# Skip the id2path lookup for older formats
1478
1469
filter_tree_path = None
1481
1471
file_group = []
1482
1472
for suffix, tree, path, lines in data:
1483
1473
if path is not None:
1485
1475
name, parent_id, path, tree, suffix, lines,
1486
1476
filter_tree_path)
1487
1477
file_group.append(trans_id)
1488
if set_version and not versioned:
1489
self.tt.version_file(trans_id, file_id=file_id)
1491
1478
return file_group
1493
1480
def _conflict_file(self, name, parent_id, path, tree, suffix,
1535
1522
def cook_conflicts(self, fs_conflicts):
1536
1523
"""Convert all conflicts into a form that doesn't depend on trans_id"""
1537
content_conflict_file_ids = set()
1538
cooked_conflicts = transform.cook_conflicts(fs_conflicts, self.tt)
1539
fp = transform.FinalPaths(self.tt)
1540
for conflict in self._raw_conflicts:
1541
conflict_type = conflict[0]
1542
if conflict_type == 'path conflict':
1544
this_parent, this_name,
1545
other_parent, other_name) = conflict[1:]
1546
if this_parent is None or this_name is None:
1547
this_path = '<deleted>'
1549
parent_path = fp.get_path(
1550
self.tt.trans_id_file_id(this_parent))
1551
this_path = osutils.pathjoin(parent_path, this_name)
1552
if other_parent is None or other_name is None:
1553
other_path = '<deleted>'
1555
if other_parent == self.other_tree.path2id(''):
1556
# The tree transform doesn't know about the other root,
1557
# so we special case here to avoid a NoFinalPath
1561
parent_path = fp.get_path(
1562
self.tt.trans_id_file_id(other_parent))
1563
other_path = osutils.pathjoin(parent_path, other_name)
1564
c = _mod_conflicts.Conflict.factory(
1565
'path conflict', path=this_path,
1566
conflict_path=other_path,
1568
elif conflict_type == 'contents conflict':
1569
for trans_id in conflict[1]:
1570
file_id = self.tt.final_file_id(trans_id)
1571
if file_id is not None:
1572
# Ok we found the relevant file-id
1574
path = fp.get_path(trans_id)
1575
for suffix in ('.BASE', '.THIS', '.OTHER'):
1576
if path.endswith(suffix):
1577
# Here is the raw path
1578
path = path[:-len(suffix)]
1580
c = _mod_conflicts.Conflict.factory(conflict_type,
1581
path=path, file_id=file_id)
1582
content_conflict_file_ids.add(file_id)
1583
elif conflict_type == 'text conflict':
1584
trans_id = conflict[1]
1585
path = fp.get_path(trans_id)
1586
file_id = self.tt.final_file_id(trans_id)
1587
c = _mod_conflicts.Conflict.factory(conflict_type,
1588
path=path, file_id=file_id)
1590
raise AssertionError('bad conflict type: %r' % (conflict,))
1591
cooked_conflicts.append(c)
1593
self.cooked_conflicts = []
1594
# We want to get rid of path conflicts when a corresponding contents
1595
# conflict exists. This can occur when one branch deletes a file while
1596
# the other renames *and* modifies it. In this case, the content
1597
# conflict is enough.
1598
for c in cooked_conflicts:
1599
if (c.typestring == 'path conflict'
1600
and c.file_id in content_conflict_file_ids):
1602
self.cooked_conflicts.append(c)
1603
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))
1606
1528
class WeaveMerger(Merge3Merger):
1657
1579
self._raw_conflicts.append(('text conflict', trans_id))
1658
1580
name = self.tt.final_name(trans_id)
1659
1581
parent_id = self.tt.final_parent(trans_id)
1660
file_id = self.tt.final_file_id(trans_id)
1661
file_group = self._dump_conflicts(name, paths, parent_id, file_id,
1663
base_lines=base_lines)
1582
file_group = self._dump_conflicts(name, paths, parent_id,
1583
(base_lines, None, None),
1664
1585
file_group.append(trans_id)