~bzr-pqm/bzr/bzr.dev

2052.3.2 by John Arbash Meinel
Change Copyright .. by Canonical to Copyright ... Canonical
1
# Copyright (C) 2004, 2005 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
821 by Martin Pool
- start code for built-in diff3-style resolve
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
821 by Martin Pool
- start code for built-in diff3-style resolve
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
821 by Martin Pool
- start code for built-in diff3-style resolve
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
823 by Martin Pool
quote
18
# mbp: "you know that thing where cvs gives you conflict markers?"
19
# s: "i hate that."
20
21
1185.24.1 by Aaron Bentley
Got reprocessing working
22
from bzrlib.errors import CantReprocessAndShowBase
1711.2.23 by John Arbash Meinel
Late bind to PatienceSequenceMatcher in merge3.py
23
import bzrlib.patiencediff
1558.15.11 by Aaron Bentley
Apply merge review suggestions
24
from bzrlib.textfile import check_text_lines
821 by Martin Pool
- start code for built-in diff3-style resolve
25
1711.2.11 by John Arbash Meinel
Rename patiencediff.SequenceMatcher => PatienceSequenceMatcher and knit.SequenceMatcher => KnitSequenceMatcher
26
821 by Martin Pool
- start code for built-in diff3-style resolve
27
def intersect(ra, rb):
28
    """Given two ranges return the range where they intersect or None.
29
30
    >>> intersect((0, 10), (0, 6))
31
    (0, 6)
32
    >>> intersect((0, 10), (5, 15))
33
    (5, 10)
34
    >>> intersect((0, 10), (10, 15))
35
    >>> intersect((0, 9), (10, 15))
36
    >>> intersect((0, 9), (7, 15))
37
    (7, 9)
38
    """
3376.2.9 by Martin Pool
Restore some assertions as comments
39
    # preconditions: (ra[0] <= ra[1]) and (rb[0] <= rb[1])
40
    
821 by Martin Pool
- start code for built-in diff3-style resolve
41
    sa = max(ra[0], rb[0])
42
    sb = min(ra[1], rb[1])
43
    if sa < sb:
44
        return sa, sb
45
    else:
46
        return None
47
48
839 by Martin Pool
- avoid copying string lists when handling unmatched regions
49
def compare_range(a, astart, aend, b, bstart, bend):
50
    """Compare a[astart:aend] == b[bstart:bend], without slicing.
51
    """
52
    if (aend-astart) != (bend-bstart):
53
        return False
54
    for ia, ib in zip(xrange(astart, aend), xrange(bstart, bend)):
55
        if a[ia] != b[ib]:
56
            return False
57
    else:
58
        return True
59
        
60
61
822 by Martin Pool
- Renamed merge3 test suite for easier access.
62
821 by Martin Pool
- start code for built-in diff3-style resolve
63
class Merge3(object):
64
    """3-way merge of texts.
65
66
    Given BASE, OTHER, THIS, tries to produce a combined text
67
    incorporating the changes from both BASE->OTHER and BASE->THIS.
68
    All three will typically be sequences of lines."""
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
69
    def __init__(self, base, a, b, is_cherrypick=False):
1558.15.4 by Aaron Bentley
Fixed binary handling in Merge3
70
        check_text_lines(base)
71
        check_text_lines(a)
72
        check_text_lines(b)
821 by Martin Pool
- start code for built-in diff3-style resolve
73
        self.base = base
74
        self.a = a
75
        self.b = b
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
76
        self.is_cherrypick = is_cherrypick
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
77
828 by Martin Pool
- code to represent merges in regular text conflict form
78
    def merge_lines(self,
829 by Martin Pool
- More merge3 cvs-form stuff
79
                    name_a=None,
80
                    name_b=None,
1185.18.1 by Aaron Bentley
Added --show-base to merge
81
                    name_base=None,
1148 by Martin Pool
- change conflict markers to suit smerge, etc
82
                    start_marker='<<<<<<<',
83
                    mid_marker='=======',
84
                    end_marker='>>>>>>>',
1185.24.1 by Aaron Bentley
Got reprocessing working
85
                    base_marker=None,
86
                    reprocess=False):
828 by Martin Pool
- code to represent merges in regular text conflict form
87
        """Return merge in cvs-like form.
88
        """
1551.10.38 by Aaron Bentley
merge3 auto-detects line endings for conflict markers
89
        newline = '\n'
90
        if len(self.a) > 0:
91
            if self.a[0].endswith('\r\n'):
92
                newline = '\r\n'
93
            elif self.a[0].endswith('\r'):
94
                newline = '\r'
1185.24.1 by Aaron Bentley
Got reprocessing working
95
        if base_marker and reprocess:
96
            raise CantReprocessAndShowBase()
829 by Martin Pool
- More merge3 cvs-form stuff
97
        if name_a:
98
            start_marker = start_marker + ' ' + name_a
99
        if name_b:
100
            end_marker = end_marker + ' ' + name_b
1185.18.1 by Aaron Bentley
Added --show-base to merge
101
        if name_base and base_marker:
102
            base_marker = base_marker + ' ' + name_base
1185.24.1 by Aaron Bentley
Got reprocessing working
103
        merge_regions = self.merge_regions()
104
        if reprocess is True:
105
            merge_regions = self.reprocess_merge_regions(merge_regions)
106
        for t in merge_regions:
828 by Martin Pool
- code to represent merges in regular text conflict form
107
            what = t[0]
108
            if what == 'unchanged':
109
                for i in range(t[1], t[2]):
110
                    yield self.base[i]
830 by Martin Pool
- handle chunks which differ from the base but agree
111
            elif what == 'a' or what == 'same':
828 by Martin Pool
- code to represent merges in regular text conflict form
112
                for i in range(t[1], t[2]):
113
                    yield self.a[i]
114
            elif what == 'b':
115
                for i in range(t[1], t[2]):
116
                    yield self.b[i]
117
            elif what == 'conflict':
1551.10.38 by Aaron Bentley
merge3 auto-detects line endings for conflict markers
118
                yield start_marker + newline
828 by Martin Pool
- code to represent merges in regular text conflict form
119
                for i in range(t[3], t[4]):
120
                    yield self.a[i]
1185.18.1 by Aaron Bentley
Added --show-base to merge
121
                if base_marker is not None:
1551.10.38 by Aaron Bentley
merge3 auto-detects line endings for conflict markers
122
                    yield base_marker + newline
1185.18.1 by Aaron Bentley
Added --show-base to merge
123
                    for i in range(t[1], t[2]):
124
                        yield self.base[i]
1551.10.38 by Aaron Bentley
merge3 auto-detects line endings for conflict markers
125
                yield mid_marker + newline
828 by Martin Pool
- code to represent merges in regular text conflict form
126
                for i in range(t[5], t[6]):
127
                    yield self.b[i]
1551.10.38 by Aaron Bentley
merge3 auto-detects line endings for conflict markers
128
                yield end_marker + newline
828 by Martin Pool
- code to represent merges in regular text conflict form
129
            else:
130
                raise ValueError(what)
131
832 by Martin Pool
- New Merge3.merge_annotated method for debugging.
132
    def merge_annotated(self):
133
        """Return merge with conflicts, showing origin of lines.
134
135
        Most useful for debugging merge.        
136
        """
137
        for t in self.merge_regions():
138
            what = t[0]
139
            if what == 'unchanged':
140
                for i in range(t[1], t[2]):
141
                    yield 'u | ' + self.base[i]
142
            elif what == 'a' or what == 'same':
143
                for i in range(t[1], t[2]):
144
                    yield what[0] + ' | ' + self.a[i]
145
            elif what == 'b':
146
                for i in range(t[1], t[2]):
147
                    yield 'b | ' + self.b[i]
148
            elif what == 'conflict':
149
                yield '<<<<\n'
150
                for i in range(t[3], t[4]):
151
                    yield 'A | ' + self.a[i]
152
                yield '----\n'
153
                for i in range(t[5], t[6]):
154
                    yield 'B | ' + self.b[i]
155
                yield '>>>>\n'
156
            else:
157
                raise ValueError(what)
158
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
159
    def merge_groups(self):
160
        """Yield sequence of line groups.  Each one is a tuple:
161
162
        'unchanged', lines
163
             Lines unchanged from base
164
165
        'a', lines
166
             Lines taken from a
167
830 by Martin Pool
- handle chunks which differ from the base but agree
168
        'same', lines
169
             Lines taken from a (and equal to b)
170
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
171
        'b', lines
172
             Lines taken from b
173
174
        'conflict', base_lines, a_lines, b_lines
175
             Lines from base were changed to either a or b and conflict.
176
        """
177
        for t in self.merge_regions():
178
            what = t[0]
179
            if what == 'unchanged':
180
                yield what, self.base[t[1]:t[2]]
830 by Martin Pool
- handle chunks which differ from the base but agree
181
            elif what == 'a' or what == 'same':
827 by Martin Pool
- new Merge3.merge_groups feeds back the merged lines
182
                yield what, self.a[t[1]:t[2]]
183
            elif what == 'b':
184
                yield what, self.b[t[1]:t[2]]
185
            elif what == 'conflict':
186
                yield (what,
187
                       self.base[t[1]:t[2]],
188
                       self.a[t[3]:t[4]],
189
                       self.b[t[5]:t[6]])
190
            else:
191
                raise ValueError(what)
192
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
193
    def merge_regions(self):
822 by Martin Pool
- Renamed merge3 test suite for easier access.
194
        """Return sequences of matching and conflicting regions.
195
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
196
        This returns tuples, where the first value says what kind we
197
        have:
198
199
        'unchanged', start, end
200
             Take a region of base[start:end]
201
830 by Martin Pool
- handle chunks which differ from the base but agree
202
        'same', astart, aend
203
             b and a are different from base but give the same result
204
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
205
        'a', start, end
206
             Non-clashing insertion from a[start:end]
207
822 by Martin Pool
- Renamed merge3 test suite for easier access.
208
        Method is as follows:
209
210
        The two sequences align only on regions which match the base
211
        and both descendents.  These are found by doing a two-way diff
212
        of each one against the base, and then finding the
213
        intersections between those regions.  These "sync regions"
214
        are by definition unchanged in both and easily dealt with.
215
216
        The regions in between can be in any of three cases:
217
        conflicted, or changed on only one side.
218
        """
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
219
220
        # section a[0:ia] has been disposed of, etc
221
        iz = ia = ib = 0
222
        
223
        for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions():
224
            matchlen = zend - zmatch
3376.2.9 by Martin Pool
Restore some assertions as comments
225
            # invariants:
226
            #   matchlen >= 0
227
            #   matchlen == (aend - amatch)
228
            #   matchlen == (bend - bmatch)
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
229
            len_a = amatch - ia
230
            len_b = bmatch - ib
231
            len_base = zmatch - iz
3376.2.9 by Martin Pool
Restore some assertions as comments
232
            # invariants:
233
            # assert len_a >= 0
234
            # assert len_b >= 0
235
            # assert len_base >= 0
236
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
237
            #print 'unmatched a=%d, b=%d' % (len_a, len_b)
238
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
239
            if len_a or len_b:
839 by Martin Pool
- avoid copying string lists when handling unmatched regions
240
                # try to avoid actually slicing the lists
241
                same = compare_range(self.a, ia, amatch,
242
                                     self.b, ib, bmatch)
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
243
830 by Martin Pool
- handle chunks which differ from the base but agree
244
                if same:
245
                    yield 'same', ia, amatch
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
246
                else:
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
247
                    equal_a = compare_range(self.a, ia, amatch,
248
                                            self.base, iz, zmatch)
249
                    equal_b = compare_range(self.b, ib, bmatch,
250
                                            self.base, iz, zmatch)
251
                    if equal_a and not equal_b:
252
                        yield 'b', ib, bmatch
253
                    elif equal_b and not equal_a:
254
                        yield 'a', ia, amatch
255
                    elif not equal_a and not equal_b:
256
                        if self.is_cherrypick:
257
                            for node in self._refine_cherrypick_conflict(
258
                                                    iz, zmatch, ia, amatch,
259
                                                    ib, bmatch):
260
                                yield node
261
                        else:
262
                            yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch
263
                    else:
264
                        raise AssertionError("can't handle a=b=base but unmatched")
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
265
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
266
                ia = amatch
826 by Martin Pool
- Actually merge unsynchronized regions. Woot!
267
                ib = bmatch
268
            iz = zmatch
269
270
            # if the same part of the base was deleted on both sides
271
            # that's OK, we can just skip it.
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
272
273
            if matchlen > 0:
3376.2.9 by Martin Pool
Restore some assertions as comments
274
                # invariants:
275
                # assert ia == amatch
276
                # assert ib == bmatch
277
                # assert iz == zmatch
278
                
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
279
                yield 'unchanged', zmatch, zend
280
                iz = zend
281
                ia = aend
282
                ib = bend
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
283
284
    def _refine_cherrypick_conflict(self, zstart, zend, astart, aend, bstart, bend):
285
        """When cherrypicking b => a, ignore matches with b and base."""
286
        # Do not emit regions which match, only regions which do not match
287
        matches = bzrlib.patiencediff.PatienceSequenceMatcher(None,
288
            self.base[zstart:zend], self.b[bstart:bend]).get_matching_blocks()
3249.3.2 by John Arbash Meinel
review feedback from Robert
289
        last_base_idx = 0
290
        last_b_idx = 0
291
        last_b_idx = 0
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
292
        yielded_a = False
3249.3.2 by John Arbash Meinel
review feedback from Robert
293
        for base_idx, b_idx, match_len in matches:
294
            conflict_z_len = base_idx - last_base_idx
295
            conflict_b_len = b_idx - last_b_idx
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
296
            if conflict_b_len == 0: # There are no lines in b which conflict,
297
                                    # so skip it
298
                pass
299
            else:
300
                if yielded_a:
3249.3.2 by John Arbash Meinel
review feedback from Robert
301
                    yield ('conflict',
302
                           zstart + last_base_idx, zstart + base_idx,
303
                           aend, aend, bstart + last_b_idx, bstart + b_idx)
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
304
                else:
305
                    # The first conflict gets the a-range
306
                    yielded_a = True
3249.3.2 by John Arbash Meinel
review feedback from Robert
307
                    yield ('conflict', zstart + last_base_idx, zstart +
308
                    base_idx,
309
                           astart, aend, bstart + last_b_idx, bstart + b_idx)
310
            last_base_idx = base_idx + match_len
311
            last_b_idx = b_idx + match_len
312
        if last_base_idx != zend - zstart or last_b_idx != bend - bstart:
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
313
            if yielded_a:
3249.3.2 by John Arbash Meinel
review feedback from Robert
314
                yield ('conflict', zstart + last_base_idx, zstart + base_idx,
315
                       aend, aend, bstart + last_b_idx, bstart + b_idx)
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
316
            else:
317
                # The first conflict gets the a-range
318
                yielded_a = True
3249.3.2 by John Arbash Meinel
review feedback from Robert
319
                yield ('conflict', zstart + last_base_idx, zstart + base_idx,
320
                       astart, aend, bstart + last_b_idx, bstart + b_idx)
3249.3.1 by John Arbash Meinel
Implement cherrypick support for Merge3
321
        if not yielded_a:
322
            yield ('conflict', zstart, zend, astart, aend, bstart, bend)
1185.24.1 by Aaron Bentley
Got reprocessing working
323
324
    def reprocess_merge_regions(self, merge_regions):
1185.33.62 by Martin Pool
doc
325
        """Where there are conflict regions, remove the agreed lines.
326
327
        Lines where both A and B have made the same changes are 
328
        eliminated.
329
        """
1185.24.1 by Aaron Bentley
Got reprocessing working
330
        for region in merge_regions:
331
            if region[0] != "conflict":
332
                yield region
333
                continue
334
            type, iz, zmatch, ia, amatch, ib, bmatch = region
335
            a_region = self.a[ia:amatch]
336
            b_region = self.b[ib:bmatch]
1711.2.23 by John Arbash Meinel
Late bind to PatienceSequenceMatcher in merge3.py
337
            matches = bzrlib.patiencediff.PatienceSequenceMatcher(
338
                    None, a_region, b_region).get_matching_blocks()
1185.24.1 by Aaron Bentley
Got reprocessing working
339
            next_a = ia
340
            next_b = ib
341
            for region_ia, region_ib, region_len in matches[:-1]:
342
                region_ia += ia
343
                region_ib += ib
344
                reg = self.mismatch_region(next_a, region_ia, next_b,
345
                                           region_ib)
346
                if reg is not None:
347
                    yield reg
348
                yield 'same', region_ia, region_len+region_ia
349
                next_a = region_ia + region_len
350
                next_b = region_ib + region_len
351
            reg = self.mismatch_region(next_a, amatch, next_b, bmatch)
352
            if reg is not None:
353
                yield reg
354
355
    @staticmethod
356
    def mismatch_region(next_a, region_ia,  next_b, region_ib):
357
        if next_a < region_ia or next_b < region_ib:
358
            return 'conflict', None, None, next_a, region_ia, next_b, region_ib
359
822 by Martin Pool
- Renamed merge3 test suite for easier access.
360
    def find_sync_regions(self):
361
        """Return a list of sync regions, where both descendents match the base.
362
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
363
        Generates a list of (base1, base2, a1, a2, b1, b2).  There is
364
        always a zero-length sync region at the end of all the files.
821 by Martin Pool
- start code for built-in diff3-style resolve
365
        """
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
366
367
        ia = ib = 0
1711.2.23 by John Arbash Meinel
Late bind to PatienceSequenceMatcher in merge3.py
368
        amatches = bzrlib.patiencediff.PatienceSequenceMatcher(
369
                None, self.base, self.a).get_matching_blocks()
370
        bmatches = bzrlib.patiencediff.PatienceSequenceMatcher(
371
                None, self.base, self.b).get_matching_blocks()
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
372
        len_a = len(amatches)
373
        len_b = len(bmatches)
374
375
        sl = []
376
377
        while ia < len_a and ib < len_b:
378
            abase, amatch, alen = amatches[ia]
379
            bbase, bmatch, blen = bmatches[ib]
380
822 by Martin Pool
- Renamed merge3 test suite for easier access.
381
            # there is an unconflicted block at i; how long does it
382
            # extend?  until whichever one ends earlier.
383
            i = intersect((abase, abase+alen), (bbase, bbase+blen))
384
            if i:
385
                intbase = i[0]
386
                intend = i[1]
387
                intlen = intend - intbase
3376.2.9 by Martin Pool
Restore some assertions as comments
388
389
                # found a match of base[i[0], i[1]]; this may be less than
390
                # the region that matches in either one
391
                # assert intlen <= alen
392
                # assert intlen <= blen
393
                # assert abase <= intbase
394
                # assert bbase <= intbase
395
822 by Martin Pool
- Renamed merge3 test suite for easier access.
396
                asub = amatch + (intbase - abase)
397
                bsub = bmatch + (intbase - bbase)
398
                aend = asub + intlen
399
                bend = bsub + intlen
3376.2.9 by Martin Pool
Restore some assertions as comments
400
401
                # assert self.base[intbase:intend] == self.a[asub:aend], \
402
                #       (self.base[intbase:intend], self.a[asub:aend])
403
                # assert self.base[intbase:intend] == self.b[bsub:bend]
404
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
405
                sl.append((intbase, intend,
406
                           asub, aend,
407
                           bsub, bend))
822 by Martin Pool
- Renamed merge3 test suite for easier access.
408
            # advance whichever one ends first in the base text
409
            if (abase + alen) < (bbase + blen):
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
410
                ia += 1
822 by Martin Pool
- Renamed merge3 test suite for easier access.
411
            else:
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
412
                ib += 1
413
            
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
414
        intbase = len(self.base)
415
        abase = len(self.a)
416
        bbase = len(self.b)
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
417
        sl.append((intbase, intbase, abase, abase, bbase, bbase))
418
419
        return sl
825 by Martin Pool
- Merge3.find_sync_regions always returns a zero-length sentinal at the end to
420
821 by Martin Pool
- start code for built-in diff3-style resolve
421
    def find_unconflicted(self):
422
        """Return a list of ranges in base that are not conflicted."""
1711.2.23 by John Arbash Meinel
Late bind to PatienceSequenceMatcher in merge3.py
423
        am = bzrlib.patiencediff.PatienceSequenceMatcher(
424
                None, self.base, self.a).get_matching_blocks()
425
        bm = bzrlib.patiencediff.PatienceSequenceMatcher(
426
                None, self.base, self.b).get_matching_blocks()
821 by Martin Pool
- start code for built-in diff3-style resolve
427
428
        unc = []
429
430
        while am and bm:
431
            # there is an unconflicted block at i; how long does it
432
            # extend?  until whichever one ends earlier.
433
            a1 = am[0][0]
434
            a2 = a1 + am[0][2]
435
            b1 = bm[0][0]
436
            b2 = b1 + bm[0][2]
437
            i = intersect((a1, a2), (b1, b2))
438
            if i:
439
                unc.append(i)
440
441
            if a2 < b2:
442
                del am[0]
443
            else:
444
                del bm[0]
445
                
446
        return unc
829 by Martin Pool
- More merge3 cvs-form stuff
447
448
449
def main(argv):
830 by Martin Pool
- handle chunks which differ from the base but agree
450
    # as for diff3 and meld the syntax is "MINE BASE OTHER"
451
    a = file(argv[1], 'rt').readlines()
452
    base = file(argv[2], 'rt').readlines()
829 by Martin Pool
- More merge3 cvs-form stuff
453
    b = file(argv[3], 'rt').readlines()
454
455
    m3 = Merge3(base, a, b)
456
838 by Martin Pool
- Merge3.find_sync_regions() - avoid problems with iters on python2.3 by
457
    #for sr in m3.find_sync_regions():
458
    #    print sr
459
832 by Martin Pool
- New Merge3.merge_annotated method for debugging.
460
    # sys.stdout.writelines(m3.merge_lines(name_a=argv[1], name_b=argv[3]))
461
    sys.stdout.writelines(m3.merge_annotated())
829 by Martin Pool
- More merge3 cvs-form stuff
462
463
464
if __name__ == '__main__':
465
    import sys
466
    sys.exit(main(sys.argv))