63
60
Use brz resolve when you have fixed a problem.
68
help='List paths of files with text conflicts.'),
65
help='List paths of files with text conflicts.'),
70
67
_see_also = ['resolve', 'conflict-types']
78
75
self.outf.write(conflict.path + '\n')
80
self.outf.write(text_type(conflict) + '\n')
77
self.outf.write(str(conflict) + '\n')
83
80
resolve_action_registry = registry.Registry()
86
83
resolve_action_registry.register(
84
'auto', 'auto', 'Detect whether conflict has been resolved by user.')
85
resolve_action_registry.register(
87
86
'done', 'done', 'Marks the conflict as resolved.')
88
87
resolve_action_registry.register(
89
88
'take-this', 'take_this',
117
117
aliases = ['resolved']
118
118
takes_args = ['file*']
119
119
takes_options = [
121
option.Option('all', help='Resolve all conflicts in this tree.'),
122
ResolveActionOption(),
121
option.Option('all', help='Resolve all conflicts in this tree.'),
122
ResolveActionOption(),
124
124
_see_also = ['conflicts']
125
126
def run(self, file_list=None, all=False, action=None, directory=None):
128
129
raise errors.BzrCommandError(gettext("If --all is specified,"
129
" no FILE may be provided"))
130
" no FILE may be provided"))
130
131
if directory is None:
132
133
tree = workingtree.WorkingTree.open_containing(directory)[0]
136
137
tree, file_list = workingtree.WorkingTree.open_containing_paths(
137
138
file_list, directory)
138
if file_list is None:
140
# FIXME: There is a special case here related to the option
141
# handling that could be clearer and easier to discover by
142
# providing an --auto action (bug #344013 and #383396) and
143
# make it mandatory instead of implicit and active only
144
# when no file_list is provided -- vila 091229
140
if file_list is None:
150
if file_list is None:
151
un_resolved, resolved = tree.auto_resolve()
152
if len(un_resolved) > 0:
153
trace.note(ngettext('%d conflict auto-resolved.',
154
'%d conflicts auto-resolved.', len(resolved)),
156
trace.note(gettext('Remaining conflicts:'))
157
for conflict in un_resolved:
158
trace.note(text_type(conflict))
161
trace.note(gettext('All conflicts resolved.'))
144
before, after = resolve(tree, file_list, action=action)
145
# GZ 2012-07-27: Should unify UI below now that auto is less magical.
146
if action == 'auto' and file_list is None:
149
ngettext('%d conflict auto-resolved.',
150
'%d conflicts auto-resolved.', before - after),
152
trace.note(gettext('Remaining conflicts:'))
153
for conflict in tree.conflicts():
154
trace.note(str(conflict))
164
# FIXME: This can never occur but the block above needs some
165
# refactoring to transfer tree.auto_resolve() to
166
# conflict.auto(tree) --vila 091242
157
trace.note(gettext('All conflicts resolved.'))
169
before, after = resolve(tree, file_list, action=action)
170
160
trace.note(ngettext('{0} conflict resolved, {1} remaining',
171
161
'{0} conflicts resolved, {1} remaining',
172
before-after).format(before - after, after))
162
before - after).format(before - after, after))
175
165
def resolve(tree, paths=None, ignore_misses=False, recursive=False,
370
360
# the factory blindly transfers the Stanza values to __init__ and
371
361
# Stanza is purely a Unicode api.
372
if isinstance(file_id, text_type):
362
if isinstance(file_id, str):
373
363
file_id = cache_utf8.encode(file_id)
374
364
self.file_id = osutils.safe_file_id(file_id)
386
376
def __cmp__(self, other):
387
377
if getattr(other, "_cmp_list", None) is None:
389
return cmp(self._cmp_list(), other._cmp_list())
380
y = other._cmp_list()
381
return (x > y) - (x < y)
391
383
def __hash__(self):
392
384
return hash((type(self), self.path, self.file_id))
443
441
if e.errno != errno.ENOENT:
444
def action_auto(self, tree):
445
raise NotImplementedError(self.action_auto)
446
447
def action_done(self, tree):
447
448
"""Mark the conflict as solved once it has been handled."""
448
449
# This method does nothing but simplifies the design of upper levels.
455
456
raise NotImplementedError(self.action_take_other)
457
458
def _resolve_with_cleanups(self, tree, *args, **kwargs):
458
tt = transform.TreeTransform(tree)
459
op = cleanup.OperationWithCleanups(self._resolve)
460
op.add_cleanup(tt.finalize)
461
op.run_simple(tt, *args, **kwargs)
459
with tree.get_transform() as tt:
460
self._resolve(tt, *args, **kwargs)
464
463
class PathConflict(Conflict):
515
514
tid = tt.trans_id_tree_path(path_to_create)
516
515
tree = self._revision_tree(tt._tree, revid)
517
516
transform.create_from_tree(
518
tt, tid, tree, tree.id2path(file_id), file_id=file_id)
517
tt, tid, tree, tree.id2path(file_id))
519
518
tt.version_file(file_id, tid)
521
520
tid = tt.trans_id_file_id(file_id)
610
609
# deleted the file either manually or when resolving a conflict on
611
610
# the parent. We may raise some exception to indicate that the
612
611
# conflict doesn't exist anymore and as such doesn't need to be
613
# resolved ? -- vila 20110615
612
# resolved ? -- vila 20110615
616
615
this_tid = tt.trans_id_tree_path(this_path)
664
665
# Switch the paths to preserve the content
665
666
tt.adjust_path(osutils.basename(self.path),
666
667
winner_parent_tid, winner_tid)
667
tt.adjust_path(osutils.basename(winner_path), item_parent_tid, item_tid)
668
tt.adjust_path(osutils.basename(winner_path),
669
item_parent_tid, item_tid)
668
670
# Associate the file_id to the right content
669
671
tt.unversion_file(item_tid)
670
672
tt.version_file(self.file_id, winner_tid)
675
def action_auto(self, tree):
676
# GZ 2012-07-27: Using NotImplementedError to signal that a conflict
677
# can't be auto resolved does not seem ideal.
679
kind = tree.kind(self.path)
680
except errors.NoSuchFile:
683
raise NotImplementedError("Conflict is not a file")
684
conflict_markers_in_line = self._conflict_re.search
685
# GZ 2012-07-27: What if not tree.has_id(self.file_id) due to removal?
686
with tree.get_file(self.path) as f:
688
if conflict_markers_in_line(line):
689
raise NotImplementedError("Conflict markers present")
673
691
def action_take_this(self, tree):
674
692
self._resolve_with_cleanups(tree, 'THIS')
715
733
self.conflict_path = conflict_path
716
734
# the factory blindly transfers the Stanza values to __init__,
717
735
# so they can be unicode.
718
if isinstance(conflict_file_id, text_type):
736
if isinstance(conflict_file_id, str):
719
737
conflict_file_id = cache_utf8.encode(conflict_file_id)
720
738
self.conflict_file_id = osutils.safe_file_id(conflict_file_id)
777
795
def action_take_other(self, tree):
778
tt = transform.TreeTransform(tree)
796
with tree.get_transform() as tt:
780
797
p_tid = tt.trans_id_file_id(self.file_id)
781
798
parent_tid = tt.get_tree_parent(p_tid)
782
799
cp_tid = tt.trans_id_file_id(self.conflict_file_id)
891
906
for conflict_type in conflict_types:
892
907
ctype[conflict_type.typestring] = conflict_type
894
910
register_types(ContentsConflict, TextConflict, PathConflict, DuplicateID,
895
911
DuplicateEntry, ParentLoop, UnversionedParent, MissingParent,
896
912
DeletingParent, NonDirectoryParent)