comparison mercurial/filemerge.py @ 34052:96123bdea43e

filemerge: reduce creation of tempfiles until needed This restricts the creation of temporary files to just `_xmerge`, when we call an external tool. Differential Revision: https://phab.mercurial-scm.org/D403
author Phil Cohen <phillco@fb.com>
date Thu, 31 Aug 2017 11:28:59 -0700
parents 7558917f291e
children fe04c018eaac
comparison
equal deleted inserted replaced
34051:7558917f291e 34052:96123bdea43e
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
685 if onfailure: 685 if onfailure:
686 ui.warn(onfailure % fd) 686 ui.warn(onfailure % fd)
687 return True, 1, False 687 return True, 1, False
688 688
689 back = _makebackup(repo, ui, fcd, premerge) 689 back = _makebackup(repo, ui, fcd, premerge)
690 files = _maketempfiles(repo, fcd, fco, fca) + (back,) 690 files = (None, None, None, back)
691 r = 1 691 r = 1
692 try: 692 try:
693 markerstyle = ui.config('ui', 'mergemarkers') 693 markerstyle = ui.config('ui', 'mergemarkers')
694 if not labels: 694 if not labels:
695 labels = _defaultconflictlabels 695 labels = _defaultconflictlabels
713 713
714 return True, r, deleted 714 return True, r, deleted
715 finally: 715 finally:
716 if not r and back is not None: 716 if not r and back is not None:
717 util.unlink(back) 717 util.unlink(back)
718 util.unlink(files[1])
719 util.unlink(files[2])
720 718
721 def _check(repo, r, ui, tool, fcd, files): 719 def _check(repo, r, ui, tool, fcd, files):
722 fd = fcd.path() 720 fd = fcd.path()
723 unused, unused, unused, back = files 721 unused, unused, unused, back = files
724 722