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

  • Committer: Jelmer Vernooij
  • Date: 2018-11-23 01:35:56 UTC
  • mto: (7211.10.3 git-empty-dirs)
  • mto: This revision was merged to the branch mainline in revision 7215.
  • Revision ID: jelmer@jelmer.uk-20181123013556-mu7ct9ovl7fozjc2
Update comment about ssl.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006, 2009, 2010 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
#
 
17
# Author: Martin Pool <mbp@canonical.com>
 
18
#         Aaron Bentley <aaron.bentley@utoronto.ca>
 
19
 
 
20
from __future__ import absolute_import
 
21
 
 
22
from .lazy_import import lazy_import
 
23
lazy_import(globals(), """
 
24
from breezy import patiencediff
 
25
""")
 
26
 
 
27
 
 
28
class TextMerge(object):
 
29
    """Base class for text-mergers
 
30
    Subclasses must implement _merge_struct.
 
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.
 
36
 
 
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.
 
41
    """
 
42
    # TODO: Show some version information (e.g. author, date) on conflicted
 
43
    # regions.
 
44
    A_MARKER = b'<<<<<<< \n'
 
45
    B_MARKER = b'>>>>>>> \n'
 
46
    SPLIT_MARKER = b'=======\n'
 
47
 
 
48
    def __init__(self, a_marker=A_MARKER, b_marker=B_MARKER,
 
49
                 split_marker=SPLIT_MARKER):
 
50
        self.a_marker = a_marker
 
51
        self.b_marker = b_marker
 
52
        self.split_marker = split_marker
 
53
 
 
54
    def _merge_struct(self):
 
55
        """Return structured merge info.  Must be implemented by subclasses.
 
56
        See TextMerge docstring for details on the format.
 
57
        """
 
58
        raise NotImplementedError('_merge_struct is abstract')
 
59
 
 
60
    def struct_to_lines(self, struct_iter):
 
61
        """Convert merge result tuples to lines"""
 
62
        for lines in struct_iter:
 
63
            if len(lines) == 1:
 
64
                for line in lines[0]:
 
65
                    yield line
 
66
            else:
 
67
                yield self.a_marker
 
68
                for line in lines[0]:
 
69
                    yield line
 
70
                yield self.split_marker
 
71
                for line in lines[1]:
 
72
                    yield line
 
73
                yield self.b_marker
 
74
 
 
75
    def iter_useful(self, struct_iter):
 
76
        """Iterate through input tuples, skipping empty ones."""
 
77
        for group in struct_iter:
 
78
            if len(group[0]) > 0:
 
79
                yield group
 
80
            elif len(group) > 1 and len(group[1]) > 0:
 
81
                yield group
 
82
 
 
83
    def merge_lines(self, reprocess=False):
 
84
        """Produce an iterable of lines, suitable for writing to a file
 
85
        Returns a tuple of (line iterable, conflict indicator)
 
86
        If reprocess is True, a two-way merge will be performed on the
 
87
        intermediate structure, to reduce conflict regions.
 
88
        """
 
89
        struct = []
 
90
        conflicts = False
 
91
        for group in self.merge_struct(reprocess):
 
92
            struct.append(group)
 
93
            if len(group) > 1:
 
94
                conflicts = True
 
95
        return self.struct_to_lines(struct), conflicts
 
96
 
 
97
    def merge_struct(self, reprocess=False):
 
98
        """Produce structured merge info"""
 
99
        struct_iter = self.iter_useful(self._merge_struct())
 
100
        if reprocess is True:
 
101
            return self.reprocess_struct(struct_iter)
 
102
        else:
 
103
            return struct_iter
 
104
 
 
105
    @staticmethod
 
106
    def reprocess_struct(struct_iter):
 
107
        """ Perform a two-way merge on structural merge info.
 
108
        This reduces the size of conflict regions, but breaks the connection
 
109
        between the BASE text and the conflict region.
 
110
 
 
111
        This process may split a single conflict region into several smaller
 
112
        ones, but will not introduce new conflicts.
 
113
        """
 
114
        for group in struct_iter:
 
115
            if len(group) == 1:
 
116
                yield group
 
117
            else:
 
118
                for newgroup in Merge2(group[0], group[1]).merge_struct():
 
119
                    yield newgroup
 
120
 
 
121
 
 
122
class Merge2(TextMerge):
 
123
    """ Two-way merge.
 
124
    In a two way merge, common regions are shown as unconflicting, and uncommon
 
125
    regions produce conflicts.
 
126
    """
 
127
 
 
128
    def __init__(self, lines_a, lines_b, a_marker=TextMerge.A_MARKER,
 
129
                 b_marker=TextMerge.B_MARKER,
 
130
                 split_marker=TextMerge.SPLIT_MARKER):
 
131
        TextMerge.__init__(self, a_marker, b_marker, split_marker)
 
132
        self.lines_a = lines_a
 
133
        self.lines_b = lines_b
 
134
 
 
135
    def _merge_struct(self):
 
136
        """Return structured merge info.
 
137
        See TextMerge docstring.
 
138
        """
 
139
        sm = patiencediff.PatienceSequenceMatcher(
 
140
            None, self.lines_a, self.lines_b)
 
141
        pos_a = 0
 
142
        pos_b = 0
 
143
        for ai, bi, l in sm.get_matching_blocks():
 
144
            # non-matching lines
 
145
            yield(self.lines_a[pos_a:ai], self.lines_b[pos_b:bi])
 
146
            # matching lines
 
147
            yield(self.lines_a[ai:ai + l],)
 
148
            pos_a = ai + l
 
149
            pos_b = bi + l
 
150
        # final non-matching lines
 
151
        yield(self.lines_a[pos_a:-1], self.lines_b[pos_b:-1])