/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/merge.py

  • Committer: Breezy landing bot
  • Author(s): Gustav Hartvigsson
  • Date: 2021-01-10 18:46:30 UTC
  • mfrom: (7526.1.1 brz-removed-api-doc)
  • mto: This revision was merged to the branch mainline in revision 7532.
  • Revision ID: breezy.the.bot@gmail.com-20210110184630-dxu0g9dqq020uiw6
Drop documentation for removed API API.

Merged from https://code.launchpad.net/~gustav-hartvigsson/brz/removed-api-doc/+merge/396033

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
    revision as _mod_revision,
31
31
    textfile,
32
32
    trace,
33
 
    transform,
34
33
    tree as _mod_tree,
35
34
    tsort,
36
35
    ui,
37
36
    workingtree,
38
37
    )
39
38
from breezy.bzr import (
 
39
    conflicts as _mod_bzr_conflicts,
40
40
    generate_ids,
41
41
    versionedfile,
42
42
    )
43
43
from breezy.i18n import gettext
44
44
""")
 
45
from breezy.bzr.conflicts import Conflict as BzrConflict
45
46
from . import (
46
47
    decorators,
47
48
    errors,
48
49
    hooks,
49
50
    registry,
 
51
    transform,
50
52
    )
51
53
# TODO: Report back as changes are merged in
52
54
 
758
760
            stack.enter_context(self.this_tree.lock_read())
759
761
            stack.enter_context(self.base_tree.lock_read())
760
762
            stack.enter_context(self.other_tree.lock_read())
761
 
            self.tt = self.working_tree.get_transform()
 
763
            self.tt = self.working_tree.transform()
762
764
            stack.enter_context(self.tt)
763
765
            self._compute_transform()
764
766
            results = self.tt.apply(no_conflicts=True)
770
772
 
771
773
    def make_preview_transform(self):
772
774
        with self.base_tree.lock_read(), self.other_tree.lock_read():
773
 
            self.tt = transform.TransformPreview(self.working_tree)
 
775
            self.tt = self.working_tree.preview_transform()
774
776
            self._compute_transform()
775
777
            return self.tt
776
778
 
777
779
    def _compute_transform(self):
778
780
        if self._lca_trees is None:
779
 
            entries = self._entries3()
 
781
            entries = list(self._entries3())
780
782
            resolver = self._three_way
781
783
        else:
782
 
            entries = self._entries_lca()
 
784
            entries = list(self._entries_lca())
783
785
            resolver = self._lca_multi_way
784
786
        # Prepare merge hooks
785
787
        factories = Merger.hooks['merge_file_content']
788
790
        self.active_hooks = [hook for hook in hooks if hook is not None]
789
791
        with ui.ui_factory.nested_progress_bar() as child_pb:
790
792
            for num, (file_id, changed, paths3, parents3, names3,
791
 
                      executable3) in enumerate(entries):
 
793
                      executable3, copied) in enumerate(entries):
 
794
                if copied:
 
795
                    # Treat copies as simple adds for now
 
796
                    paths3 = (None, paths3[1], None)
 
797
                    parents3 = (None, parents3[1], None)
 
798
                    names3 = (None, names3[1], None)
 
799
                    executable3 = (None, executable3[1], None)
 
800
                    changed = True
 
801
                    copied = False
792
802
                trans_id = self.tt.trans_id_file_id(file_id)
793
 
 
794
803
                # Try merging each entry
795
804
                child_pb.update(gettext('Preparing file merge'),
796
805
                                num, len(entries))
831
840
        other and this.  names3 is a tuple of names for base, other and this.
832
841
        executable3 is a tuple of execute-bit values for base, other and this.
833
842
        """
834
 
        result = []
835
843
        iterator = self.other_tree.iter_changes(self.base_tree,
836
844
                                                specific_files=self.interesting_files,
837
845
                                                extra_trees=[self.this_tree])
859
867
            names3 = change.name + (this_name,)
860
868
            paths3 = change.path + (this_path, )
861
869
            executable3 = change.executable + (this_executable,)
862
 
            result.append(
 
870
            yield (
863
871
                (change.file_id, change.changed_content, paths3,
864
 
                 parents3, names3, executable3))
865
 
        return result
 
872
                 parents3, names3, executable3, change.copied))
866
873
 
867
874
    def _entries_lca(self):
868
875
        """Gather data about files modified between multiple trees.
872
879
 
873
880
        For the multi-valued entries, the format will be (BASE, [lca1, lca2])
874
881
 
875
 
        :return: [(file_id, changed, paths, parents, names, executable)], where:
 
882
        :return: [(file_id, changed, paths, parents, names, executable, copied)], where:
876
883
 
877
884
            * file_id: Simple file_id of the entry
878
885
            * changed: Boolean, True if the kind or contents changed else False
891
898
                self.interesting_files, lookup_trees)
892
899
        else:
893
900
            interesting_files = None
894
 
        result = []
895
901
        from .multiwalker import MultiWalker
896
902
        walker = MultiWalker(self.other_tree, self._lca_trees)
897
903
 
1035
1041
                    raise AssertionError('unhandled kind: %s' % other_ie.kind)
1036
1042
 
1037
1043
            # If we have gotten this far, that means something has changed
1038
 
            result.append((file_id, content_changed,
 
1044
            yield (file_id, content_changed,
1039
1045
                           ((base_path, lca_paths),
1040
1046
                            other_path, this_path),
1041
1047
                           ((base_ie.parent_id, lca_parent_ids),
1043
1049
                           ((base_ie.name, lca_names),
1044
1050
                            other_ie.name, this_ie.name),
1045
1051
                           ((base_ie.executable, lca_executable),
1046
 
                            other_ie.executable, this_ie.executable)
1047
 
                           ))
1048
 
        return result
 
1052
                            other_ie.executable, this_ie.executable),
 
1053
                           # Copy detection is not yet supported, so nothing is
 
1054
                           # a copy:
 
1055
                           False
 
1056
                           )
1049
1057
 
1050
1058
    def write_modified(self, results):
1051
1059
        if not self.working_tree.supports_merge_modified():
1284
1292
                    keep_this = True
1285
1293
                    # versioning the merged file will trigger a duplicate
1286
1294
                    # conflict
1287
 
                    self.tt.version_file(file_id, trans_id)
 
1295
                    self.tt.version_file(trans_id, file_id=file_id)
1288
1296
                    transform.create_from_tree(
1289
1297
                        self.tt, trans_id, self.other_tree,
1290
1298
                        other_path,
1307
1315
                # This is a contents conflict, because none of the available
1308
1316
                # functions could merge it.
1309
1317
                file_group = self._dump_conflicts(
1310
 
                    name, (base_path, other_path, this_path), parent_id,
1311
 
                    file_id, set_version=True)
 
1318
                    name, (base_path, other_path, this_path), parent_id)
 
1319
                for tid in file_group:
 
1320
                    self.tt.version_file(tid, file_id=file_id)
 
1321
                    break
1312
1322
                self._raw_conflicts.append(('contents conflict', file_group))
1313
1323
        elif hook_status == 'success':
1314
1324
            self.tt.create_file(lines, trans_id)
1320
1330
            name = self.tt.final_name(trans_id)
1321
1331
            parent_id = self.tt.final_parent(trans_id)
1322
1332
            self._dump_conflicts(
1323
 
                name, (base_path, other_path, this_path), parent_id, file_id)
 
1333
                name, (base_path, other_path, this_path), parent_id)
1324
1334
        elif hook_status == 'delete':
1325
1335
            self.tt.unversion_file(trans_id)
1326
1336
            result = "deleted"
1331
1341
        else:
1332
1342
            raise AssertionError('unknown hook_status: %r' % (hook_status,))
1333
1343
        if not this_path and result == "modified":
1334
 
            self.tt.version_file(file_id, trans_id)
 
1344
            self.tt.version_file(trans_id, file_id=file_id)
1335
1345
        if not keep_this:
1336
1346
            # The merge has been performed and produced a new content, so the
1337
1347
            # old contents should not be retained.
1426
1436
            self._raw_conflicts.append(('text conflict', trans_id))
1427
1437
            name = self.tt.final_name(trans_id)
1428
1438
            parent_id = self.tt.final_parent(trans_id)
1429
 
            file_id = self.tt.final_file_id(trans_id)
1430
 
            file_group = self._dump_conflicts(name, paths, parent_id, file_id,
1431
 
                                              this_lines, base_lines,
1432
 
                                              other_lines)
 
1439
            file_group = self._dump_conflicts(
 
1440
                name, paths, parent_id,
 
1441
                lines=(base_lines, other_lines, this_lines))
1433
1442
            file_group.append(trans_id)
1434
1443
 
1435
1444
    def _get_filter_tree_path(self, path):
1446
1455
        # Skip the lookup for older formats
1447
1456
        return None
1448
1457
 
1449
 
    def _dump_conflicts(self, name, paths, parent_id, file_id, this_lines=None,
1450
 
                        base_lines=None, other_lines=None, set_version=False,
 
1458
    def _dump_conflicts(self, name, paths, parent_id, lines=None,
1451
1459
                        no_base=False):
1452
1460
        """Emit conflict files.
1453
1461
        If this_lines, base_lines, or other_lines are omitted, they will be
1455
1463
        or .BASE (in that order) will be created as versioned files.
1456
1464
        """
1457
1465
        base_path, other_path, this_path = paths
 
1466
        if lines:
 
1467
            base_lines, other_lines, this_lines = lines
 
1468
        else:
 
1469
            base_lines = other_lines = this_lines = None
1458
1470
        data = [('OTHER', self.other_tree, other_path, other_lines),
1459
1471
                ('THIS', self.this_tree, this_path, this_lines)]
1460
1472
        if not no_base:
1461
1473
            data.append(('BASE', self.base_tree, base_path, base_lines))
1462
1474
 
1463
1475
        # We need to use the actual path in the working tree of the file here,
1464
 
        # ignoring the conflict suffixes
1465
 
        wt = self.this_tree
1466
 
        if wt.supports_content_filtering():
1467
 
            try:
1468
 
                filter_tree_path = wt.id2path(file_id)
1469
 
            except errors.NoSuchId:
1470
 
                # file has been deleted
1471
 
                filter_tree_path = None
 
1476
        if self.this_tree.supports_content_filtering():
 
1477
            filter_tree_path = this_path
1472
1478
        else:
1473
 
            # Skip the id2path lookup for older formats
1474
1479
            filter_tree_path = None
1475
1480
 
1476
 
        versioned = False
1477
1481
        file_group = []
1478
1482
        for suffix, tree, path, lines in data:
1479
1483
            if path is not None:
1481
1485
                    name, parent_id, path, tree, suffix, lines,
1482
1486
                    filter_tree_path)
1483
1487
                file_group.append(trans_id)
1484
 
                if set_version and not versioned:
1485
 
                    self.tt.version_file(file_id, trans_id)
1486
 
                    versioned = True
1487
1488
        return file_group
1488
1489
 
1489
1490
    def _conflict_file(self, name, parent_id, path, tree, suffix,
1530
1531
 
1531
1532
    def cook_conflicts(self, fs_conflicts):
1532
1533
        """Convert all conflicts into a form that doesn't depend on trans_id"""
1533
 
        content_conflict_file_ids = set()
1534
 
        cooked_conflicts = transform.cook_conflicts(fs_conflicts, self.tt)
1535
 
        fp = transform.FinalPaths(self.tt)
1536
 
        for conflict in self._raw_conflicts:
1537
 
            conflict_type = conflict[0]
1538
 
            if conflict_type == 'path conflict':
1539
 
                (trans_id, file_id,
1540
 
                 this_parent, this_name,
1541
 
                 other_parent, other_name) = conflict[1:]
1542
 
                if this_parent is None or this_name is None:
1543
 
                    this_path = '<deleted>'
1544
 
                else:
1545
 
                    parent_path = fp.get_path(
1546
 
                        self.tt.trans_id_file_id(this_parent))
1547
 
                    this_path = osutils.pathjoin(parent_path, this_name)
1548
 
                if other_parent is None or other_name is None:
1549
 
                    other_path = '<deleted>'
1550
 
                else:
1551
 
                    if other_parent == self.other_tree.path2id(''):
1552
 
                        # The tree transform doesn't know about the other root,
1553
 
                        # so we special case here to avoid a NoFinalPath
1554
 
                        # exception
1555
 
                        parent_path = ''
1556
 
                    else:
1557
 
                        parent_path = fp.get_path(
1558
 
                            self.tt.trans_id_file_id(other_parent))
1559
 
                    other_path = osutils.pathjoin(parent_path, other_name)
1560
 
                c = _mod_conflicts.Conflict.factory(
1561
 
                    'path conflict', path=this_path,
1562
 
                    conflict_path=other_path,
1563
 
                    file_id=file_id)
1564
 
            elif conflict_type == 'contents conflict':
1565
 
                for trans_id in conflict[1]:
1566
 
                    file_id = self.tt.final_file_id(trans_id)
1567
 
                    if file_id is not None:
1568
 
                        # Ok we found the relevant file-id
1569
 
                        break
1570
 
                path = fp.get_path(trans_id)
1571
 
                for suffix in ('.BASE', '.THIS', '.OTHER'):
1572
 
                    if path.endswith(suffix):
1573
 
                        # Here is the raw path
1574
 
                        path = path[:-len(suffix)]
1575
 
                        break
1576
 
                c = _mod_conflicts.Conflict.factory(conflict_type,
1577
 
                                                    path=path, file_id=file_id)
1578
 
                content_conflict_file_ids.add(file_id)
1579
 
            elif conflict_type == 'text conflict':
1580
 
                trans_id = conflict[1]
1581
 
                path = fp.get_path(trans_id)
1582
 
                file_id = self.tt.final_file_id(trans_id)
1583
 
                c = _mod_conflicts.Conflict.factory(conflict_type,
1584
 
                                                    path=path, file_id=file_id)
1585
 
            else:
1586
 
                raise AssertionError('bad conflict type: %r' % (conflict,))
1587
 
            cooked_conflicts.append(c)
1588
 
 
1589
 
        self.cooked_conflicts = []
1590
 
        # We want to get rid of path conflicts when a corresponding contents
1591
 
        # conflict exists. This can occur when one branch deletes a file while
1592
 
        # the other renames *and* modifies it. In this case, the content
1593
 
        # conflict is enough.
1594
 
        for c in cooked_conflicts:
1595
 
            if (c.typestring == 'path conflict'
1596
 
                    and c.file_id in content_conflict_file_ids):
1597
 
                continue
1598
 
            self.cooked_conflicts.append(c)
1599
 
        self.cooked_conflicts.sort(key=_mod_conflicts.Conflict.sort_key)
 
1534
        self.cooked_conflicts = list(self.tt.cook_conflicts(
 
1535
            list(fs_conflicts) + self._raw_conflicts))
1600
1536
 
1601
1537
 
1602
1538
class WeaveMerger(Merge3Merger):
1653
1589
            self._raw_conflicts.append(('text conflict', trans_id))
1654
1590
            name = self.tt.final_name(trans_id)
1655
1591
            parent_id = self.tt.final_parent(trans_id)
1656
 
            file_id = self.tt.final_file_id(trans_id)
1657
 
            file_group = self._dump_conflicts(name, paths, parent_id, file_id,
1658
 
                                              no_base=False,
1659
 
                                              base_lines=base_lines)
 
1592
            file_group = self._dump_conflicts(name, paths, parent_id,
 
1593
                                              (base_lines, None, None),
 
1594
                                              no_base=False)
1660
1595
            file_group.append(trans_id)
1661
1596
 
1662
1597
 
1706
1641
            if status == 1:
1707
1642
                name = self.tt.final_name(trans_id)
1708
1643
                parent_id = self.tt.final_parent(trans_id)
1709
 
                file_id = self.tt.final_file_id(trans_id)
1710
 
                self._dump_conflicts(name, paths, parent_id, file_id)
 
1644
                self._dump_conflicts(name, paths, parent_id)
1711
1645
                self._raw_conflicts.append(('text conflict', trans_id))
1712
1646
        finally:
1713
1647
            osutils.rmtree(temp_dir)