~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/merge3.py

 * Two new commands 'bzr checkout' and 'bzr update' allow for CVS/SVN-alike
   behaviour. They use the existing serverless-mode and store no data
   locally. As such they are not suitable for use except in high bandwidth
   low latency environments like LAN's or local disk. (Robert Collins)

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