~bzr-pqm/bzr/bzr.dev

5273.1.5 by Vincent Ladeuil
Merge bzr.dev into cleanup
1
# Copyright (C) 2006, 2009, 2010 Canonical Ltd
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
16
#
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
17
# Author: Martin Pool <mbp@canonical.com>
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
18
#         Aaron Bentley <aaron.bentley@utoronto.ca>
19
6379.6.3 by Jelmer Vernooij
Use absolute_import.
20
from __future__ import absolute_import
1551.6.13 by Aaron Bentley
Cleanup
21
5279.1.1 by Andrew Bennetts
lazy_import most things in merge.py; add a few representative modules to the import tariff tests; tweak a couple of other modules so that patiencediff is not necessarily imported; remove a bunch of unused imports from test_knit.py.
22
from bzrlib.lazy_import import lazy_import
23
lazy_import(globals(), """
24
from bzrlib import patiencediff
25
""")
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
26
27
28
class TextMerge(object):
1551.6.8 by Aaron Bentley
Implemented reprocess for weave
29
    """Base class for text-mergers
30
    Subclasses must implement _merge_struct.
1551.6.13 by Aaron Bentley
Cleanup
31
32
    Many methods produce or consume structured merge information.
33
    This is an iterable of tuples of lists of lines.
34
    Each tuple may have a length of 1 - 3, depending on whether the region it
35
    represents is conflicted.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
36
1551.6.13 by Aaron Bentley
Cleanup
37
    Unconflicted region tuples have length 1.
38
    Conflicted region tuples have length 2 or 3.  Index 1 is text_a, e.g. THIS.
39
    Index 1 is text_b, e.g. OTHER.  Index 2 is optional.  If present, it
40
    represents BASE.
1551.6.8 by Aaron Bentley
Implemented reprocess for weave
41
    """
1551.6.13 by Aaron Bentley
Cleanup
42
    # TODO: Show some version information (e.g. author, date) on conflicted
43
    # regions.
1551.6.14 by Aaron Bentley
Tweaks from merge review
44
    A_MARKER = '<<<<<<< \n'
45
    B_MARKER = '>>>>>>> \n'
46
    SPLIT_MARKER = '=======\n'
47
    def __init__(self, a_marker=A_MARKER, b_marker=B_MARKER,
48
                 split_marker=SPLIT_MARKER):
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
49
        self.a_marker = a_marker
50
        self.b_marker = b_marker
51
        self.split_marker = split_marker
52
1551.6.14 by Aaron Bentley
Tweaks from merge review
53
    def _merge_struct(self):
54
        """Return structured merge info.  Must be implemented by subclasses.
55
        See TextMerge docstring for details on the format.
56
        """
57
        raise NotImplementedError('_merge_struct is abstract')
58
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
59
    def struct_to_lines(self, struct_iter):
1551.6.8 by Aaron Bentley
Implemented reprocess for weave
60
        """Convert merge result tuples to lines"""
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
61
        for lines in struct_iter:
62
            if len(lines) == 1:
63
                for line in lines[0]:
64
                    yield line
65
            else:
66
                yield self.a_marker
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
67
                for line in lines[0]:
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
68
                    yield line
69
                yield self.split_marker
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
70
                for line in lines[1]:
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
71
                    yield line
72
                yield self.b_marker
73
74
    def iter_useful(self, struct_iter):
1551.6.8 by Aaron Bentley
Implemented reprocess for weave
75
        """Iterate through input tuples, skipping empty ones."""
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
76
        for group in struct_iter:
77
            if len(group[0]) > 0:
78
                yield group
79
            elif len(group) > 1 and len(group[1]) > 0:
80
                yield group
81
1551.6.8 by Aaron Bentley
Implemented reprocess for weave
82
    def merge_lines(self, reprocess=False):
1551.6.14 by Aaron Bentley
Tweaks from merge review
83
        """Produce an iterable of lines, suitable for writing to a file
1551.6.13 by Aaron Bentley
Cleanup
84
        Returns a tuple of (line iterable, conflict indicator)
85
        If reprocess is True, a two-way merge will be performed on the
86
        intermediate structure, to reduce conflict regions.
87
        """
1551.6.11 by Aaron Bentley
Switched TextMerge_lines to work on a list
88
        struct = []
1551.6.12 by Aaron Bentley
Indicate conflicts from merge_lines, insead of guessing
89
        conflicts = False
1551.6.11 by Aaron Bentley
Switched TextMerge_lines to work on a list
90
        for group in self.merge_struct(reprocess):
91
            struct.append(group)
1551.6.12 by Aaron Bentley
Indicate conflicts from merge_lines, insead of guessing
92
            if len(group) > 1:
93
                conflicts = True
94
        return self.struct_to_lines(struct), conflicts
1551.6.8 by Aaron Bentley
Implemented reprocess for weave
95
96
    def merge_struct(self, reprocess=False):
1551.6.13 by Aaron Bentley
Cleanup
97
        """Produce structured merge info"""
1551.6.8 by Aaron Bentley
Implemented reprocess for weave
98
        struct_iter = self.iter_useful(self._merge_struct())
99
        if reprocess is True:
100
            return self.reprocess_struct(struct_iter)
101
        else:
102
            return struct_iter
103
104
    @staticmethod
105
    def reprocess_struct(struct_iter):
1551.6.14 by Aaron Bentley
Tweaks from merge review
106
        """ Perform a two-way merge on structural merge info.
1551.6.13 by Aaron Bentley
Cleanup
107
        This reduces the size of conflict regions, but breaks the connection
1551.6.14 by Aaron Bentley
Tweaks from merge review
108
        between the BASE text and the conflict region.
1551.6.13 by Aaron Bentley
Cleanup
109
110
        This process may split a single conflict region into several smaller
111
        ones, but will not introduce new conflicts.
112
        """
1551.6.8 by Aaron Bentley
Implemented reprocess for weave
113
        for group in struct_iter:
114
            if len(group) == 1:
115
                yield group
116
            else:
117
                for newgroup in Merge2(group[0], group[1]).merge_struct():
118
                    yield newgroup
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
119
120
121
class Merge2(TextMerge):
1551.6.14 by Aaron Bentley
Tweaks from merge review
122
    """ Two-way merge.
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
123
    In a two way merge, common regions are shown as unconflicting, and uncommon
124
    regions produce conflicts.
125
    """
1551.6.13 by Aaron Bentley
Cleanup
126
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
127
    def __init__(self, lines_a, lines_b, a_marker=TextMerge.A_MARKER,
128
                 b_marker=TextMerge.B_MARKER,
1551.6.14 by Aaron Bentley
Tweaks from merge review
129
                 split_marker=TextMerge.SPLIT_MARKER):
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
130
        TextMerge.__init__(self, a_marker, b_marker, split_marker)
131
        self.lines_a = lines_a
132
        self.lines_b = lines_b
133
134
    def _merge_struct(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
135
        """Return structured merge info.
1551.6.13 by Aaron Bentley
Cleanup
136
        See TextMerge docstring.
137
        """
5279.1.1 by Andrew Bennetts
lazy_import most things in merge.py; add a few representative modules to the import tariff tests; tweak a couple of other modules so that patiencediff is not necessarily imported; remove a bunch of unused imports from test_knit.py.
138
        sm = patiencediff.PatienceSequenceMatcher(
139
            None, self.lines_a, self.lines_b)
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
140
        pos_a = 0
141
        pos_b = 0
142
        for ai, bi, l in sm.get_matching_blocks():
143
            # non-matching lines
144
            yield(self.lines_a[pos_a:ai], self.lines_b[pos_b:bi])
145
            # matching lines
146
            yield(self.lines_a[ai:ai+l],)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
147
            pos_a = ai + l
1551.6.7 by Aaron Bentley
Implemented two-way merge, refactored weave merge
148
            pos_b = bi + l
149
        # final non-matching lines
150
        yield(self.lines_a[pos_a:-1], self.lines_b[pos_b:-1])