~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/merge3.py

  • Committer: Martin Pool
  • Date: 2005-09-06 02:26:28 UTC
  • Revision ID: mbp@sourcefrog.net-20050906022628-66d65f0feb4a9e80
- implement version 5 xml storage, and tests

  This stores files identified by the version that introduced the 
  text, and the version that introduced the name.  Entry kinds are
  given by the xml tag not an explicit kind field.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
# s: "i hate that."
20
20
 
21
21
 
22
 
from difflib import SequenceMatcher
23
 
 
24
 
from bzrlib.errors import CantReprocessAndShowBase
25
 
from bzrlib.textfile import check_text_lines
26
22
 
27
23
def intersect(ra, rb):
28
24
    """Given two ranges return the range where they intersect or None.
68
64
    incorporating the changes from both BASE->OTHER and BASE->THIS.
69
65
    All three will typically be sequences of lines."""
70
66
    def __init__(self, base, a, b):
71
 
        check_text_lines(base)
72
 
        check_text_lines(a)
73
 
        check_text_lines(b)
74
67
        self.base = base
75
68
        self.a = a
76
69
        self.b = b
 
70
        from difflib import SequenceMatcher
 
71
        self.a_ops = SequenceMatcher(None, base, a).get_opcodes()
 
72
        self.b_ops = SequenceMatcher(None, base, b).get_opcodes()
77
73
 
78
74
 
79
75
 
80
76
    def merge_lines(self,
81
77
                    name_a=None,
82
78
                    name_b=None,
83
 
                    name_base=None,
84
79
                    start_marker='<<<<<<<',
85
80
                    mid_marker='=======',
86
81
                    end_marker='>>>>>>>',
87
 
                    base_marker=None,
88
 
                    reprocess=False):
 
82
                    show_base=False):
89
83
        """Return merge in cvs-like form.
90
84
        """
91
 
        if base_marker and reprocess:
92
 
            raise CantReprocessAndShowBase()
93
85
        if name_a:
94
86
            start_marker = start_marker + ' ' + name_a
95
87
        if name_b:
96
88
            end_marker = end_marker + ' ' + name_b
97
 
        if name_base and base_marker:
98
 
            base_marker = base_marker + ' ' + name_base
99
 
        merge_regions = self.merge_regions()
100
 
        if reprocess is True:
101
 
            merge_regions = self.reprocess_merge_regions(merge_regions)
102
 
        for t in merge_regions:
 
89
            
 
90
        for t in self.merge_regions():
103
91
            what = t[0]
104
92
            if what == 'unchanged':
105
93
                for i in range(t[1], t[2]):
114
102
                yield start_marker + '\n'
115
103
                for i in range(t[3], t[4]):
116
104
                    yield self.a[i]
117
 
                if base_marker is not None:
118
 
                    yield base_marker + '\n'
119
 
                    for i in range(t[1], t[2]):
120
 
                        yield self.base[i]
121
105
                yield mid_marker + '\n'
122
106
                for i in range(t[5], t[6]):
123
107
                    yield self.b[i]
279
263
                iz = zend
280
264
                ia = aend
281
265
                ib = bend
282
 
    
283
 
 
284
 
    def reprocess_merge_regions(self, merge_regions):
285
 
        """Where there are conflict regions, remove the agreed lines.
286
 
 
287
 
        Lines where both A and B have made the same changes are 
288
 
        eliminated.
289
 
        """
290
 
        for region in merge_regions:
291
 
            if region[0] != "conflict":
292
 
                yield region
293
 
                continue
294
 
            type, iz, zmatch, ia, amatch, ib, bmatch = region
295
 
            a_region = self.a[ia:amatch]
296
 
            b_region = self.b[ib:bmatch]
297
 
            matches = SequenceMatcher(None, a_region, 
298
 
                                      b_region).get_matching_blocks()
299
 
            next_a = ia
300
 
            next_b = ib
301
 
            for region_ia, region_ib, region_len in matches[:-1]:
302
 
                region_ia += ia
303
 
                region_ib += ib
304
 
                reg = self.mismatch_region(next_a, region_ia, next_b,
305
 
                                           region_ib)
306
 
                if reg is not None:
307
 
                    yield reg
308
 
                yield 'same', region_ia, region_len+region_ia
309
 
                next_a = region_ia + region_len
310
 
                next_b = region_ib + region_len
311
 
            reg = self.mismatch_region(next_a, amatch, next_b, bmatch)
312
 
            if reg is not None:
313
 
                yield reg
314
 
 
315
 
 
316
 
    @staticmethod
317
 
    def mismatch_region(next_a, region_ia,  next_b, region_ib):
318
 
        if next_a < region_ia or next_b < region_ib:
319
 
            return 'conflict', None, None, next_a, region_ia, next_b, region_ib
320
 
            
321
 
 
 
266
        
 
267
 
 
268
        
322
269
    def find_sync_regions(self):
323
270
        """Return a list of sync regions, where both descendents match the base.
324
271
 
325
272
        Generates a list of (base1, base2, a1, a2, b1, b2).  There is
326
273
        always a zero-length sync region at the end of all the files.
327
274
        """
 
275
        from difflib import SequenceMatcher
328
276
 
329
277
        ia = ib = 0
330
278
        amatches = SequenceMatcher(None, self.base, self.a).get_matching_blocks()
384
332
 
385
333
    def find_unconflicted(self):
386
334
        """Return a list of ranges in base that are not conflicted."""
 
335
        from difflib import SequenceMatcher
387
336
 
388
337
        import re
389
338