/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/conflicts.py

  • Committer: Jelmer Vernooij
  • Date: 2018-05-06 11:48:54 UTC
  • mto: This revision was merged to the branch mainline in revision 6960.
  • Revision ID: jelmer@jelmer.uk-20180506114854-h4qd9ojaqy8wxjsd
Move .mailmap to root.

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
from __future__ import absolute_import
21
21
 
22
22
import os
23
 
import re
24
23
 
25
24
from .lazy_import import lazy_import
26
25
lazy_import(globals(), """
27
26
import errno
28
27
 
29
28
from breezy import (
 
29
    cleanup,
 
30
    errors,
30
31
    osutils,
31
32
    rio,
32
33
    trace,
37
38
""")
38
39
from . import (
39
40
    cache_utf8,
40
 
    errors,
41
41
    commands,
42
42
    option,
43
43
    registry,
63
63
    Use brz resolve when you have fixed a problem.
64
64
    """
65
65
    takes_options = [
66
 
        'directory',
67
 
        option.Option('text',
68
 
                      help='List paths of files with text conflicts.'),
 
66
            'directory',
 
67
            option.Option('text',
 
68
                          help='List paths of files with text conflicts.'),
69
69
        ]
70
70
    _see_also = ['resolve', 'conflict-types']
71
71
 
84
84
 
85
85
 
86
86
resolve_action_registry.register(
87
 
    'auto', 'auto', 'Detect whether conflict has been resolved by user.')
88
 
resolve_action_registry.register(
89
87
    'done', 'done', 'Marks the conflict as resolved.')
90
88
resolve_action_registry.register(
91
89
    'take-this', 'take_this',
95
93
    'Resolve the conflict taking the merged version into account.')
96
94
resolve_action_registry.default_key = 'done'
97
95
 
98
 
 
99
96
class ResolveActionOption(option.RegistryOption):
100
97
 
101
98
    def __init__(self):
120
117
    aliases = ['resolved']
121
118
    takes_args = ['file*']
122
119
    takes_options = [
123
 
        'directory',
124
 
        option.Option('all', help='Resolve all conflicts in this tree.'),
125
 
        ResolveActionOption(),
126
 
        ]
 
120
            'directory',
 
121
            option.Option('all', help='Resolve all conflicts in this tree.'),
 
122
            ResolveActionOption(),
 
123
            ]
127
124
    _see_also = ['conflicts']
128
 
 
129
125
    def run(self, file_list=None, all=False, action=None, directory=None):
130
126
        if all:
131
127
            if file_list:
132
128
                raise errors.BzrCommandError(gettext("If --all is specified,"
133
 
                                                     " no FILE may be provided"))
 
129
                                             " no FILE may be provided"))
134
130
            if directory is None:
135
131
                directory = u'.'
136
132
            tree = workingtree.WorkingTree.open_containing(directory)[0]
139
135
        else:
140
136
            tree, file_list = workingtree.WorkingTree.open_containing_paths(
141
137
                file_list, directory)
142
 
            if action is None:
143
 
                if file_list is None:
 
138
            if file_list is None:
 
139
                if action 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
145
                    action = 'auto'
145
 
                else:
 
146
            else:
 
147
                if action is None:
146
148
                    action = 'done'
147
 
        before, after = resolve(tree, file_list, action=action)
148
 
        # GZ 2012-07-27: Should unify UI below now that auto is less magical.
149
 
        if action == 'auto' and file_list is None:
150
 
            if after > 0:
151
 
                trace.note(
152
 
                    ngettext('%d conflict auto-resolved.',
153
 
                             '%d conflicts auto-resolved.', before - after),
154
 
                    before - after)
155
 
                trace.note(gettext('Remaining conflicts:'))
156
 
                for conflict in tree.conflicts():
157
 
                    trace.note(text_type(conflict))
158
 
                return 1
 
149
        if action == 'auto':
 
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)),
 
155
                        len(resolved))
 
156
                    trace.note(gettext('Remaining conflicts:'))
 
157
                    for conflict in un_resolved:
 
158
                        trace.note(text_type(conflict))
 
159
                    return 1
 
160
                else:
 
161
                    trace.note(gettext('All conflicts resolved.'))
 
162
                    return 0
159
163
            else:
160
 
                trace.note(gettext('All conflicts resolved.'))
161
 
                return 0
 
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
 
167
                pass
162
168
        else:
 
169
            before, after = resolve(tree, file_list, action=action)
163
170
            trace.note(ngettext('{0} conflict resolved, {1} remaining',
164
171
                                '{0} conflicts resolved, {1} remaining',
165
 
                                before - after).format(before - after, after))
 
172
                                before-after).format(before - after, after))
166
173
 
167
174
 
168
175
def resolve(tree, paths=None, ignore_misses=False, recursive=False,
379
386
    def __cmp__(self, other):
380
387
        if getattr(other, "_cmp_list", None) is None:
381
388
            return -1
382
 
        x = self._cmp_list()
383
 
        y = other._cmp_list()
384
 
        return (x > y) - (x < y)
 
389
        return cmp(self._cmp_list(), other._cmp_list())
385
390
 
386
391
    def __hash__(self):
387
392
        return hash((type(self), self.path, self.file_id))
393
398
        return not self.__eq__(other)
394
399
 
395
400
    def __unicode__(self):
396
 
        return self.describe()
397
 
 
398
 
    def __str__(self):
399
 
        return self.describe()
400
 
 
401
 
    def describe(self):
402
401
        return self.format % self.__dict__
403
402
 
404
403
    def __repr__(self):
444
443
                if e.errno != errno.ENOENT:
445
444
                    raise
446
445
 
447
 
    def action_auto(self, tree):
448
 
        raise NotImplementedError(self.action_auto)
449
 
 
450
446
    def action_done(self, tree):
451
447
        """Mark the conflict as solved once it has been handled."""
452
448
        # This method does nothing but simplifies the design of upper levels.
459
455
        raise NotImplementedError(self.action_take_other)
460
456
 
461
457
    def _resolve_with_cleanups(self, tree, *args, **kwargs):
462
 
        with tree.get_transform() as tt:
463
 
            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)
464
462
 
465
463
 
466
464
class PathConflict(Conflict):
497
495
        path_to_create = None
498
496
        if winner == 'this':
499
497
            if self.path == '<deleted>':
500
 
                return  # Nothing to do
 
498
                return # Nothing to do
501
499
            if self.conflict_path == '<deleted>':
502
500
                path_to_create = self.path
503
501
                revid = tt._tree.get_parent_ids()[0]
517
515
            tid = tt.trans_id_tree_path(path_to_create)
518
516
            tree = self._revision_tree(tt._tree, revid)
519
517
            transform.create_from_tree(
520
 
                tt, tid, tree, tree.id2path(file_id))
 
518
                tt, tid, tree, tree.id2path(file_id), file_id=file_id)
521
519
            tt.version_file(file_id, tid)
522
520
        else:
523
521
            tid = tt.trans_id_file_id(file_id)
536
534
        possible_paths = []
537
535
        for p in (self.path, self.conflict_path):
538
536
            if p == '<deleted>':
539
 
                # special hard-coded path
 
537
                # special hard-coded path 
540
538
                continue
541
539
            if p is not None:
542
540
                possible_paths.append(p)
612
610
            # deleted the file either manually or when resolving a conflict on
613
611
            # the parent.  We may raise some exception to indicate that the
614
612
            # conflict doesn't exist anymore and as such doesn't need to be
615
 
            # resolved ? -- vila 20110615
 
613
            # resolved ? -- vila 20110615 
616
614
            this_tid = None
617
615
        else:
618
616
            this_tid = tt.trans_id_tree_path(this_path)
643
641
 
644
642
    rformat = '%(class)s(%(path)r, %(file_id)r)'
645
643
 
646
 
    _conflict_re = re.compile(b'^(<{7}|={7}|>{7})')
647
 
 
648
644
    def associated_filenames(self):
649
645
        return [self.path + suffix for suffix in CONFLICT_SUFFIXES]
650
646
 
668
664
        # Switch the paths to preserve the content
669
665
        tt.adjust_path(osutils.basename(self.path),
670
666
                       winner_parent_tid, winner_tid)
671
 
        tt.adjust_path(osutils.basename(winner_path),
672
 
                       item_parent_tid, item_tid)
 
667
        tt.adjust_path(osutils.basename(winner_path), item_parent_tid, item_tid)
673
668
        # Associate the file_id to the right content
674
669
        tt.unversion_file(item_tid)
675
670
        tt.version_file(self.file_id, winner_tid)
676
671
        tt.apply()
677
672
 
678
 
    def action_auto(self, tree):
679
 
        # GZ 2012-07-27: Using NotImplementedError to signal that a conflict
680
 
        #                can't be auto resolved does not seem ideal.
681
 
        try:
682
 
            kind = tree.kind(self.path)
683
 
        except errors.NoSuchFile:
684
 
            return
685
 
        if kind != 'file':
686
 
            raise NotImplementedError("Conflict is not a file")
687
 
        conflict_markers_in_line = self._conflict_re.search
688
 
        # GZ 2012-07-27: What if not tree.has_id(self.file_id) due to removal?
689
 
        with tree.get_file(self.path) as f:
690
 
            for line in f:
691
 
                if conflict_markers_in_line(line):
692
 
                    raise NotImplementedError("Conflict markers present")
693
 
 
694
673
    def action_take_this(self, tree):
695
674
        self._resolve_with_cleanups(tree, 'THIS')
696
675
 
796
775
        pass
797
776
 
798
777
    def action_take_other(self, tree):
799
 
        with tree.get_transform() as tt:
 
778
        tt = transform.TreeTransform(tree)
 
779
        try:
800
780
            p_tid = tt.trans_id_file_id(self.file_id)
801
781
            parent_tid = tt.get_tree_parent(p_tid)
802
782
            cp_tid = tt.trans_id_file_id(self.conflict_file_id)
805
785
            tt.adjust_path(osutils.basename(self.conflict_path),
806
786
                           parent_tid, p_tid)
807
787
            tt.apply()
 
788
        finally:
 
789
            tt.finalize()
808
790
 
809
791
 
810
792
class UnversionedParent(HandledConflict):
909
891
    for conflict_type in conflict_types:
910
892
        ctype[conflict_type.typestring] = conflict_type
911
893
 
912
 
 
913
894
register_types(ContentsConflict, TextConflict, PathConflict, DuplicateID,
914
895
               DuplicateEntry, ParentLoop, UnversionedParent, MissingParent,
915
896
               DeletingParent, NonDirectoryParent)