/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:
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
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
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
#
 
17
# Author: Martin Pool <mbp@canonical.com> 
 
18
#         Aaron Bentley <aaron.bentley@utoronto.ca>
 
19
 
 
20
from difflib import SequenceMatcher
 
21
 
 
22
 
 
23
class TextMerge(object):
 
24
    """Base class for text-mergers
 
25
    Subclasses must implement _merge_struct.
 
26
    """
 
27
    def __init__(self, a_marker='<<<<<<< \n', b_marker='>>>>>>> \n',
 
28
                 split_marker='=======\n'):
 
29
        self.a_marker = a_marker
 
30
        self.b_marker = b_marker
 
31
        self.split_marker = split_marker
 
32
 
 
33
    def struct_to_lines(self, struct_iter):
 
34
        """Convert merge result tuples to lines"""
 
35
        for lines in struct_iter:
 
36
            if len(lines) == 1:
 
37
                for line in lines[0]:
 
38
                    yield line
 
39
            else:
 
40
                yield self.a_marker
 
41
                for line in lines[0]: 
 
42
                    yield line
 
43
                yield self.split_marker
 
44
                for line in lines[1]: 
 
45
                    yield line
 
46
                yield self.b_marker
 
47
 
 
48
    def iter_useful(self, struct_iter):
 
49
        """Iterate through input tuples, skipping empty ones."""
 
50
        for group in struct_iter:
 
51
            if len(group[0]) > 0:
 
52
                yield group
 
53
            elif len(group) > 1 and len(group[1]) > 0:
 
54
                yield group
 
55
 
 
56
    def merge_lines(self, reprocess=False):
 
57
        return self.struct_to_lines(self.merge_struct(reprocess))
 
58
 
 
59
    def merge_struct(self, reprocess=False):
 
60
        struct_iter = self.iter_useful(self._merge_struct())
 
61
        if reprocess is True:
 
62
            return self.reprocess_struct(struct_iter)
 
63
        else:
 
64
            return struct_iter
 
65
 
 
66
    @staticmethod
 
67
    def reprocess_struct(struct_iter):
 
68
        for group in struct_iter:
 
69
            if len(group) == 1:
 
70
                yield group
 
71
            else:
 
72
                for newgroup in Merge2(group[0], group[1]).merge_struct():
 
73
                    yield newgroup
 
74
 
 
75
 
 
76
class Merge2(TextMerge):
 
77
 
 
78
    """
 
79
    Two-way merge.
 
80
    In a two way merge, common regions are shown as unconflicting, and uncommon
 
81
    regions produce conflicts.
 
82
    """
 
83
    def __init__(self, lines_a, lines_b, a_marker='<<<<<<< \n', 
 
84
                 b_marker='>>>>>>> \n', split_marker='=======\n'):
 
85
        TextMerge.__init__(self, a_marker, b_marker, split_marker)
 
86
        self.lines_a = lines_a
 
87
        self.lines_b = lines_b
 
88
 
 
89
    def _merge_struct(self):
 
90
        sm = SequenceMatcher(None, self.lines_a, self.lines_b)
 
91
        pos_a = 0
 
92
        pos_b = 0
 
93
        for ai, bi, l in sm.get_matching_blocks():
 
94
            # non-matching lines
 
95
            yield(self.lines_a[pos_a:ai], self.lines_b[pos_b:bi])
 
96
            # matching lines
 
97
            yield(self.lines_a[ai:ai+l],)
 
98
            pos_a = ai + l 
 
99
            pos_b = bi + l
 
100
        # final non-matching lines
 
101
        yield(self.lines_a[pos_a:-1], self.lines_b[pos_b:-1])