merge-tools: look for merge-tools inside repo when relative path is supplied

Summary:
This is useful when writing merge tools that are checked into the repo. We can now reference a tool in the repo. Suggested use case:

  [merge-tools]
  mytool =
  mytool.executable = scripts/mytool.py

Reviewed By: quark-zju

Differential Revision: D17342897

fbshipit-source-id: ffdb160dfea8404721c4fc94fdfcab2d86cca08d
This commit is contained in:
Ron Mordechai 2019-09-18 07:10:31 -07:00 committed by Facebook Github Bot
parent 0dda4d7bae
commit 4d1577a9c2
2 changed files with 47 additions and 8 deletions

View File

@ -114,13 +114,13 @@ class absentfilectx(object):
return True
def _findtool(ui, tool):
def _findtool(ui, repo, tool):
if tool in internals:
return tool
return findexternaltool(ui, tool)
return _findexternaltoolwithreporoot(ui, repo, tool)
def findexternaltool(ui, tool):
def _findexternaltoolinternal(ui, tool):
for kn in ("regkey", "regkeyalt"):
k = _toolstr(ui, tool, kn)
if not k:
@ -130,7 +130,21 @@ def findexternaltool(ui, tool):
p = util.findexe(p + _toolstr(ui, tool, "regappend", ""))
if p:
return p
exe = _toolstr(ui, tool, "executable", tool)
return _toolstr(ui, tool, "executable", tool)
def findexternaltool(ui, tool):
return util.findexe(util.expandpath(_findexternaltoolinternal(ui, tool)))
def _findexternaltoolwithreporoot(ui, repo, tool):
"""Like findexternaltool, but try checking inside the repo for the tool
before looking in the path."""
exe = _findexternaltoolinternal(ui, tool)
if not os.path.isabs(exe):
path = repo.wvfs.join(exe)
if os.path.isfile(path) and util.isexec(path):
return path
return util.findexe(util.expandpath(exe))
@ -142,7 +156,7 @@ def _picktool(repo, ui, path, binary, symlink, changedelete):
tmsg = tool
if pat:
tmsg = _("%s (for pattern %s)") % (tool, pat)
if not _findtool(ui, tool):
if not _findtool(ui, repo, tool):
if pat: # explicitly requested tool deserves a warning
ui.warn(_("couldn't find merge tool %s\n") % tmsg)
else: # configured but non-existing tools are more silent
@ -165,7 +179,7 @@ def _picktool(repo, ui, path, binary, symlink, changedelete):
# forcemerge comes from command line arguments, highest priority
force = ui.config("ui", "forcemerge")
if force:
toolpath = _findtool(ui, force)
toolpath = _findtool(ui, repo, force)
if changedelete and not supportscd(toolpath):
return ":prompt", None
else:
@ -187,7 +201,7 @@ def _picktool(repo, ui, path, binary, symlink, changedelete):
for pat, tool in ui.configitems("merge-patterns"):
mf = match.match(repo.root, "", [pat])
if mf(path) and check(tool, pat, symlink, False, changedelete):
toolpath = _findtool(ui, tool)
toolpath = _findtool(ui, repo, tool)
return (tool, util.shellquote(toolpath))
# then merge tools
@ -211,7 +225,7 @@ def _picktool(repo, ui, path, binary, symlink, changedelete):
tools.append((None, "hgmerge")) # the old default, if found
for p, t in tools:
if check(t, None, symlink, binary, changedelete):
toolpath = _findtool(ui, t)
toolpath = _findtool(ui, repo, t)
return (t, util.shellquote(toolpath))
# internal merge or prompt as last resort

View File

@ -1138,6 +1138,31 @@ Merge with "echo mergeresult > $local":
# hg resolve --list
R f
Relative path in merge tool executable searches for tool inside repo before looking outside
$ beforemerge
[merge-tools]
false.whatever=
true.priority=1
true.executable=cat
# hg update -C 1
$ echo "echo hello, world!" > hello_world.sh
$ chmod +x hello_world.sh
$ hg stat
? hello_world.sh
$ hg merge -r 2 --config merge-tools.true.executable='hello_world.sh' --config merge-tools.true.args='> f'
merging f
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ rm -f hello_world.sh
$ aftermerge
# cat f
hello, world!
# hg stat
M f
# hg resolve --list
R f
Merge with "echo mergeresult > $output" - the variable is a bit magic:
$ beforemerge