91
CONFLICT_SUFFIXES = ['.BASE', '.OTHER', '.OTHER']
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."""
101
typestring = 'text conflict'
103
_conflict_re = re.compile(b'^(<{7}|={7}|>{7})')
105
def associated_filenames(self):
106
return [self.path + suffix for suffix in CONFLICT_SUFFIXES]
108
def _resolve(self, tt, winner_suffix):
109
"""Resolve the conflict by copying one of .THIS or .OTHER into file.
111
:param tt: The TreeTransform where the conflict is resolved.
112
:param winner_suffix: Either 'THIS' or 'OTHER'
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.
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)
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.
138
kind = tree.kind(self.path)
139
except errors.NoSuchFile:
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:
146
if conflict_markers_in_line(line):
147
raise NotImplementedError("Conflict markers present")
149
def _resolve_with_cleanups(self, tree, *args, **kwargs):
150
with tree.transform() as tt:
151
self._resolve(tt, *args, **kwargs)
153
def action_take_this(self, tree):
154
self._resolve_with_cleanups(tree, 'THIS')
156
def action_take_other(self, tree):
157
self._resolve_with_cleanups(tree, 'OTHER')
159
def do(self, action, tree):
160
"""Apply the specified action to the conflict.
162
:param action: The method name to call.
164
:param tree: The tree passed as a parameter to the method.
166
meth = getattr(self, 'action_%s' % action, None)
168
raise NotImplementedError(self.__class__.__name__ + '.' + action)
171
def action_auto(self, tree):
172
raise NotImplementedError(self.action_auto)
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.
90
180
class GitWorkingTree(MutableGitIndexTree, workingtree.WorkingTree):
91
181
"""A Git working tree."""