60
63
Use brz resolve when you have fixed a problem.
65
help='List paths of files with text conflicts.'),
68
help='List paths of files with text conflicts.'),
67
70
_see_also = ['resolve', 'conflict-types']
75
78
self.outf.write(conflict.path + '\n')
77
self.outf.write(str(conflict) + '\n')
80
self.outf.write(text_type(conflict) + '\n')
80
83
resolve_action_registry = registry.Registry()
83
86
resolve_action_registry.register(
84
'auto', 'auto', 'Detect whether conflict has been resolved by user.')
85
resolve_action_registry.register(
86
87
'done', 'done', 'Marks the conflict as resolved.')
87
88
resolve_action_registry.register(
88
89
'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']
126
125
def run(self, file_list=None, all=False, action=None, directory=None):
129
raise errors.CommandError(gettext("If --all is specified,"
130
" no FILE may be provided"))
128
raise errors.BzrCommandError(gettext("If --all is specified,"
129
" no FILE may be provided"))
131
130
if directory is None:
133
132
tree = workingtree.WorkingTree.open_containing(directory)[0]
137
136
tree, file_list = workingtree.WorkingTree.open_containing_paths(
138
137
file_list, directory)
140
if file_list is None:
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
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))
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.'))
157
trace.note(gettext('All conflicts resolved.'))
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
169
before, after = resolve(tree, file_list, action=action)
160
170
trace.note(ngettext('{0} conflict resolved, {1} remaining',
161
171
'{0} conflicts resolved, {1} remaining',
162
before - after).format(before - after, after))
172
before-after).format(before - after, after))
165
175
def resolve(tree, paths=None, ignore_misses=False, recursive=False,
360
370
# the factory blindly transfers the Stanza values to __init__ and
361
371
# Stanza is purely a Unicode api.
362
if isinstance(file_id, str):
372
if isinstance(file_id, text_type):
363
373
file_id = cache_utf8.encode(file_id)
364
self.file_id = file_id
374
self.file_id = osutils.safe_file_id(file_id)
366
376
def as_stanza(self):
367
377
s = rio.Stanza(type=self.typestring, path=self.path)
376
386
def __cmp__(self, other):
377
387
if getattr(other, "_cmp_list", None) is None:
380
y = other._cmp_list()
381
return (x > y) - (x < y)
389
return cmp(self._cmp_list(), other._cmp_list())
383
391
def __hash__(self):
384
392
return hash((type(self), self.path, self.file_id))
441
443
if e.errno != errno.ENOENT:
444
def action_auto(self, tree):
445
raise NotImplementedError(self.action_auto)
447
446
def action_done(self, tree):
448
447
"""Mark the conflict as solved once it has been handled."""
449
448
# This method does nothing but simplifies the design of upper levels.
456
455
raise NotImplementedError(self.action_take_other)
458
457
def _resolve_with_cleanups(self, tree, *args, **kwargs):
459
with tree.transform() as tt:
460
self._resolve(tt, *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)
463
464
class PathConflict(Conflict):
514
515
tid = tt.trans_id_tree_path(path_to_create)
515
516
tree = self._revision_tree(tt._tree, revid)
516
517
transform.create_from_tree(
517
tt, tid, tree, tree.id2path(file_id))
518
tt.version_file(tid, file_id=file_id)
518
tt, tid, tree, tree.id2path(file_id), file_id=file_id)
519
tt.version_file(file_id, tid)
520
521
tid = tt.trans_id_file_id(file_id)
521
522
# Adjust the path for the retained file id
609
610
# deleted the file either manually or when resolving a conflict on
610
611
# the parent. We may raise some exception to indicate that the
611
612
# conflict doesn't exist anymore and as such doesn't need to be
612
# resolved ? -- vila 20110615
613
# resolved ? -- vila 20110615
615
616
this_tid = tt.trans_id_tree_path(this_path)
665
664
# Switch the paths to preserve the content
666
665
tt.adjust_path(osutils.basename(self.path),
667
666
winner_parent_tid, winner_tid)
668
tt.adjust_path(osutils.basename(winner_path),
669
item_parent_tid, item_tid)
667
tt.adjust_path(osutils.basename(winner_path), item_parent_tid, item_tid)
670
668
# Associate the file_id to the right content
671
669
tt.unversion_file(item_tid)
672
tt.version_file(winner_tid, file_id=self.file_id)
670
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")
691
673
def action_take_this(self, tree):
692
674
self._resolve_with_cleanups(tree, 'THIS')
733
715
self.conflict_path = conflict_path
734
716
# the factory blindly transfers the Stanza values to __init__,
735
717
# so they can be unicode.
736
if isinstance(conflict_file_id, str):
718
if isinstance(conflict_file_id, text_type):
737
719
conflict_file_id = cache_utf8.encode(conflict_file_id)
738
self.conflict_file_id = conflict_file_id
720
self.conflict_file_id = osutils.safe_file_id(conflict_file_id)
740
722
def _cmp_list(self):
741
723
return HandledConflict._cmp_list(self) + [self.conflict_path,
795
777
def action_take_other(self, tree):
796
with tree.transform() as tt:
778
tt = transform.TreeTransform(tree)
797
780
p_tid = tt.trans_id_file_id(self.file_id)
798
781
parent_tid = tt.get_tree_parent(p_tid)
799
782
cp_tid = tt.trans_id_file_id(self.conflict_file_id)
906
891
for conflict_type in conflict_types:
907
892
ctype[conflict_type.typestring] = conflict_type
910
894
register_types(ContentsConflict, TextConflict, PathConflict, DuplicateID,
911
895
DuplicateEntry, ParentLoop, UnversionedParent, MissingParent,
912
896
DeletingParent, NonDirectoryParent)