##// END OF EJS Templates
simplemerge: remove hash-bang from non-executable script
Mads Kiilerich -
r12055:81c4e18c stable
parent child Browse files
Show More
@@ -1,451 +1,450 b''
1 #!/usr/bin/env python
2 # Copyright (C) 2004, 2005 Canonical Ltd
1 # Copyright (C) 2004, 2005 Canonical Ltd
3 #
2 #
4 # This program is free software; you can redistribute it and/or modify
3 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
4 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
5 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
6 # (at your option) any later version.
8 #
7 #
9 # This program is distributed in the hope that it will be useful,
8 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
11 # GNU General Public License for more details.
13 #
12 #
14 # You should have received a copy of the GNU General Public License
13 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
14 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
16
18 # mbp: "you know that thing where cvs gives you conflict markers?"
17 # mbp: "you know that thing where cvs gives you conflict markers?"
19 # s: "i hate that."
18 # s: "i hate that."
20
19
21 from i18n import _
20 from i18n import _
22 import util, mdiff
21 import util, mdiff
23 import sys, os
22 import sys, os
24
23
25 class CantReprocessAndShowBase(Exception):
24 class CantReprocessAndShowBase(Exception):
26 pass
25 pass
27
26
28 def intersect(ra, rb):
27 def intersect(ra, rb):
29 """Given two ranges return the range where they intersect or None.
28 """Given two ranges return the range where they intersect or None.
30
29
31 >>> intersect((0, 10), (0, 6))
30 >>> intersect((0, 10), (0, 6))
32 (0, 6)
31 (0, 6)
33 >>> intersect((0, 10), (5, 15))
32 >>> intersect((0, 10), (5, 15))
34 (5, 10)
33 (5, 10)
35 >>> intersect((0, 10), (10, 15))
34 >>> intersect((0, 10), (10, 15))
36 >>> intersect((0, 9), (10, 15))
35 >>> intersect((0, 9), (10, 15))
37 >>> intersect((0, 9), (7, 15))
36 >>> intersect((0, 9), (7, 15))
38 (7, 9)
37 (7, 9)
39 """
38 """
40 assert ra[0] <= ra[1]
39 assert ra[0] <= ra[1]
41 assert rb[0] <= rb[1]
40 assert rb[0] <= rb[1]
42
41
43 sa = max(ra[0], rb[0])
42 sa = max(ra[0], rb[0])
44 sb = min(ra[1], rb[1])
43 sb = min(ra[1], rb[1])
45 if sa < sb:
44 if sa < sb:
46 return sa, sb
45 return sa, sb
47 else:
46 else:
48 return None
47 return None
49
48
50 def compare_range(a, astart, aend, b, bstart, bend):
49 def compare_range(a, astart, aend, b, bstart, bend):
51 """Compare a[astart:aend] == b[bstart:bend], without slicing.
50 """Compare a[astart:aend] == b[bstart:bend], without slicing.
52 """
51 """
53 if (aend - astart) != (bend - bstart):
52 if (aend - astart) != (bend - bstart):
54 return False
53 return False
55 for ia, ib in zip(xrange(astart, aend), xrange(bstart, bend)):
54 for ia, ib in zip(xrange(astart, aend), xrange(bstart, bend)):
56 if a[ia] != b[ib]:
55 if a[ia] != b[ib]:
57 return False
56 return False
58 else:
57 else:
59 return True
58 return True
60
59
61 class Merge3Text(object):
60 class Merge3Text(object):
62 """3-way merge of texts.
61 """3-way merge of texts.
63
62
64 Given strings BASE, OTHER, THIS, tries to produce a combined text
63 Given strings BASE, OTHER, THIS, tries to produce a combined text
65 incorporating the changes from both BASE->OTHER and BASE->THIS."""
64 incorporating the changes from both BASE->OTHER and BASE->THIS."""
66 def __init__(self, basetext, atext, btext, base=None, a=None, b=None):
65 def __init__(self, basetext, atext, btext, base=None, a=None, b=None):
67 self.basetext = basetext
66 self.basetext = basetext
68 self.atext = atext
67 self.atext = atext
69 self.btext = btext
68 self.btext = btext
70 if base is None:
69 if base is None:
71 base = mdiff.splitnewlines(basetext)
70 base = mdiff.splitnewlines(basetext)
72 if a is None:
71 if a is None:
73 a = mdiff.splitnewlines(atext)
72 a = mdiff.splitnewlines(atext)
74 if b is None:
73 if b is None:
75 b = mdiff.splitnewlines(btext)
74 b = mdiff.splitnewlines(btext)
76 self.base = base
75 self.base = base
77 self.a = a
76 self.a = a
78 self.b = b
77 self.b = b
79
78
80 def merge_lines(self,
79 def merge_lines(self,
81 name_a=None,
80 name_a=None,
82 name_b=None,
81 name_b=None,
83 name_base=None,
82 name_base=None,
84 start_marker='<<<<<<<',
83 start_marker='<<<<<<<',
85 mid_marker='=======',
84 mid_marker='=======',
86 end_marker='>>>>>>>',
85 end_marker='>>>>>>>',
87 base_marker=None,
86 base_marker=None,
88 reprocess=False):
87 reprocess=False):
89 """Return merge in cvs-like form.
88 """Return merge in cvs-like form.
90 """
89 """
91 self.conflicts = False
90 self.conflicts = False
92 newline = '\n'
91 newline = '\n'
93 if len(self.a) > 0:
92 if len(self.a) > 0:
94 if self.a[0].endswith('\r\n'):
93 if self.a[0].endswith('\r\n'):
95 newline = '\r\n'
94 newline = '\r\n'
96 elif self.a[0].endswith('\r'):
95 elif self.a[0].endswith('\r'):
97 newline = '\r'
96 newline = '\r'
98 if base_marker and reprocess:
97 if base_marker and reprocess:
99 raise CantReprocessAndShowBase()
98 raise CantReprocessAndShowBase()
100 if name_a:
99 if name_a:
101 start_marker = start_marker + ' ' + name_a
100 start_marker = start_marker + ' ' + name_a
102 if name_b:
101 if name_b:
103 end_marker = end_marker + ' ' + name_b
102 end_marker = end_marker + ' ' + name_b
104 if name_base and base_marker:
103 if name_base and base_marker:
105 base_marker = base_marker + ' ' + name_base
104 base_marker = base_marker + ' ' + name_base
106 merge_regions = self.merge_regions()
105 merge_regions = self.merge_regions()
107 if reprocess is True:
106 if reprocess is True:
108 merge_regions = self.reprocess_merge_regions(merge_regions)
107 merge_regions = self.reprocess_merge_regions(merge_regions)
109 for t in merge_regions:
108 for t in merge_regions:
110 what = t[0]
109 what = t[0]
111 if what == 'unchanged':
110 if what == 'unchanged':
112 for i in range(t[1], t[2]):
111 for i in range(t[1], t[2]):
113 yield self.base[i]
112 yield self.base[i]
114 elif what == 'a' or what == 'same':
113 elif what == 'a' or what == 'same':
115 for i in range(t[1], t[2]):
114 for i in range(t[1], t[2]):
116 yield self.a[i]
115 yield self.a[i]
117 elif what == 'b':
116 elif what == 'b':
118 for i in range(t[1], t[2]):
117 for i in range(t[1], t[2]):
119 yield self.b[i]
118 yield self.b[i]
120 elif what == 'conflict':
119 elif what == 'conflict':
121 self.conflicts = True
120 self.conflicts = True
122 yield start_marker + newline
121 yield start_marker + newline
123 for i in range(t[3], t[4]):
122 for i in range(t[3], t[4]):
124 yield self.a[i]
123 yield self.a[i]
125 if base_marker is not None:
124 if base_marker is not None:
126 yield base_marker + newline
125 yield base_marker + newline
127 for i in range(t[1], t[2]):
126 for i in range(t[1], t[2]):
128 yield self.base[i]
127 yield self.base[i]
129 yield mid_marker + newline
128 yield mid_marker + newline
130 for i in range(t[5], t[6]):
129 for i in range(t[5], t[6]):
131 yield self.b[i]
130 yield self.b[i]
132 yield end_marker + newline
131 yield end_marker + newline
133 else:
132 else:
134 raise ValueError(what)
133 raise ValueError(what)
135
134
136 def merge_annotated(self):
135 def merge_annotated(self):
137 """Return merge with conflicts, showing origin of lines.
136 """Return merge with conflicts, showing origin of lines.
138
137
139 Most useful for debugging merge.
138 Most useful for debugging merge.
140 """
139 """
141 for t in self.merge_regions():
140 for t in self.merge_regions():
142 what = t[0]
141 what = t[0]
143 if what == 'unchanged':
142 if what == 'unchanged':
144 for i in range(t[1], t[2]):
143 for i in range(t[1], t[2]):
145 yield 'u | ' + self.base[i]
144 yield 'u | ' + self.base[i]
146 elif what == 'a' or what == 'same':
145 elif what == 'a' or what == 'same':
147 for i in range(t[1], t[2]):
146 for i in range(t[1], t[2]):
148 yield what[0] + ' | ' + self.a[i]
147 yield what[0] + ' | ' + self.a[i]
149 elif what == 'b':
148 elif what == 'b':
150 for i in range(t[1], t[2]):
149 for i in range(t[1], t[2]):
151 yield 'b | ' + self.b[i]
150 yield 'b | ' + self.b[i]
152 elif what == 'conflict':
151 elif what == 'conflict':
153 yield '<<<<\n'
152 yield '<<<<\n'
154 for i in range(t[3], t[4]):
153 for i in range(t[3], t[4]):
155 yield 'A | ' + self.a[i]
154 yield 'A | ' + self.a[i]
156 yield '----\n'
155 yield '----\n'
157 for i in range(t[5], t[6]):
156 for i in range(t[5], t[6]):
158 yield 'B | ' + self.b[i]
157 yield 'B | ' + self.b[i]
159 yield '>>>>\n'
158 yield '>>>>\n'
160 else:
159 else:
161 raise ValueError(what)
160 raise ValueError(what)
162
161
163 def merge_groups(self):
162 def merge_groups(self):
164 """Yield sequence of line groups. Each one is a tuple:
163 """Yield sequence of line groups. Each one is a tuple:
165
164
166 'unchanged', lines
165 'unchanged', lines
167 Lines unchanged from base
166 Lines unchanged from base
168
167
169 'a', lines
168 'a', lines
170 Lines taken from a
169 Lines taken from a
171
170
172 'same', lines
171 'same', lines
173 Lines taken from a (and equal to b)
172 Lines taken from a (and equal to b)
174
173
175 'b', lines
174 'b', lines
176 Lines taken from b
175 Lines taken from b
177
176
178 'conflict', base_lines, a_lines, b_lines
177 'conflict', base_lines, a_lines, b_lines
179 Lines from base were changed to either a or b and conflict.
178 Lines from base were changed to either a or b and conflict.
180 """
179 """
181 for t in self.merge_regions():
180 for t in self.merge_regions():
182 what = t[0]
181 what = t[0]
183 if what == 'unchanged':
182 if what == 'unchanged':
184 yield what, self.base[t[1]:t[2]]
183 yield what, self.base[t[1]:t[2]]
185 elif what == 'a' or what == 'same':
184 elif what == 'a' or what == 'same':
186 yield what, self.a[t[1]:t[2]]
185 yield what, self.a[t[1]:t[2]]
187 elif what == 'b':
186 elif what == 'b':
188 yield what, self.b[t[1]:t[2]]
187 yield what, self.b[t[1]:t[2]]
189 elif what == 'conflict':
188 elif what == 'conflict':
190 yield (what,
189 yield (what,
191 self.base[t[1]:t[2]],
190 self.base[t[1]:t[2]],
192 self.a[t[3]:t[4]],
191 self.a[t[3]:t[4]],
193 self.b[t[5]:t[6]])
192 self.b[t[5]:t[6]])
194 else:
193 else:
195 raise ValueError(what)
194 raise ValueError(what)
196
195
197 def merge_regions(self):
196 def merge_regions(self):
198 """Return sequences of matching and conflicting regions.
197 """Return sequences of matching and conflicting regions.
199
198
200 This returns tuples, where the first value says what kind we
199 This returns tuples, where the first value says what kind we
201 have:
200 have:
202
201
203 'unchanged', start, end
202 'unchanged', start, end
204 Take a region of base[start:end]
203 Take a region of base[start:end]
205
204
206 'same', astart, aend
205 'same', astart, aend
207 b and a are different from base but give the same result
206 b and a are different from base but give the same result
208
207
209 'a', start, end
208 'a', start, end
210 Non-clashing insertion from a[start:end]
209 Non-clashing insertion from a[start:end]
211
210
212 Method is as follows:
211 Method is as follows:
213
212
214 The two sequences align only on regions which match the base
213 The two sequences align only on regions which match the base
215 and both descendents. These are found by doing a two-way diff
214 and both descendents. These are found by doing a two-way diff
216 of each one against the base, and then finding the
215 of each one against the base, and then finding the
217 intersections between those regions. These "sync regions"
216 intersections between those regions. These "sync regions"
218 are by definition unchanged in both and easily dealt with.
217 are by definition unchanged in both and easily dealt with.
219
218
220 The regions in between can be in any of three cases:
219 The regions in between can be in any of three cases:
221 conflicted, or changed on only one side.
220 conflicted, or changed on only one side.
222 """
221 """
223
222
224 # section a[0:ia] has been disposed of, etc
223 # section a[0:ia] has been disposed of, etc
225 iz = ia = ib = 0
224 iz = ia = ib = 0
226
225
227 for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions():
226 for zmatch, zend, amatch, aend, bmatch, bend in self.find_sync_regions():
228 #print 'match base [%d:%d]' % (zmatch, zend)
227 #print 'match base [%d:%d]' % (zmatch, zend)
229
228
230 matchlen = zend - zmatch
229 matchlen = zend - zmatch
231 assert matchlen >= 0
230 assert matchlen >= 0
232 assert matchlen == (aend - amatch)
231 assert matchlen == (aend - amatch)
233 assert matchlen == (bend - bmatch)
232 assert matchlen == (bend - bmatch)
234
233
235 len_a = amatch - ia
234 len_a = amatch - ia
236 len_b = bmatch - ib
235 len_b = bmatch - ib
237 len_base = zmatch - iz
236 len_base = zmatch - iz
238 assert len_a >= 0
237 assert len_a >= 0
239 assert len_b >= 0
238 assert len_b >= 0
240 assert len_base >= 0
239 assert len_base >= 0
241
240
242 #print 'unmatched a=%d, b=%d' % (len_a, len_b)
241 #print 'unmatched a=%d, b=%d' % (len_a, len_b)
243
242
244 if len_a or len_b:
243 if len_a or len_b:
245 # try to avoid actually slicing the lists
244 # try to avoid actually slicing the lists
246 equal_a = compare_range(self.a, ia, amatch,
245 equal_a = compare_range(self.a, ia, amatch,
247 self.base, iz, zmatch)
246 self.base, iz, zmatch)
248 equal_b = compare_range(self.b, ib, bmatch,
247 equal_b = compare_range(self.b, ib, bmatch,
249 self.base, iz, zmatch)
248 self.base, iz, zmatch)
250 same = compare_range(self.a, ia, amatch,
249 same = compare_range(self.a, ia, amatch,
251 self.b, ib, bmatch)
250 self.b, ib, bmatch)
252
251
253 if same:
252 if same:
254 yield 'same', ia, amatch
253 yield 'same', ia, amatch
255 elif equal_a and not equal_b:
254 elif equal_a and not equal_b:
256 yield 'b', ib, bmatch
255 yield 'b', ib, bmatch
257 elif equal_b and not equal_a:
256 elif equal_b and not equal_a:
258 yield 'a', ia, amatch
257 yield 'a', ia, amatch
259 elif not equal_a and not equal_b:
258 elif not equal_a and not equal_b:
260 yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch
259 yield 'conflict', iz, zmatch, ia, amatch, ib, bmatch
261 else:
260 else:
262 raise AssertionError("can't handle a=b=base but unmatched")
261 raise AssertionError("can't handle a=b=base but unmatched")
263
262
264 ia = amatch
263 ia = amatch
265 ib = bmatch
264 ib = bmatch
266 iz = zmatch
265 iz = zmatch
267
266
268 # if the same part of the base was deleted on both sides
267 # if the same part of the base was deleted on both sides
269 # that's OK, we can just skip it.
268 # that's OK, we can just skip it.
270
269
271
270
272 if matchlen > 0:
271 if matchlen > 0:
273 assert ia == amatch
272 assert ia == amatch
274 assert ib == bmatch
273 assert ib == bmatch
275 assert iz == zmatch
274 assert iz == zmatch
276
275
277 yield 'unchanged', zmatch, zend
276 yield 'unchanged', zmatch, zend
278 iz = zend
277 iz = zend
279 ia = aend
278 ia = aend
280 ib = bend
279 ib = bend
281
280
282 def reprocess_merge_regions(self, merge_regions):
281 def reprocess_merge_regions(self, merge_regions):
283 """Where there are conflict regions, remove the agreed lines.
282 """Where there are conflict regions, remove the agreed lines.
284
283
285 Lines where both A and B have made the same changes are
284 Lines where both A and B have made the same changes are
286 eliminated.
285 eliminated.
287 """
286 """
288 for region in merge_regions:
287 for region in merge_regions:
289 if region[0] != "conflict":
288 if region[0] != "conflict":
290 yield region
289 yield region
291 continue
290 continue
292 type, iz, zmatch, ia, amatch, ib, bmatch = region
291 type, iz, zmatch, ia, amatch, ib, bmatch = region
293 a_region = self.a[ia:amatch]
292 a_region = self.a[ia:amatch]
294 b_region = self.b[ib:bmatch]
293 b_region = self.b[ib:bmatch]
295 matches = mdiff.get_matching_blocks(''.join(a_region),
294 matches = mdiff.get_matching_blocks(''.join(a_region),
296 ''.join(b_region))
295 ''.join(b_region))
297 next_a = ia
296 next_a = ia
298 next_b = ib
297 next_b = ib
299 for region_ia, region_ib, region_len in matches[:-1]:
298 for region_ia, region_ib, region_len in matches[:-1]:
300 region_ia += ia
299 region_ia += ia
301 region_ib += ib
300 region_ib += ib
302 reg = self.mismatch_region(next_a, region_ia, next_b,
301 reg = self.mismatch_region(next_a, region_ia, next_b,
303 region_ib)
302 region_ib)
304 if reg is not None:
303 if reg is not None:
305 yield reg
304 yield reg
306 yield 'same', region_ia, region_len + region_ia
305 yield 'same', region_ia, region_len + region_ia
307 next_a = region_ia + region_len
306 next_a = region_ia + region_len
308 next_b = region_ib + region_len
307 next_b = region_ib + region_len
309 reg = self.mismatch_region(next_a, amatch, next_b, bmatch)
308 reg = self.mismatch_region(next_a, amatch, next_b, bmatch)
310 if reg is not None:
309 if reg is not None:
311 yield reg
310 yield reg
312
311
313 def mismatch_region(next_a, region_ia, next_b, region_ib):
312 def mismatch_region(next_a, region_ia, next_b, region_ib):
314 if next_a < region_ia or next_b < region_ib:
313 if next_a < region_ia or next_b < region_ib:
315 return 'conflict', None, None, next_a, region_ia, next_b, region_ib
314 return 'conflict', None, None, next_a, region_ia, next_b, region_ib
316 mismatch_region = staticmethod(mismatch_region)
315 mismatch_region = staticmethod(mismatch_region)
317
316
318 def find_sync_regions(self):
317 def find_sync_regions(self):
319 """Return a list of sync regions, where both descendents match the base.
318 """Return a list of sync regions, where both descendents match the base.
320
319
321 Generates a list of (base1, base2, a1, a2, b1, b2). There is
320 Generates a list of (base1, base2, a1, a2, b1, b2). There is
322 always a zero-length sync region at the end of all the files.
321 always a zero-length sync region at the end of all the files.
323 """
322 """
324
323
325 ia = ib = 0
324 ia = ib = 0
326 amatches = mdiff.get_matching_blocks(self.basetext, self.atext)
325 amatches = mdiff.get_matching_blocks(self.basetext, self.atext)
327 bmatches = mdiff.get_matching_blocks(self.basetext, self.btext)
326 bmatches = mdiff.get_matching_blocks(self.basetext, self.btext)
328 len_a = len(amatches)
327 len_a = len(amatches)
329 len_b = len(bmatches)
328 len_b = len(bmatches)
330
329
331 sl = []
330 sl = []
332
331
333 while ia < len_a and ib < len_b:
332 while ia < len_a and ib < len_b:
334 abase, amatch, alen = amatches[ia]
333 abase, amatch, alen = amatches[ia]
335 bbase, bmatch, blen = bmatches[ib]
334 bbase, bmatch, blen = bmatches[ib]
336
335
337 # there is an unconflicted block at i; how long does it
336 # there is an unconflicted block at i; how long does it
338 # extend? until whichever one ends earlier.
337 # extend? until whichever one ends earlier.
339 i = intersect((abase, abase + alen), (bbase, bbase + blen))
338 i = intersect((abase, abase + alen), (bbase, bbase + blen))
340 if i:
339 if i:
341 intbase = i[0]
340 intbase = i[0]
342 intend = i[1]
341 intend = i[1]
343 intlen = intend - intbase
342 intlen = intend - intbase
344
343
345 # found a match of base[i[0], i[1]]; this may be less than
344 # found a match of base[i[0], i[1]]; this may be less than
346 # the region that matches in either one
345 # the region that matches in either one
347 assert intlen <= alen
346 assert intlen <= alen
348 assert intlen <= blen
347 assert intlen <= blen
349 assert abase <= intbase
348 assert abase <= intbase
350 assert bbase <= intbase
349 assert bbase <= intbase
351
350
352 asub = amatch + (intbase - abase)
351 asub = amatch + (intbase - abase)
353 bsub = bmatch + (intbase - bbase)
352 bsub = bmatch + (intbase - bbase)
354 aend = asub + intlen
353 aend = asub + intlen
355 bend = bsub + intlen
354 bend = bsub + intlen
356
355
357 assert self.base[intbase:intend] == self.a[asub:aend], \
356 assert self.base[intbase:intend] == self.a[asub:aend], \
358 (self.base[intbase:intend], self.a[asub:aend])
357 (self.base[intbase:intend], self.a[asub:aend])
359
358
360 assert self.base[intbase:intend] == self.b[bsub:bend]
359 assert self.base[intbase:intend] == self.b[bsub:bend]
361
360
362 sl.append((intbase, intend,
361 sl.append((intbase, intend,
363 asub, aend,
362 asub, aend,
364 bsub, bend))
363 bsub, bend))
365
364
366 # advance whichever one ends first in the base text
365 # advance whichever one ends first in the base text
367 if (abase + alen) < (bbase + blen):
366 if (abase + alen) < (bbase + blen):
368 ia += 1
367 ia += 1
369 else:
368 else:
370 ib += 1
369 ib += 1
371
370
372 intbase = len(self.base)
371 intbase = len(self.base)
373 abase = len(self.a)
372 abase = len(self.a)
374 bbase = len(self.b)
373 bbase = len(self.b)
375 sl.append((intbase, intbase, abase, abase, bbase, bbase))
374 sl.append((intbase, intbase, abase, abase, bbase, bbase))
376
375
377 return sl
376 return sl
378
377
379 def find_unconflicted(self):
378 def find_unconflicted(self):
380 """Return a list of ranges in base that are not conflicted."""
379 """Return a list of ranges in base that are not conflicted."""
381 am = mdiff.get_matching_blocks(self.basetext, self.atext)
380 am = mdiff.get_matching_blocks(self.basetext, self.atext)
382 bm = mdiff.get_matching_blocks(self.basetext, self.btext)
381 bm = mdiff.get_matching_blocks(self.basetext, self.btext)
383
382
384 unc = []
383 unc = []
385
384
386 while am and bm:
385 while am and bm:
387 # there is an unconflicted block at i; how long does it
386 # there is an unconflicted block at i; how long does it
388 # extend? until whichever one ends earlier.
387 # extend? until whichever one ends earlier.
389 a1 = am[0][0]
388 a1 = am[0][0]
390 a2 = a1 + am[0][2]
389 a2 = a1 + am[0][2]
391 b1 = bm[0][0]
390 b1 = bm[0][0]
392 b2 = b1 + bm[0][2]
391 b2 = b1 + bm[0][2]
393 i = intersect((a1, a2), (b1, b2))
392 i = intersect((a1, a2), (b1, b2))
394 if i:
393 if i:
395 unc.append(i)
394 unc.append(i)
396
395
397 if a2 < b2:
396 if a2 < b2:
398 del am[0]
397 del am[0]
399 else:
398 else:
400 del bm[0]
399 del bm[0]
401
400
402 return unc
401 return unc
403
402
404 def simplemerge(ui, local, base, other, **opts):
403 def simplemerge(ui, local, base, other, **opts):
405 def readfile(filename):
404 def readfile(filename):
406 f = open(filename, "rb")
405 f = open(filename, "rb")
407 text = f.read()
406 text = f.read()
408 f.close()
407 f.close()
409 if util.binary(text):
408 if util.binary(text):
410 msg = _("%s looks like a binary file.") % filename
409 msg = _("%s looks like a binary file.") % filename
411 if not opts.get('text'):
410 if not opts.get('text'):
412 raise util.Abort(msg)
411 raise util.Abort(msg)
413 elif not opts.get('quiet'):
412 elif not opts.get('quiet'):
414 ui.warn(_('warning: %s\n') % msg)
413 ui.warn(_('warning: %s\n') % msg)
415 return text
414 return text
416
415
417 name_a = local
416 name_a = local
418 name_b = other
417 name_b = other
419 labels = opts.get('label', [])
418 labels = opts.get('label', [])
420 if labels:
419 if labels:
421 name_a = labels.pop(0)
420 name_a = labels.pop(0)
422 if labels:
421 if labels:
423 name_b = labels.pop(0)
422 name_b = labels.pop(0)
424 if labels:
423 if labels:
425 raise util.Abort(_("can only specify two labels."))
424 raise util.Abort(_("can only specify two labels."))
426
425
427 localtext = readfile(local)
426 localtext = readfile(local)
428 basetext = readfile(base)
427 basetext = readfile(base)
429 othertext = readfile(other)
428 othertext = readfile(other)
430
429
431 local = os.path.realpath(local)
430 local = os.path.realpath(local)
432 if not opts.get('print'):
431 if not opts.get('print'):
433 opener = util.opener(os.path.dirname(local))
432 opener = util.opener(os.path.dirname(local))
434 out = opener(os.path.basename(local), "w", atomictemp=True)
433 out = opener(os.path.basename(local), "w", atomictemp=True)
435 else:
434 else:
436 out = sys.stdout
435 out = sys.stdout
437
436
438 reprocess = not opts.get('no_minimal')
437 reprocess = not opts.get('no_minimal')
439
438
440 m3 = Merge3Text(basetext, localtext, othertext)
439 m3 = Merge3Text(basetext, localtext, othertext)
441 for line in m3.merge_lines(name_a=name_a, name_b=name_b,
440 for line in m3.merge_lines(name_a=name_a, name_b=name_b,
442 reprocess=reprocess):
441 reprocess=reprocess):
443 out.write(line)
442 out.write(line)
444
443
445 if not opts.get('print'):
444 if not opts.get('print'):
446 out.rename()
445 out.rename()
447
446
448 if m3.conflicts:
447 if m3.conflicts:
449 if not opts.get('quiet'):
448 if not opts.get('quiet'):
450 ui.warn(_("warning: conflicts during merge.\n"))
449 ui.warn(_("warning: conflicts during merge.\n"))
451 return 1
450 return 1
General Comments 0
You need to be logged in to leave comments. Login now