/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 bzrlib/textmerge.py

Implemented reprocess for weave

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
#
17
 
# Author: Martin Pool <mbp@canonical.com>
 
17
# Author: Martin Pool <mbp@canonical.com> 
18
18
#         Aaron Bentley <aaron.bentley@utoronto.ca>
19
19
 
20
 
 
21
 
import bzrlib.patiencediff
 
20
from difflib import SequenceMatcher
22
21
 
23
22
 
24
23
class TextMerge(object):
25
24
    """Base class for text-mergers
26
25
    Subclasses must implement _merge_struct.
27
 
 
28
 
    Many methods produce or consume structured merge information.
29
 
    This is an iterable of tuples of lists of lines.
30
 
    Each tuple may have a length of 1 - 3, depending on whether the region it
31
 
    represents is conflicted.
32
 
 
33
 
    Unconflicted region tuples have length 1.
34
 
    Conflicted region tuples have length 2 or 3.  Index 1 is text_a, e.g. THIS.
35
 
    Index 1 is text_b, e.g. OTHER.  Index 2 is optional.  If present, it
36
 
    represents BASE.
37
26
    """
38
 
    # TODO: Show some version information (e.g. author, date) on conflicted
39
 
    # regions.
40
 
    A_MARKER = '<<<<<<< \n'
41
 
    B_MARKER = '>>>>>>> \n'
42
 
    SPLIT_MARKER = '=======\n'
43
 
    def __init__(self, a_marker=A_MARKER, b_marker=B_MARKER,
44
 
                 split_marker=SPLIT_MARKER):
 
27
    def __init__(self, a_marker='<<<<<<< \n', b_marker='>>>>>>> \n',
 
28
                 split_marker='=======\n'):
45
29
        self.a_marker = a_marker
46
30
        self.b_marker = b_marker
47
31
        self.split_marker = split_marker
48
32
 
49
 
    def _merge_struct(self):
50
 
        """Return structured merge info.  Must be implemented by subclasses.
51
 
        See TextMerge docstring for details on the format.
52
 
        """
53
 
        raise NotImplementedError('_merge_struct is abstract')
54
 
 
55
33
    def struct_to_lines(self, struct_iter):
56
34
        """Convert merge result tuples to lines"""
57
35
        for lines in struct_iter:
60
38
                    yield line
61
39
            else:
62
40
                yield self.a_marker
63
 
                for line in lines[0]:
 
41
                for line in lines[0]: 
64
42
                    yield line
65
43
                yield self.split_marker
66
 
                for line in lines[1]:
 
44
                for line in lines[1]: 
67
45
                    yield line
68
46
                yield self.b_marker
69
47
 
76
54
                yield group
77
55
 
78
56
    def merge_lines(self, reprocess=False):
79
 
        """Produce an iterable of lines, suitable for writing to a file
80
 
        Returns a tuple of (line iterable, conflict indicator)
81
 
        If reprocess is True, a two-way merge will be performed on the
82
 
        intermediate structure, to reduce conflict regions.
83
 
        """
84
 
        struct = []
85
 
        conflicts = False
86
 
        for group in self.merge_struct(reprocess):
87
 
            struct.append(group)
88
 
            if len(group) > 1:
89
 
                conflicts = True
90
 
        return self.struct_to_lines(struct), conflicts
 
57
        return self.struct_to_lines(self.merge_struct(reprocess))
91
58
 
92
59
    def merge_struct(self, reprocess=False):
93
 
        """Produce structured merge info"""
94
60
        struct_iter = self.iter_useful(self._merge_struct())
95
61
        if reprocess is True:
96
62
            return self.reprocess_struct(struct_iter)
99
65
 
100
66
    @staticmethod
101
67
    def reprocess_struct(struct_iter):
102
 
        """ Perform a two-way merge on structural merge info.
103
 
        This reduces the size of conflict regions, but breaks the connection
104
 
        between the BASE text and the conflict region.
105
 
 
106
 
        This process may split a single conflict region into several smaller
107
 
        ones, but will not introduce new conflicts.
108
 
        """
109
68
        for group in struct_iter:
110
69
            if len(group) == 1:
111
70
                yield group
115
74
 
116
75
 
117
76
class Merge2(TextMerge):
118
 
    """ Two-way merge.
 
77
 
 
78
    """
 
79
    Two-way merge.
119
80
    In a two way merge, common regions are shown as unconflicting, and uncommon
120
81
    regions produce conflicts.
121
82
    """
122
 
 
123
 
    def __init__(self, lines_a, lines_b, a_marker=TextMerge.A_MARKER,
124
 
                 b_marker=TextMerge.B_MARKER,
125
 
                 split_marker=TextMerge.SPLIT_MARKER):
 
83
    def __init__(self, lines_a, lines_b, a_marker='<<<<<<< \n', 
 
84
                 b_marker='>>>>>>> \n', split_marker='=======\n'):
126
85
        TextMerge.__init__(self, a_marker, b_marker, split_marker)
127
86
        self.lines_a = lines_a
128
87
        self.lines_b = lines_b
129
88
 
130
89
    def _merge_struct(self):
131
 
        """Return structured merge info.
132
 
        See TextMerge docstring.
133
 
        """
134
 
        sm = bzrlib.patiencediff.PatienceSequenceMatcher(None, self.lines_a, self.lines_b)
 
90
        sm = SequenceMatcher(None, self.lines_a, self.lines_b)
135
91
        pos_a = 0
136
92
        pos_b = 0
137
93
        for ai, bi, l in sm.get_matching_blocks():
139
95
            yield(self.lines_a[pos_a:ai], self.lines_b[pos_b:bi])
140
96
            # matching lines
141
97
            yield(self.lines_a[ai:ai+l],)
142
 
            pos_a = ai + l
 
98
            pos_a = ai + l 
143
99
            pos_b = bi + l
144
100
        # final non-matching lines
145
101
        yield(self.lines_a[pos_a:-1], self.lines_b[pos_b:-1])