Mercurial > public > mercurial-scm > hg-stable
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 |