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