##// END OF EJS Templates
filemerge: indent filemerge.filemerge...
Siddharth Agarwal -
r26512:4c52dd40 default
parent child Browse files
Show More
@@ -1,545 +1,547 b''
1 1 # filemerge.py - file-level merge handling for Mercurial
2 2 #
3 3 # Copyright 2006, 2007, 2008 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import filecmp
11 11 import os
12 12 import re
13 13 import tempfile
14 14
15 15 from .i18n import _
16 16 from .node import short
17 17
18 18 from . import (
19 19 error,
20 20 match,
21 21 simplemerge,
22 22 tagmerge,
23 23 templatekw,
24 24 templater,
25 25 util,
26 26 )
27 27
28 28 def _toolstr(ui, tool, part, default=""):
29 29 return ui.config("merge-tools", tool + "." + part, default)
30 30
31 31 def _toolbool(ui, tool, part, default=False):
32 32 return ui.configbool("merge-tools", tool + "." + part, default)
33 33
34 34 def _toollist(ui, tool, part, default=[]):
35 35 return ui.configlist("merge-tools", tool + "." + part, default)
36 36
37 37 internals = {}
38 38 # Merge tools to document.
39 39 internalsdoc = {}
40 40
41 41 def internaltool(name, trymerge, onfailure=None):
42 42 '''return a decorator for populating internal merge tool table'''
43 43 def decorator(func):
44 44 fullname = ':' + name
45 45 func.__doc__ = "``%s``\n" % fullname + func.__doc__.strip()
46 46 internals[fullname] = func
47 47 internals['internal:' + name] = func
48 48 internalsdoc[fullname] = func
49 49 func.trymerge = trymerge
50 50 func.onfailure = onfailure
51 51 return func
52 52 return decorator
53 53
54 54 def _findtool(ui, tool):
55 55 if tool in internals:
56 56 return tool
57 57 return findexternaltool(ui, tool)
58 58
59 59 def findexternaltool(ui, tool):
60 60 for kn in ("regkey", "regkeyalt"):
61 61 k = _toolstr(ui, tool, kn)
62 62 if not k:
63 63 continue
64 64 p = util.lookupreg(k, _toolstr(ui, tool, "regname"))
65 65 if p:
66 66 p = util.findexe(p + _toolstr(ui, tool, "regappend"))
67 67 if p:
68 68 return p
69 69 exe = _toolstr(ui, tool, "executable", tool)
70 70 return util.findexe(util.expandpath(exe))
71 71
72 72 def _picktool(repo, ui, path, binary, symlink):
73 73 def check(tool, pat, symlink, binary):
74 74 tmsg = tool
75 75 if pat:
76 76 tmsg += " specified for " + pat
77 77 if not _findtool(ui, tool):
78 78 if pat: # explicitly requested tool deserves a warning
79 79 ui.warn(_("couldn't find merge tool %s\n") % tmsg)
80 80 else: # configured but non-existing tools are more silent
81 81 ui.note(_("couldn't find merge tool %s\n") % tmsg)
82 82 elif symlink and not _toolbool(ui, tool, "symlink"):
83 83 ui.warn(_("tool %s can't handle symlinks\n") % tmsg)
84 84 elif binary and not _toolbool(ui, tool, "binary"):
85 85 ui.warn(_("tool %s can't handle binary\n") % tmsg)
86 86 elif not util.gui() and _toolbool(ui, tool, "gui"):
87 87 ui.warn(_("tool %s requires a GUI\n") % tmsg)
88 88 else:
89 89 return True
90 90 return False
91 91
92 92 # internal config: ui.forcemerge
93 93 # forcemerge comes from command line arguments, highest priority
94 94 force = ui.config('ui', 'forcemerge')
95 95 if force:
96 96 toolpath = _findtool(ui, force)
97 97 if toolpath:
98 98 return (force, util.shellquote(toolpath))
99 99 else:
100 100 # mimic HGMERGE if given tool not found
101 101 return (force, force)
102 102
103 103 # HGMERGE takes next precedence
104 104 hgmerge = os.environ.get("HGMERGE")
105 105 if hgmerge:
106 106 return (hgmerge, hgmerge)
107 107
108 108 # then patterns
109 109 for pat, tool in ui.configitems("merge-patterns"):
110 110 mf = match.match(repo.root, '', [pat])
111 111 if mf(path) and check(tool, pat, symlink, False):
112 112 toolpath = _findtool(ui, tool)
113 113 return (tool, util.shellquote(toolpath))
114 114
115 115 # then merge tools
116 116 tools = {}
117 117 for k, v in ui.configitems("merge-tools"):
118 118 t = k.split('.')[0]
119 119 if t not in tools:
120 120 tools[t] = int(_toolstr(ui, t, "priority", "0"))
121 121 names = tools.keys()
122 122 tools = sorted([(-p, t) for t, p in tools.items()])
123 123 uimerge = ui.config("ui", "merge")
124 124 if uimerge:
125 125 if uimerge not in names:
126 126 return (uimerge, uimerge)
127 127 tools.insert(0, (None, uimerge)) # highest priority
128 128 tools.append((None, "hgmerge")) # the old default, if found
129 129 for p, t in tools:
130 130 if check(t, None, symlink, binary):
131 131 toolpath = _findtool(ui, t)
132 132 return (t, util.shellquote(toolpath))
133 133
134 134 # internal merge or prompt as last resort
135 135 if symlink or binary:
136 136 return ":prompt", None
137 137 return ":merge", None
138 138
139 139 def _eoltype(data):
140 140 "Guess the EOL type of a file"
141 141 if '\0' in data: # binary
142 142 return None
143 143 if '\r\n' in data: # Windows
144 144 return '\r\n'
145 145 if '\r' in data: # Old Mac
146 146 return '\r'
147 147 if '\n' in data: # UNIX
148 148 return '\n'
149 149 return None # unknown
150 150
151 151 def _matcheol(file, origfile):
152 152 "Convert EOL markers in a file to match origfile"
153 153 tostyle = _eoltype(util.readfile(origfile))
154 154 if tostyle:
155 155 data = util.readfile(file)
156 156 style = _eoltype(data)
157 157 if style:
158 158 newdata = data.replace(style, tostyle)
159 159 if newdata != data:
160 160 util.writefile(file, newdata)
161 161
162 162 @internaltool('prompt', False)
163 163 def _iprompt(repo, mynode, orig, fcd, fco, fca, toolconf):
164 164 """Asks the user which of the local or the other version to keep as
165 165 the merged version."""
166 166 ui = repo.ui
167 167 fd = fcd.path()
168 168
169 169 if ui.promptchoice(_(" no tool found to merge %s\n"
170 170 "keep (l)ocal or take (o)ther?"
171 171 "$$ &Local $$ &Other") % fd, 0):
172 172 return _iother(repo, mynode, orig, fcd, fco, fca, toolconf)
173 173 else:
174 174 return _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf)
175 175
176 176 @internaltool('local', False)
177 177 def _ilocal(repo, mynode, orig, fcd, fco, fca, toolconf):
178 178 """Uses the local version of files as the merged version."""
179 179 return 0
180 180
181 181 @internaltool('other', False)
182 182 def _iother(repo, mynode, orig, fcd, fco, fca, toolconf):
183 183 """Uses the other version of files as the merged version."""
184 184 repo.wwrite(fcd.path(), fco.data(), fco.flags())
185 185 return 0
186 186
187 187 @internaltool('fail', False)
188 188 def _ifail(repo, mynode, orig, fcd, fco, fca, toolconf):
189 189 """
190 190 Rather than attempting to merge files that were modified on both
191 191 branches, it marks them as unresolved. The resolve command must be
192 192 used to resolve these conflicts."""
193 193 return 1
194 194
195 195 def _premerge(repo, toolconf, files, labels=None):
196 196 tool, toolpath, binary, symlink = toolconf
197 197 if symlink:
198 198 return 1
199 199 a, b, c, back = files
200 200
201 201 ui = repo.ui
202 202
203 203 validkeep = ['keep', 'keep-merge3']
204 204
205 205 # do we attempt to simplemerge first?
206 206 try:
207 207 premerge = _toolbool(ui, tool, "premerge", not binary)
208 208 except error.ConfigError:
209 209 premerge = _toolstr(ui, tool, "premerge").lower()
210 210 if premerge not in validkeep:
211 211 _valid = ', '.join(["'" + v + "'" for v in validkeep])
212 212 raise error.ConfigError(_("%s.premerge not valid "
213 213 "('%s' is neither boolean nor %s)") %
214 214 (tool, premerge, _valid))
215 215
216 216 if premerge:
217 217 if premerge == 'keep-merge3':
218 218 if not labels:
219 219 labels = _defaultconflictlabels
220 220 if len(labels) < 3:
221 221 labels.append('base')
222 222 r = simplemerge.simplemerge(ui, a, b, c, quiet=True, label=labels)
223 223 if not r:
224 224 ui.debug(" premerge successful\n")
225 225 return 0
226 226 if premerge not in validkeep:
227 227 util.copyfile(back, a) # restore from backup and try again
228 228 return 1 # continue merging
229 229
230 230 def _merge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels, mode):
231 231 """
232 232 Uses the internal non-interactive simple merge algorithm for merging
233 233 files. It will fail if there are any conflicts and leave markers in
234 234 the partially merged file. Markers will have two sections, one for each side
235 235 of merge, unless mode equals 'union' which suppresses the markers."""
236 236 tool, toolpath, binary, symlink = toolconf
237 237 if symlink:
238 238 repo.ui.warn(_('warning: internal :merge cannot merge symlinks '
239 239 'for %s\n') % fcd.path())
240 240 return False, 1
241 241 r = _premerge(repo, toolconf, files, labels=labels)
242 242 if r:
243 243 a, b, c, back = files
244 244
245 245 ui = repo.ui
246 246
247 247 r = simplemerge.simplemerge(ui, a, b, c, label=labels, mode=mode)
248 248 return True, r
249 249 return False, 0
250 250
251 251 @internaltool('union', True,
252 252 _("merging %s incomplete! "
253 253 "(edit conflicts, then use 'hg resolve --mark')\n"))
254 254 def _iunion(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
255 255 """
256 256 Uses the internal non-interactive simple merge algorithm for merging
257 257 files. It will use both left and right sides for conflict regions.
258 258 No markers are inserted."""
259 259 return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
260 260 files, labels, 'union')
261 261
262 262 @internaltool('merge', True,
263 263 _("merging %s incomplete! "
264 264 "(edit conflicts, then use 'hg resolve --mark')\n"))
265 265 def _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
266 266 """
267 267 Uses the internal non-interactive simple merge algorithm for merging
268 268 files. It will fail if there are any conflicts and leave markers in
269 269 the partially merged file. Markers will have two sections, one for each side
270 270 of merge."""
271 271 return _merge(repo, mynode, orig, fcd, fco, fca, toolconf,
272 272 files, labels, 'merge')
273 273
274 274 @internaltool('merge3', True,
275 275 _("merging %s incomplete! "
276 276 "(edit conflicts, then use 'hg resolve --mark')\n"))
277 277 def _imerge3(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
278 278 """
279 279 Uses the internal non-interactive simple merge algorithm for merging
280 280 files. It will fail if there are any conflicts and leave markers in
281 281 the partially merged file. Marker will have three sections, one from each
282 282 side of the merge and one for the base content."""
283 283 if not labels:
284 284 labels = _defaultconflictlabels
285 285 if len(labels) < 3:
286 286 labels.append('base')
287 287 return _imerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels)
288 288
289 289 def _imergeauto(repo, mynode, orig, fcd, fco, fca, toolconf, files,
290 290 labels=None, localorother=None):
291 291 """
292 292 Generic driver for _imergelocal and _imergeother
293 293 """
294 294 assert localorother is not None
295 295 tool, toolpath, binary, symlink = toolconf
296 296 if symlink:
297 297 repo.ui.warn(_('warning: :merge-%s cannot merge symlinks '
298 298 'for %s\n') % (localorother, fcd.path()))
299 299 return False, 1
300 300 a, b, c, back = files
301 301 r = simplemerge.simplemerge(repo.ui, a, b, c, label=labels,
302 302 localorother=localorother)
303 303 return True, r
304 304
305 305 @internaltool('merge-local', True)
306 306 def _imergelocal(*args, **kwargs):
307 307 """
308 308 Like :merge, but resolve all conflicts non-interactively in favor
309 309 of the local changes."""
310 310 success, status = _imergeauto(localorother='local', *args, **kwargs)
311 311 return success, status
312 312
313 313 @internaltool('merge-other', True)
314 314 def _imergeother(*args, **kwargs):
315 315 """
316 316 Like :merge, but resolve all conflicts non-interactively in favor
317 317 of the other changes."""
318 318 success, status = _imergeauto(localorother='other', *args, **kwargs)
319 319 return success, status
320 320
321 321 @internaltool('tagmerge', True,
322 322 _("automatic tag merging of %s failed! "
323 323 "(use 'hg resolve --tool :merge' or another merge "
324 324 "tool of your choice)\n"))
325 325 def _itagmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
326 326 """
327 327 Uses the internal tag merge algorithm (experimental).
328 328 """
329 329 return tagmerge.merge(repo, fcd, fco, fca)
330 330
331 331 @internaltool('dump', True)
332 332 def _idump(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
333 333 """
334 334 Creates three versions of the files to merge, containing the
335 335 contents of local, other and base. These files can then be used to
336 336 perform a merge manually. If the file to be merged is named
337 337 ``a.txt``, these files will accordingly be named ``a.txt.local``,
338 338 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
339 339 same directory as ``a.txt``."""
340 340 r = _premerge(repo, toolconf, files, labels=labels)
341 341 if r:
342 342 a, b, c, back = files
343 343
344 344 fd = fcd.path()
345 345
346 346 util.copyfile(a, a + ".local")
347 347 repo.wwrite(fd + ".other", fco.data(), fco.flags())
348 348 repo.wwrite(fd + ".base", fca.data(), fca.flags())
349 349 return False, r
350 350
351 351 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
352 352 r = _premerge(repo, toolconf, files, labels=labels)
353 353 if r:
354 354 tool, toolpath, binary, symlink = toolconf
355 355 a, b, c, back = files
356 356 out = ""
357 357 env = {'HG_FILE': fcd.path(),
358 358 'HG_MY_NODE': short(mynode),
359 359 'HG_OTHER_NODE': str(fco.changectx()),
360 360 'HG_BASE_NODE': str(fca.changectx()),
361 361 'HG_MY_ISLINK': 'l' in fcd.flags(),
362 362 'HG_OTHER_ISLINK': 'l' in fco.flags(),
363 363 'HG_BASE_ISLINK': 'l' in fca.flags(),
364 364 }
365 365
366 366 ui = repo.ui
367 367
368 368 args = _toolstr(ui, tool, "args", '$local $base $other')
369 369 if "$output" in args:
370 370 out, a = a, back # read input from backup, write to original
371 371 replace = {'local': a, 'base': b, 'other': c, 'output': out}
372 372 args = util.interpolate(r'\$', replace, args,
373 373 lambda s: util.shellquote(util.localpath(s)))
374 374 cmd = toolpath + ' ' + args
375 375 repo.ui.debug('launching merge tool: %s\n' % cmd)
376 376 r = ui.system(cmd, cwd=repo.root, environ=env)
377 377 repo.ui.debug('merge tool returned: %s\n' % r)
378 378 return True, r
379 379 return False, 0
380 380
381 381 def _formatconflictmarker(repo, ctx, template, label, pad):
382 382 """Applies the given template to the ctx, prefixed by the label.
383 383
384 384 Pad is the minimum width of the label prefix, so that multiple markers
385 385 can have aligned templated parts.
386 386 """
387 387 if ctx.node() is None:
388 388 ctx = ctx.p1()
389 389
390 390 props = templatekw.keywords.copy()
391 391 props['templ'] = template
392 392 props['ctx'] = ctx
393 393 props['repo'] = repo
394 394 templateresult = template('conflictmarker', **props)
395 395
396 396 label = ('%s:' % label).ljust(pad + 1)
397 397 mark = '%s %s' % (label, templater.stringify(templateresult))
398 398
399 399 if mark:
400 400 mark = mark.splitlines()[0] # split for safety
401 401
402 402 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
403 403 return util.ellipsis(mark, 80 - 8)
404 404
405 405 _defaultconflictmarker = ('{node|short} ' +
406 406 '{ifeq(tags, "tip", "", "{tags} ")}' +
407 407 '{if(bookmarks, "{bookmarks} ")}' +
408 408 '{ifeq(branch, "default", "", "{branch} ")}' +
409 409 '- {author|user}: {desc|firstline}')
410 410
411 411 _defaultconflictlabels = ['local', 'other']
412 412
413 413 def _formatlabels(repo, fcd, fco, fca, labels):
414 414 """Formats the given labels using the conflict marker template.
415 415
416 416 Returns a list of formatted labels.
417 417 """
418 418 cd = fcd.changectx()
419 419 co = fco.changectx()
420 420 ca = fca.changectx()
421 421
422 422 ui = repo.ui
423 423 template = ui.config('ui', 'mergemarkertemplate', _defaultconflictmarker)
424 424 tmpl = templater.templater(None, cache={'conflictmarker': template})
425 425
426 426 pad = max(len(l) for l in labels)
427 427
428 428 newlabels = [_formatconflictmarker(repo, cd, tmpl, labels[0], pad),
429 429 _formatconflictmarker(repo, co, tmpl, labels[1], pad)]
430 430 if len(labels) > 2:
431 431 newlabels.append(_formatconflictmarker(repo, ca, tmpl, labels[2], pad))
432 432 return newlabels
433 433
434 434 def filemerge(repo, mynode, orig, fcd, fco, fca, labels=None):
435 435 """perform a 3-way merge in the working directory
436 436
437 437 mynode = parent node before merge
438 438 orig = original local filename before merge
439 439 fco = other file context
440 440 fca = ancestor file context
441 441 fcd = local file context for current/destination file
442 442 """
443 443
444 def temp(prefix, ctx):
445 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
446 (fd, name) = tempfile.mkstemp(prefix=pre)
447 data = repo.wwritedata(ctx.path(), ctx.data())
448 f = os.fdopen(fd, "wb")
449 f.write(data)
450 f.close()
451 return name
444 if True:
445 def temp(prefix, ctx):
446 pre = "%s~%s." % (os.path.basename(ctx.path()), prefix)
447 (fd, name) = tempfile.mkstemp(prefix=pre)
448 data = repo.wwritedata(ctx.path(), ctx.data())
449 f = os.fdopen(fd, "wb")
450 f.write(data)
451 f.close()
452 return name
453
454 if not fco.cmp(fcd): # files identical?
455 return None
456
457 ui = repo.ui
458 fd = fcd.path()
459 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
460 symlink = 'l' in fcd.flags() + fco.flags()
461 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
462 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
463 (tool, fd, binary, symlink))
452 464
453 if not fco.cmp(fcd): # files identical?
454 return None
465 if tool in internals:
466 func = internals[tool]
467 trymerge = func.trymerge
468 onfailure = func.onfailure
469 else:
470 func = _xmerge
471 trymerge = True
472 onfailure = _("merging %s failed!\n")
473
474 toolconf = tool, toolpath, binary, symlink
455 475
456 ui = repo.ui
457 fd = fcd.path()
458 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
459 symlink = 'l' in fcd.flags() + fco.flags()
460 tool, toolpath = _picktool(repo, ui, fd, binary, symlink)
461 ui.debug("picked tool '%s' for %s (binary %s symlink %s)\n" %
462 (tool, fd, binary, symlink))
476 if not trymerge:
477 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
478
479 a = repo.wjoin(fd)
480 b = temp("base", fca)
481 c = temp("other", fco)
482 back = a + ".orig"
483 util.copyfile(a, back)
484
485 if orig != fco.path():
486 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
487 else:
488 ui.status(_("merging %s\n") % fd)
463 489
464 if tool in internals:
465 func = internals[tool]
466 trymerge = func.trymerge
467 onfailure = func.onfailure
468 else:
469 func = _xmerge
470 trymerge = True
471 onfailure = _("merging %s failed!\n")
490 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
491
492 markerstyle = ui.config('ui', 'mergemarkers', 'basic')
493 if not labels:
494 labels = _defaultconflictlabels
495 if markerstyle != 'basic':
496 labels = _formatlabels(repo, fcd, fco, fca, labels)
472 497
473 toolconf = tool, toolpath, binary, symlink
498 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
499 (a, b, c, back), labels=labels)
500 if not needcheck:
501 if r:
502 if onfailure:
503 ui.warn(onfailure % fd)
504 else:
505 util.unlink(back)
474 506
475 if not trymerge:
476 return func(repo, mynode, orig, fcd, fco, fca, toolconf)
507 util.unlink(b)
508 util.unlink(c)
509 return r
477 510
478 a = repo.wjoin(fd)
479 b = temp("base", fca)
480 c = temp("other", fco)
481 back = a + ".orig"
482 util.copyfile(a, back)
511 if not r and (_toolbool(ui, tool, "checkconflicts") or
512 'conflicts' in _toollist(ui, tool, "check")):
513 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
514 re.MULTILINE):
515 r = 1
483 516
484 if orig != fco.path():
485 ui.status(_("merging %s and %s to %s\n") % (orig, fco.path(), fd))
486 else:
487 ui.status(_("merging %s\n") % fd)
517 checked = False
518 if 'prompt' in _toollist(ui, tool, "check"):
519 checked = True
520 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
521 "$$ &Yes $$ &No") % fd, 1):
522 r = 1
488 523
489 ui.debug("my %s other %s ancestor %s\n" % (fcd, fco, fca))
524 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
525 'changed' in
526 _toollist(ui, tool, "check")):
527 if filecmp.cmp(a, back):
528 if ui.promptchoice(_(" output file %s appears unchanged\n"
529 "was merge successful (yn)?"
530 "$$ &Yes $$ &No") % fd, 1):
531 r = 1
490 532
491 markerstyle = ui.config('ui', 'mergemarkers', 'basic')
492 if not labels:
493 labels = _defaultconflictlabels
494 if markerstyle != 'basic':
495 labels = _formatlabels(repo, fcd, fco, fca, labels)
533 if _toolbool(ui, tool, "fixeol"):
534 _matcheol(a, back)
496 535
497 needcheck, r = func(repo, mynode, orig, fcd, fco, fca, toolconf,
498 (a, b, c, back), labels=labels)
499 if not needcheck:
500 536 if r:
501 537 if onfailure:
502 538 ui.warn(onfailure % fd)
503 539 else:
504 540 util.unlink(back)
505 541
506 542 util.unlink(b)
507 543 util.unlink(c)
508 544 return r
509 545
510 if not r and (_toolbool(ui, tool, "checkconflicts") or
511 'conflicts' in _toollist(ui, tool, "check")):
512 if re.search("^(<<<<<<< .*|=======|>>>>>>> .*)$", fcd.data(),
513 re.MULTILINE):
514 r = 1
515
516 checked = False
517 if 'prompt' in _toollist(ui, tool, "check"):
518 checked = True
519 if ui.promptchoice(_("was merge of '%s' successful (yn)?"
520 "$$ &Yes $$ &No") % fd, 1):
521 r = 1
522
523 if not r and not checked and (_toolbool(ui, tool, "checkchanged") or
524 'changed' in _toollist(ui, tool, "check")):
525 if filecmp.cmp(a, back):
526 if ui.promptchoice(_(" output file %s appears unchanged\n"
527 "was merge successful (yn)?"
528 "$$ &Yes $$ &No") % fd, 1):
529 r = 1
530
531 if _toolbool(ui, tool, "fixeol"):
532 _matcheol(a, back)
533
534 if r:
535 if onfailure:
536 ui.warn(onfailure % fd)
537 else:
538 util.unlink(back)
539
540 util.unlink(b)
541 util.unlink(c)
542 return r
543
544 546 # tell hggettext to extract docstrings from these functions:
545 547 i18nfunctions = internals.values()
General Comments 0
You need to be logged in to leave comments. Login now