[PATCH] filemerge: support passing python script to custom merge-tools

tom_hindle at sil.org tom_hindle at sil.org
Tue May 1 19:51:01 UTC 2018


# HG changeset patch
# User hindlemail <tom_hindle at sil.org>
# Date 1523988043 21600
#      Tue Apr 17 12:00:43 2018 -0600
# Node ID 279036df5b14e08c09e95222b2dc61b279b5733a
# Parent  92213f6745ed6f2c50feca9a2261b6f33a9a32fa
filemerge: support passing python script to custom merge-tools

Eliminates the need to specify a python execuatable, which may not exist on
system. Additionally launching script inprocess aids portablity on systems that
can't execute python via the shell.
example usage "merge-tools.myTool.executable=python:c:\myTool.py"

diff -r 92213f6745ed -r 279036df5b14 mercurial/filemerge.py
--- a/mercurial/filemerge.py	Sun Mar 04 15:29:41 2018 -0500
+++ b/mercurial/filemerge.py	Tue Apr 17 12:00:43 2018 -0600
@@ -11,6 +11,7 @@
 import os
 import re
 import shutil
+import sys
 import tempfile
 
 from .i18n import _
@@ -114,6 +115,9 @@
 def _findtool(ui, tool):
     if tool in internals:
         return tool
+    cmd = _toolstr(ui, tool, "executable", tool)
+    if cmd.startswith('python:'):
+        return cmd
     return findexternaltool(ui, tool)
 
 def findexternaltool(ui, tool):
@@ -325,7 +329,7 @@
         return filectx
 
 def _premerge(repo, fcd, fco, fca, toolconf, files, labels=None):
-    tool, toolpath, binary, symlink = toolconf
+    tool, toolpath, binary, symlink, script = toolconf
     if symlink or fcd.isabsent() or fco.isabsent():
         return 1
     unused, unused, unused, back = files
@@ -361,7 +365,7 @@
     return 1 # continue merging
 
 def _mergecheck(repo, mynode, orig, fcd, fco, fca, toolconf):
-    tool, toolpath, binary, symlink = toolconf
+    tool, toolpath, binary, symlink, script = toolconf
     if symlink:
         repo.ui.warn(_('warning: internal %s cannot merge symlinks '
                        'for %s\n') % (tool, fcd.path()))
@@ -430,7 +434,7 @@
     Generic driver for _imergelocal and _imergeother
     """
     assert localorother is not None
-    tool, toolpath, binary, symlink = toolconf
+    tool, toolpath, binary, symlink, script = toolconf
     r = simplemerge.simplemerge(repo.ui, fcd, fca, fco, label=labels,
                                 localorother=localorother)
     return True, r
@@ -510,7 +514,7 @@
                                             'external merge tools')
 
 def _xmerge(repo, mynode, orig, fcd, fco, fca, toolconf, files, labels=None):
-    tool, toolpath, binary, symlink = toolconf
+    tool, toolpath, binary, symlink, script = toolconf
     if fcd.isabsent() or fco.isabsent():
         repo.ui.warn(_('warning: %s cannot merge change/delete conflict '
                        'for %s\n') % (tool, fcd.path()))
@@ -556,7 +560,17 @@
             repo.ui.status(_('running merge tool %s for file %s\n') %
                            (tool, fcd.path()))
         repo.ui.debug('launching merge tool: %s\n' % cmd)
-        r = ui.system(cmd, cwd=repo.root, environ=env, blockedtag='mergetool')
+        if not script:
+            r = ui.system(cmd, cwd=repo.root, environ=env,
+                          blockedtag='mergetool')
+        else:
+            r = 0
+            try:
+                sys.argv = procutil.shellsplit(cmd)
+                execfile(procutil.shellsplit(toolpath)[0], {})
+            except Exception as err:
+                r = 1
+                repo.ui.debug('merge tool threw exception: %s\n' % err.args[0])
         repo.ui.debug('merge tool returned: %d\n' % r)
         return True, r, False
 
@@ -751,9 +765,13 @@
     symlink = 'l' in fcd.flags() + fco.flags()
     changedelete = fcd.isabsent() or fco.isabsent()
     tool, toolpath = _picktool(repo, ui, fd, binary, symlink, changedelete)
+    script = False
     if tool in internals and tool.startswith('internal:'):
         # normalize to new-style names (':merge' etc)
         tool = tool[len('internal'):]
+    if toolpath and procutil.shellsplit(toolpath)[0].startswith('python:'):
+        toolpath = toolpath.replace('python:', '')
+        script = True
     ui.debug("picked tool '%s' for %s (binary %s symlink %s changedelete %s)\n"
              % (tool, fd, pycompat.bytestr(binary), pycompat.bytestr(symlink),
                     pycompat.bytestr(changedelete)))
@@ -774,7 +792,7 @@
         precheck = None
         isexternal = True
 
-    toolconf = tool, toolpath, binary, symlink
+    toolconf = tool, toolpath, binary, symlink, script
 
     if mergetype == nomerge:
         r, deleted = func(repo, mynode, orig, fcd, fco, fca, toolconf, labels)


More information about the Mercurial-devel mailing list