/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/git/workingtree.py

  • Committer: Jelmer Vernooij
  • Date: 2020-08-09 18:10:01 UTC
  • mto: (7490.133.15 transform)
  • mto: This revision was merged to the branch mainline in revision 7521.
  • Revision ID: jelmer@jelmer.uk-20200809181001-bt9wdmmquzij3e5l
Split out bzr-specific Conflicts code.

Show diffs side-by-side

added added

removed removed

Lines of Context:
46
46
    )
47
47
import os
48
48
import posixpath
 
49
import re
49
50
import stat
50
51
import sys
51
52
 
87
88
    )
88
89
 
89
90
 
 
91
CONFLICT_SUFFIXES = ['.BASE', '.OTHER', '.OTHER']
 
92
 
 
93
 
 
94
# TODO: There should be a base revid attribute to better inform the user about
 
95
# how the conflicts were generated.
 
96
class TextConflict(_mod_conflicts.Conflict):
 
97
    """The merge algorithm could not resolve all differences encountered."""
 
98
 
 
99
    has_files = True
 
100
 
 
101
    typestring = 'text conflict'
 
102
 
 
103
    _conflict_re = re.compile(b'^(<{7}|={7}|>{7})')
 
104
 
 
105
    def associated_filenames(self):
 
106
        return [self.path + suffix for suffix in CONFLICT_SUFFIXES]
 
107
 
 
108
    def _resolve(self, tt, winner_suffix):
 
109
        """Resolve the conflict by copying one of .THIS or .OTHER into file.
 
110
 
 
111
        :param tt: The TreeTransform where the conflict is resolved.
 
112
        :param winner_suffix: Either 'THIS' or 'OTHER'
 
113
 
 
114
        The resolution is symmetric, when taking THIS, item.THIS is renamed
 
115
        into item and vice-versa. This takes one of the files as a whole
 
116
        ignoring every difference that could have been merged cleanly.
 
117
        """
 
118
        # To avoid useless copies, we switch item and item.winner_suffix, only
 
119
        # item will exist after the conflict has been resolved anyway.
 
120
        item_tid = tt.trans_id_tree_path(self.path)
 
121
        item_parent_tid = tt.get_tree_parent(item_tid)
 
122
        winner_path = self.path + '.' + winner_suffix
 
123
        winner_tid = tt.trans_id_tree_path(winner_path)
 
124
        winner_parent_tid = tt.get_tree_parent(winner_tid)
 
125
        # Switch the paths to preserve the content
 
126
        tt.adjust_path(osutils.basename(self.path),
 
127
                       winner_parent_tid, winner_tid)
 
128
        tt.adjust_path(osutils.basename(winner_path),
 
129
                       item_parent_tid, item_tid)
 
130
        tt.unversion_file(item_tid)
 
131
        tt.version_file(winner_tid)
 
132
        tt.apply()
 
133
 
 
134
    def action_auto(self, tree):
 
135
        # GZ 2012-07-27: Using NotImplementedError to signal that a conflict
 
136
        #                can't be auto resolved does not seem ideal.
 
137
        try:
 
138
            kind = tree.kind(self.path)
 
139
        except errors.NoSuchFile:
 
140
            return
 
141
        if kind != 'file':
 
142
            raise NotImplementedError("Conflict is not a file")
 
143
        conflict_markers_in_line = self._conflict_re.search
 
144
        with tree.get_file(self.path) as f:
 
145
            for line in f:
 
146
                if conflict_markers_in_line(line):
 
147
                    raise NotImplementedError("Conflict markers present")
 
148
 
 
149
    def _resolve_with_cleanups(self, tree, *args, **kwargs):
 
150
        with tree.transform() as tt:
 
151
            self._resolve(tt, *args, **kwargs)
 
152
 
 
153
    def action_take_this(self, tree):
 
154
        self._resolve_with_cleanups(tree, 'THIS')
 
155
 
 
156
    def action_take_other(self, tree):
 
157
        self._resolve_with_cleanups(tree, 'OTHER')
 
158
 
 
159
    def do(self, action, tree):
 
160
        """Apply the specified action to the conflict.
 
161
 
 
162
        :param action: The method name to call.
 
163
 
 
164
        :param tree: The tree passed as a parameter to the method.
 
165
        """
 
166
        meth = getattr(self, 'action_%s' % action, None)
 
167
        if meth is None:
 
168
            raise NotImplementedError(self.__class__.__name__ + '.' + action)
 
169
        meth(tree)
 
170
 
 
171
    def action_auto(self, tree):
 
172
        raise NotImplementedError(self.action_auto)
 
173
 
 
174
    def action_done(self, tree):
 
175
        """Mark the conflict as solved once it has been handled."""
 
176
        # This method does nothing but simplifies the design of upper levels.
 
177
        pass
 
178
 
 
179
 
90
180
class GitWorkingTree(MutableGitIndexTree, workingtree.WorkingTree):
91
181
    """A Git working tree."""
92
182
 
870
960
            conflicts = _mod_conflicts.ConflictList()
871
961
            for item_path, value in self.index.iteritems():
872
962
                if value.flags & FLAG_STAGEMASK:
873
 
                    conflicts.append(_mod_conflicts.TextConflict(
874
 
                        decode_git_path(item_path)))
 
963
                    conflicts.append(TextConflict(decode_git_path(item_path)))
875
964
            return conflicts
876
965
 
877
966
    def set_conflicts(self, conflicts):