491 tool, toolpath, binary, symlink = toolconf |
491 tool, toolpath, binary, symlink = toolconf |
492 if fcd.isabsent() or fco.isabsent(): |
492 if fcd.isabsent() or fco.isabsent(): |
493 repo.ui.warn(_('warning: %s cannot merge change/delete conflict ' |
493 repo.ui.warn(_('warning: %s cannot merge change/delete conflict ' |
494 'for %s\n') % (tool, fcd.path())) |
494 'for %s\n') % (tool, fcd.path())) |
495 return False, 1, None |
495 return False, 1, None |
496 unused, b, c, back = files |
496 unused, unused, unused, back = files |
497 a = _workingpath(repo, fcd) |
497 a = _workingpath(repo, fcd) |
498 out = "" |
498 b, c = _maketempfiles(repo, fco, fca) |
499 env = {'HG_FILE': fcd.path(), |
499 try: |
500 'HG_MY_NODE': short(mynode), |
500 out = "" |
501 'HG_OTHER_NODE': str(fco.changectx()), |
501 env = {'HG_FILE': fcd.path(), |
502 'HG_BASE_NODE': str(fca.changectx()), |
502 'HG_MY_NODE': short(mynode), |
503 'HG_MY_ISLINK': 'l' in fcd.flags(), |
503 'HG_OTHER_NODE': str(fco.changectx()), |
504 'HG_OTHER_ISLINK': 'l' in fco.flags(), |
504 'HG_BASE_NODE': str(fca.changectx()), |
505 'HG_BASE_ISLINK': 'l' in fca.flags(), |
505 'HG_MY_ISLINK': 'l' in fcd.flags(), |
506 } |
506 'HG_OTHER_ISLINK': 'l' in fco.flags(), |
507 |
507 'HG_BASE_ISLINK': 'l' in fca.flags(), |
508 ui = repo.ui |
508 } |
509 |
509 ui = repo.ui |
510 args = _toolstr(ui, tool, "args", '$local $base $other') |
510 |
511 if "$output" in args: |
511 args = _toolstr(ui, tool, "args", '$local $base $other') |
512 out, a = a, back # read input from backup, write to original |
512 if "$output" in args: |
513 replace = {'local': a, 'base': b, 'other': c, 'output': out} |
513 out, a = a, back # read input from backup, write to original |
514 args = util.interpolate(r'\$', replace, args, |
514 replace = {'local': a, 'base': b, 'other': c, 'output': out} |
515 lambda s: util.shellquote(util.localpath(s))) |
515 args = util.interpolate(r'\$', replace, args, |
516 cmd = toolpath + ' ' + args |
516 lambda s: util.shellquote(util.localpath(s))) |
517 if _toolbool(ui, tool, "gui"): |
517 cmd = toolpath + ' ' + args |
518 repo.ui.status(_('running merge tool %s for file %s\n') % |
518 if _toolbool(ui, tool, "gui"): |
519 (tool, fcd.path())) |
519 repo.ui.status(_('running merge tool %s for file %s\n') % |
520 repo.ui.debug('launching merge tool: %s\n' % cmd) |
520 (tool, fcd.path())) |
521 r = ui.system(cmd, cwd=repo.root, environ=env, blockedtag='mergetool') |
521 repo.ui.debug('launching merge tool: %s\n' % cmd) |
522 repo.ui.debug('merge tool returned: %s\n' % r) |
522 r = ui.system(cmd, cwd=repo.root, environ=env, blockedtag='mergetool') |
523 return True, r, False |
523 repo.ui.debug('merge tool returned: %s\n' % r) |
|
524 return True, r, False |
|
525 finally: |
|
526 util.unlink(b) |
|
527 util.unlink(c) |
524 |
528 |
525 def _formatconflictmarker(repo, ctx, template, label, pad): |
529 def _formatconflictmarker(repo, ctx, template, label, pad): |
526 """Applies the given template to the ctx, prefixed by the label. |
530 """Applies the given template to the ctx, prefixed by the label. |
527 |
531 |
528 Pad is the minimum width of the label prefix, so that multiple markers |
532 Pad is the minimum width of the label prefix, so that multiple markers |
601 back = scmutil.origpath(ui, repo, a) |
605 back = scmutil.origpath(ui, repo, a) |
602 if premerge: |
606 if premerge: |
603 util.copyfile(a, back) |
607 util.copyfile(a, back) |
604 return back |
608 return back |
605 |
609 |
606 def _maketempfiles(repo, fcd, fco, fca): |
610 def _maketempfiles(repo, fco, fca): |
607 """Writes out `fco` and `fca` as temporary files, so an external merge |
611 """Writes out `fco` and `fca` as temporary files, so an external merge |
608 tool may use them. |
612 tool may use them. |
609 |
|
610 `fcd` is returned as-is, by convention, because it currently doubles as both |
|
611 the local version and merge destination. |
|
612 """ |
613 """ |
613 def temp(prefix, ctx): |
614 def temp(prefix, ctx): |
614 fullbase, ext = os.path.splitext(ctx.path()) |
615 fullbase, ext = os.path.splitext(ctx.path()) |
615 pre = "%s~%s." % (os.path.basename(fullbase), prefix) |
616 pre = "%s~%s." % (os.path.basename(fullbase), prefix) |
616 (fd, name) = tempfile.mkstemp(prefix=pre, suffix=ext) |
617 (fd, name) = tempfile.mkstemp(prefix=pre, suffix=ext) |
618 f = os.fdopen(fd, pycompat.sysstr("wb")) |
619 f = os.fdopen(fd, pycompat.sysstr("wb")) |
619 f.write(data) |
620 f.write(data) |
620 f.close() |
621 f.close() |
621 return name |
622 return name |
622 |
623 |
623 a = repo.wjoin(fcd.path()) |
|
624 b = temp("base", fca) |
624 b = temp("base", fca) |
625 c = temp("other", fco) |
625 c = temp("other", fco) |
626 |
626 |
627 return a, b, c |
627 return b, c |
628 |
628 |
629 def _filemerge(premerge, repo, mynode, orig, fcd, fco, fca, labels=None): |
629 def _filemerge(premerge, repo, mynode, orig, fcd, fco, fca, labels=None): |
630 """perform a 3-way merge in the working directory |
630 """perform a 3-way merge in the working directory |
631 |
631 |
632 premerge = whether this is a premerge |
632 premerge = whether this is a premerge |