diff options
author | Andrey Loskutov <loskutov@gmx.de> | 2022-05-27 00:59:22 -0400 |
---|---|---|
committer | Gerrit Code Review @ Eclipse.org <gerrit@eclipse.org> | 2022-05-27 00:59:22 -0400 |
commit | 5828ca160233550bc8f6d05ec9819c46fbffe5f3 (patch) | |
tree | fef2311db18500d88f6a86ee3b504c5c5867524b /org.eclipse.jgit | |
parent | fde3e8b5d880862174b9c32b5cf2ad288007deba (diff) | |
parent | 85734356351ec2df4067b2472a37f6d9bcbb7350 (diff) | |
download | jgit-5828ca160233550bc8f6d05ec9819c46fbffe5f3.tar.gz jgit-5828ca160233550bc8f6d05ec9819c46fbffe5f3.zip |
Merge "Add command line support for "git mergetool""
Diffstat (limited to 'org.eclipse.jgit')
8 files changed, 573 insertions, 52 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineMergeTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineMergeTool.java new file mode 100644 index 0000000000..3a22124328 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/CommandLineMergeTool.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2018-2022, Andre Bossert <andre.bossert@siemens.com> + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.diffmergetool; + +/** + * Pre-defined merge tools. + * + * Adds same merge tools as also pre-defined in C-Git see "git-core\mergetools\" + * see links to command line parameter description for the tools + * + * <pre> + * araxis + * bc + * bc3 + * codecompare + * deltawalker + * diffmerge + * diffuse + * ecmerge + * emerge + * examdiff + * guiffy + * gvimdiff + * gvimdiff2 + * gvimdiff3 + * kdiff3 + * kompare + * meld + * opendiff + * p4merge + * tkdiff + * tortoisemerge + * vimdiff + * vimdiff2 + * vimdiff3 + * winmerge + * xxdiff + * </pre> + * + */ +@SuppressWarnings("nls") +public enum CommandLineMergeTool { + /** + * See: <a href= + * "https://www.araxis.com/merge/documentation-windows/command-line.en">https://www.araxis.com/merge/documentation-windows/command-line.en</a> + */ + araxis("compare", + "-wait -merge -3 -a1 \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", + "-wait -2 \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", + false), + /** + * See: <a href= + * "https://www.scootersoftware.com/v4help/index.html?command_line_reference.html">https://www.scootersoftware.com/v4help/index.html?command_line_reference.html</a> + */ + bc("bcomp", "\"$LOCAL\" \"$REMOTE\" \"$BASE\" --mergeoutput=\"$MERGED\"", + "\"$LOCAL\" \"$REMOTE\" --mergeoutput=\"$MERGED\"", + false), + /** + * See: <a href= + * "https://www.scootersoftware.com/v4help/index.html?command_line_reference.html">https://www.scootersoftware.com/v4help/index.html?command_line_reference.html</a> + */ + bc3("bcompare", bc), + /** + * See: <a href= + * "https://www.devart.com/codecompare/docs/index.html?merging_via_command_line.htm">https://www.devart.com/codecompare/docs/index.html?merging_via_command_line.htm</a> + */ + codecompare("CodeMerge", + "-MF=\"$LOCAL\" -TF=\"$REMOTE\" -BF=\"$BASE\" -RF=\"$MERGED\"", + "-MF=\"$LOCAL\" -TF=\"$REMOTE\" -RF=\"$MERGED\"", + false), + /** + * See: <a href= + * "https://www.deltawalker.com/integrate/command-line">https://www.deltawalker.com/integrate/command-line</a> + * <p> + * Hint: $(pwd) command must be defined + * </p> + */ + deltawalker("DeltaWalker", + "\"$LOCAL\" \"$REMOTE\" \"$BASE\" -pwd=\"$(pwd)\" -merged=\"$MERGED\"", + "\"$LOCAL\" \"$REMOTE\" -pwd=\"$(pwd)\" -merged=\"$MERGED\"", + true), + /** + * See: <a href= + * "https://sourcegear.com/diffmerge/webhelp/sec__clargs__diff.html">https://sourcegear.com/diffmerge/webhelp/sec__clargs__diff.html</a> + */ + diffmerge("diffmerge", //$NON-NLS-1$ + "--merge --result=\"$MERGED\" \"$LOCAL\" \"$BASE\" \"$REMOTE\"", + "--merge --result=\"$MERGED\" \"$LOCAL\" \"$REMOTE\"", + true), + /** + * See: <a href= + * "http://diffuse.sourceforge.net/manual.html#introduction-usage">http://diffuse.sourceforge.net/manual.html#introduction-usage</a> + * <p> + * Hint: check the ' | cat' for the call + * </p> + */ + diffuse("diffuse", "\"$LOCAL\" \"$MERGED\" \"$REMOTE\" \"$BASE\"", + "\"$LOCAL\" \"$MERGED\" \"$REMOTE\"", false), + /** + * See: <a href= + * "http://www.elliecomputing.com/en/OnlineDoc/ecmerge_en/44205167.asp">http://www.elliecomputing.com/en/OnlineDoc/ecmerge_en/44205167.asp</a> + */ + ecmerge("ecmerge", + "--default --mode=merge3 \"$BASE\" \"$LOCAL\" \"$REMOTE\" --to=\"$MERGED\"", + "--default --mode=merge2 \"$LOCAL\" \"$REMOTE\" --to=\"$MERGED\"", + false), + /** + * See: <a href= + * "https://www.gnu.org/software/emacs/manual/html_node/emacs/Overview-of-Emerge.html">https://www.gnu.org/software/emacs/manual/html_node/emacs/Overview-of-Emerge.html</a> + * <p> + * Hint: $(basename) command must be defined + * </p> + */ + emerge("emacs", + "-f emerge-files-with-ancestor-command \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$(basename \"$MERGED\")\"", + "-f emerge-files-command \"$LOCAL\" \"$REMOTE\" \"$(basename \"$MERGED\")\"", + true), + /** + * See: <a href= + * "https://www.prestosoft.com/ps.asp?page=htmlhelp/edp/command_line_options">https://www.prestosoft.com/ps.asp?page=htmlhelp/edp/command_line_options</a> + */ + examdiff("ExamDiff", + "-merge \"$LOCAL\" \"$BASE\" \"$REMOTE\" -o:\"$MERGED\" -nh", + "-merge \"$LOCAL\" \"$REMOTE\" -o:\"$MERGED\" -nh", + false), + /** + * See: <a href= + * "https://www.guiffy.com/help/GuiffyHelp/GuiffyCmd.html">https://www.guiffy.com/help/GuiffyHelp/GuiffyCmd.html</a> + */ + guiffy("guiffy", "-s \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\"", + "-m \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", true), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + gvimdiff("gvim", + "-f -d -c '4wincmd w | wincmd J' \"$LOCAL\" \"$BASE\" \"$REMOTE\" \"$MERGED\"", + "-f -d -c 'wincmd l' \"$LOCAL\" \"$MERGED\" \"$REMOTE\"", + true), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + gvimdiff2("gvim", "-f -d -c 'wincmd l' \"$LOCAL\" \"$MERGED\" \"$REMOTE\"", + "-f -d -c 'wincmd l' \"$LOCAL\" \"$MERGED\" \"$REMOTE\"", true), + /** + * See: <a href= "http://vimdoc.sourceforge.net/htmldoc/diff.html"></a> + */ + gvimdiff3("gvim", + "-f -d -c 'hid | hid | hid' \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\"", + "-f -d -c 'hid | hid' \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", true), + /** + * See: <a href= + * "http://kdiff3.sourceforge.net/doc/documentation.html">http://kdiff3.sourceforge.net/doc/documentation.html</a> + */ + kdiff3("kdiff3", + "--auto --L1 \"$MERGED (Base)\" --L2 \"$MERGED (Local)\" --L3 \"$MERGED (Remote)\" -o \"$MERGED\" \"$BASE\" \"$LOCAL\" \"$REMOTE\"", + "--auto --L1 \"$MERGED (Local)\" --L2 \"$MERGED (Remote)\" -o \"$MERGED\" \"$LOCAL\" \"$REMOTE\"", + true), + /** + * See: <a href= + * "http://meldmerge.org/help/file-mode.html">http://meldmerge.org/help/file-mode.html</a> + * <p> + * Hint: use meld with output option only (new versions) + * </p> + */ + meld("meld", "--output=\"$MERGED\" \"$LOCAL\" \"$BASE\" \"$REMOTE\"", + "\"$LOCAL\" \"$MERGED\" \"$REMOTE\"", + false), + /** + * See: <a href= + * "http://www.manpagez.com/man/1/opendiff/">http://www.manpagez.com/man/1/opendiff/</a> + * <p> + * Hint: check the ' | cat' for the call + * </p> + */ + opendiff("opendiff", + "\"$LOCAL\" \"$REMOTE\" -ancestor \"$BASE\" -merge \"$MERGED\"", + "\"$LOCAL\" \"$REMOTE\" -merge \"$MERGED\"", + false), + /** + * See: <a href= + * "https://www.perforce.com/manuals/v15.1/cmdref/p4_merge.html">https://www.perforce.com/manuals/v15.1/cmdref/p4_merge.html</a> + * <p> + * Hint: check how to fix "no base present" / create_virtual_base problem + * </p> + */ + p4merge("p4merge", "\"$BASE\" \"$REMOTE\" \"$LOCAL\" \"$MERGED\"", + "\"$REMOTE\" \"$LOCAL\" \"$MERGED\"", false), + /** + * See: <a href= + * "http://linux.math.tifr.res.in/manuals/man/tkdiff.html">http://linux.math.tifr.res.in/manuals/man/tkdiff.html</a> + */ + tkdiff("tkdiff", "-a \"$BASE\" -o \"$MERGED\" \"$LOCAL\" \"$REMOTE\"", + "-o \"$MERGED\" \"$LOCAL\" \"$REMOTE\"", + true), + /** + * See: <a href= + * "https://tortoisegit.org/docs/tortoisegitmerge/tme-automation.html#tme-automation-basics">https://tortoisegit.org/docs/tortoisegitmerge/tme-automation.html#tme-automation-basics</a> + * <p> + * Hint: merge without base is not supported + * </p> + * <p> + * Hint: cannot diff + * </p> + */ + tortoisegitmerge("tortoisegitmerge", + "-base \"$BASE\" -mine \"$LOCAL\" -theirs \"$REMOTE\" -merged \"$MERGED\"", + null, false), + /** + * See: <a href= + * "https://tortoisegit.org/docs/tortoisegitmerge/tme-automation.html#tme-automation-basics">https://tortoisegit.org/docs/tortoisegitmerge/tme-automation.html#tme-automation-basics</a> + * <p> + * Hint: merge without base is not supported + * </p> + * <p> + * Hint: cannot diff + * </p> + */ + tortoisemerge("tortoisemerge", + "-base:\"$BASE\" -mine:\"$LOCAL\" -theirs:\"$REMOTE\" -merged:\"$MERGED\"", + null, false), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + vimdiff("vim", gvimdiff), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + vimdiff2("vim", gvimdiff2), + /** + * See: <a href= + * "http://vimdoc.sourceforge.net/htmldoc/diff.html">http://vimdoc.sourceforge.net/htmldoc/diff.html</a> + */ + vimdiff3("vim", gvimdiff3), + /** + * See: <a href= + * "http://manual.winmerge.org/Command_line.html">http://manual.winmerge.org/Command_line.html</a> + * <p> + * Hint: check how 'mergetool_find_win32_cmd "WinMergeU.exe" "WinMerge"' + * works + * </p> + */ + winmerge("WinMergeU", + "-u -e -dl Local -dr Remote \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", + "-u -e -dl Local -dr Remote \"$LOCAL\" \"$REMOTE\" \"$MERGED\"", + false), + /** + * See: <a href= + * "http://furius.ca/xxdiff/doc/xxdiff-doc.html">http://furius.ca/xxdiff/doc/xxdiff-doc.html</a> + */ + xxdiff("xxdiff", + "-X --show-merged-pane -R 'Accel.SaveAsMerged: \"Ctrl+S\"' -R 'Accel.Search: \"Ctrl+F\"' -R 'Accel.SearchForward: \"Ctrl+G\"' --merged-file \"$MERGED\" \"$LOCAL\" \"$BASE\" \"$REMOTE\"", + "-X -R 'Accel.SaveAsMerged: \"Ctrl+S\"' -R 'Accel.Search: \"Ctrl+F\"' -R 'Accel.SearchForward: \"Ctrl+G\"' --merged-file \"$MERGED\" \"$LOCAL\" \"$REMOTE\"", + false); + + CommandLineMergeTool(String path, String parametersWithBase, + String parametersWithoutBase, + boolean exitCodeTrustable) { + this.path = path; + this.parametersWithBase = parametersWithBase; + this.parametersWithoutBase = parametersWithoutBase; + this.exitCodeTrustable = exitCodeTrustable; + } + + CommandLineMergeTool(CommandLineMergeTool from) { + this(from.getPath(), from.getParameters(true), + from.getParameters(false), from.isExitCodeTrustable()); + } + + CommandLineMergeTool(String path, CommandLineMergeTool from) { + this(path, from.getParameters(true), from.getParameters(false), + from.isExitCodeTrustable()); + } + + private final String path; + + private final String parametersWithBase; + + private final String parametersWithoutBase; + + private final boolean exitCodeTrustable; + + /** + * @return path + */ + public String getPath() { + return path; + } + + /** + * @param withBase + * return parameters with base present? + * @return parameters with or without base present + */ + public String getParameters(boolean withBase) { + if (withBase) { + return parametersWithBase; + } + return parametersWithoutBase; + } + + /** + * @return parameters + */ + public boolean isExitCodeTrustable() { + return exitCodeTrustable; + } + + /** + * @return true if command with base present is valid, false otherwise + */ + public boolean canMergeWithoutBasePresent() { + return parametersWithoutBase != null; + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java index b15cbdc34a..2f2b9de818 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2021, Andre Bossert <andre.bossert@siemens.com> + * Copyright (C) 2018-2022, Andre Bossert <andre.bossert@siemens.com> * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -56,8 +56,7 @@ public class DiffTools { * @param remoteFile * the remote file element * @param mergedFilePath - * the path of 'merged' file, it equals local or remote path for - * difftool + * the path of 'merged' file, it equals local or remote path * @param toolName * the selected tool name (can be null) * @param prompt @@ -66,7 +65,7 @@ public class DiffTools { * the GUI option * @param trustExitCode * the "trust exit code" option - * @return the return code from executed tool + * @return the execution result from tool * @throws ToolException */ public ExecutionResult compare(Repository repo, FileElement localFile, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalMergeTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalMergeTool.java index bcc749adad..0c3ddf9afe 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalMergeTool.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalMergeTool.java @@ -10,6 +10,8 @@ package org.eclipse.jgit.internal.diffmergetool; +import org.eclipse.jgit.lib.internal.BooleanTriState; + /** * The merge tool interface. */ @@ -18,6 +20,14 @@ public interface ExternalMergeTool extends ExternalDiffTool { /** * @return the tool "trust exit code" option */ - boolean isTrustExitCode(); + BooleanTriState getTrustExitCode(); + + /** + * @param withBase + * get command with base present (true) or without base present + * (false) + * @return the tool command + */ + String getCommand(boolean withBase); } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeToolConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeToolConfig.java index e912822613..9be20b75ad 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeToolConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeToolConfig.java @@ -10,13 +10,24 @@ package org.eclipse.jgit.internal.diffmergetool; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_GUITOOL; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_KEEP_BACKUP; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_KEEP_TEMPORARIES; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TRUST_EXIT_CODE; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WRITE_TO_TEMP; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGETOOL_SECTION; +import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_MERGE_SECTION; + import java.util.HashMap; import java.util.Map; import java.util.Set; import org.eclipse.jgit.lib.Config; import org.eclipse.jgit.lib.Config.SectionParser; -import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.internal.BooleanTriState; /** @@ -42,31 +53,27 @@ public class MergeToolConfig { private final Map<String, ExternalMergeTool> tools; private MergeToolConfig(Config rc) { - toolName = rc.getString(ConfigConstants.CONFIG_MERGE_SECTION, null, - ConfigConstants.CONFIG_KEY_TOOL); - guiToolName = rc.getString(ConfigConstants.CONFIG_MERGE_SECTION, null, - ConfigConstants.CONFIG_KEY_GUITOOL); - prompt = rc.getBoolean(ConfigConstants.CONFIG_MERGETOOL_SECTION, - ConfigConstants.CONFIG_KEY_PROMPT, true); - keepBackup = rc.getBoolean(ConfigConstants.CONFIG_MERGETOOL_SECTION, - ConfigConstants.CONFIG_KEY_KEEP_BACKUP, true); - keepTemporaries = rc.getBoolean( - ConfigConstants.CONFIG_MERGETOOL_SECTION, - ConfigConstants.CONFIG_KEY_KEEP_TEMPORARIES, false); - writeToTemp = rc.getBoolean(ConfigConstants.CONFIG_MERGETOOL_SECTION, - ConfigConstants.CONFIG_KEY_WRITE_TO_TEMP, false); + toolName = rc.getString(CONFIG_MERGE_SECTION, null, CONFIG_KEY_TOOL); + guiToolName = rc.getString(CONFIG_MERGE_SECTION, null, + CONFIG_KEY_GUITOOL); + prompt = rc.getBoolean(CONFIG_MERGETOOL_SECTION, toolName, + CONFIG_KEY_PROMPT, true); + keepBackup = rc.getBoolean(CONFIG_MERGETOOL_SECTION, + CONFIG_KEY_KEEP_BACKUP, true); + keepTemporaries = rc.getBoolean(CONFIG_MERGETOOL_SECTION, + CONFIG_KEY_KEEP_TEMPORARIES, false); + writeToTemp = rc.getBoolean(CONFIG_MERGETOOL_SECTION, + CONFIG_KEY_WRITE_TO_TEMP, false); tools = new HashMap<>(); - Set<String> subsections = rc - .getSubsections(ConfigConstants.CONFIG_MERGETOOL_SECTION); + Set<String> subsections = rc.getSubsections(CONFIG_MERGETOOL_SECTION); for (String name : subsections) { - String cmd = rc.getString(ConfigConstants.CONFIG_MERGETOOL_SECTION, - name, ConfigConstants.CONFIG_KEY_CMD); - String path = rc.getString(ConfigConstants.CONFIG_MERGETOOL_SECTION, - name, ConfigConstants.CONFIG_KEY_PATH); + String cmd = rc.getString(CONFIG_MERGETOOL_SECTION, name, + CONFIG_KEY_CMD); + String path = rc.getString(CONFIG_MERGETOOL_SECTION, name, + CONFIG_KEY_PATH); BooleanTriState trustExitCode = BooleanTriState.FALSE; - String trustStr = rc.getString( - ConfigConstants.CONFIG_MERGETOOL_SECTION, name, - ConfigConstants.CONFIG_KEY_TRUST_EXIT_CODE); + String trustStr = rc.getString(CONFIG_MERGETOOL_SECTION, name, + CONFIG_KEY_TRUST_EXIT_CODE); if (trustStr != null) { trustExitCode = Boolean.valueOf(trustStr).booleanValue() ? BooleanTriState.TRUE @@ -75,9 +82,8 @@ public class MergeToolConfig { trustExitCode = BooleanTriState.UNSET; } if ((cmd != null) || (path != null)) { - tools.put(name, - new UserDefinedMergeTool(name, path, cmd, - trustExitCode)); + tools.put(name, new UserDefinedMergeTool(name, path, cmd, + trustExitCode)); } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java index bb5d73eeb2..cefefb8e75 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java @@ -9,17 +9,21 @@ */ package org.eclipse.jgit.internal.diffmergetool; +import java.io.File; import java.util.Map; import java.util.Set; import java.util.TreeMap; +import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.internal.BooleanTriState; +import org.eclipse.jgit.util.FS.ExecutionResult; /** * Manages merge tools. */ public class MergeTools { + private final MergeToolConfig config; private final Map<String, ExternalMergeTool> predefinedTools; @@ -33,10 +37,12 @@ public class MergeTools { public MergeTools(Repository repo) { config = repo.getConfig().get(MergeToolConfig.KEY); predefinedTools = setupPredefinedTools(); - userDefinedTools = setupUserDefinedTools(); + userDefinedTools = setupUserDefinedTools(config, predefinedTools); } /** + * @param repo + * the repository * @param localFile * the local file element * @param remoteFile @@ -49,19 +55,43 @@ public class MergeTools { * the selected tool name (can be null) * @param prompt * the prompt option - * @param trustExitCode - * the "trust exit code" option * @param gui * the GUI option * @return the execution result from tool * @throws ToolException */ - public int merge(String localFile, - String remoteFile, String baseFile, String mergedFilePath, - String toolName, BooleanTriState prompt, BooleanTriState gui, - BooleanTriState trustExitCode) + public ExecutionResult merge(Repository repo, FileElement localFile, + FileElement remoteFile, FileElement baseFile, String mergedFilePath, + String toolName, BooleanTriState prompt, BooleanTriState gui) throws ToolException { - return 0; + ExternalMergeTool tool = guessTool(toolName, gui); + try { + File workingDir = repo.getWorkTree(); + String localFilePath = localFile.getFile().getPath(); + String remoteFilePath = remoteFile.getFile().getPath(); + String baseFilePath = baseFile.getFile().getPath(); + String command = tool.getCommand(); + command = command.replace("$LOCAL", localFilePath); //$NON-NLS-1$ + command = command.replace("$REMOTE", remoteFilePath); //$NON-NLS-1$ + command = command.replace("$MERGED", mergedFilePath); //$NON-NLS-1$ + command = command.replace("$BASE", baseFilePath); //$NON-NLS-1$ + Map<String, String> env = new TreeMap<>(); + env.put(Constants.GIT_DIR_KEY, + repo.getDirectory().getAbsolutePath()); + env.put("LOCAL", localFilePath); //$NON-NLS-1$ + env.put("REMOTE", remoteFilePath); //$NON-NLS-1$ + env.put("MERGED", mergedFilePath); //$NON-NLS-1$ + env.put("BASE", baseFilePath); //$NON-NLS-1$ + boolean trust = tool.getTrustExitCode() == BooleanTriState.TRUE; + CommandExecutor cmdExec = new CommandExecutor(repo.getFS(), trust); + return cmdExec.run(command, workingDir, env); + } catch (Exception e) { + throw new ToolException(e); + } finally { + localFile.cleanTemporaries(); + remoteFile.cleanTemporaries(); + baseFile.cleanTemporaries(); + } } /** @@ -99,7 +129,7 @@ public class MergeTools { */ public String getDefaultToolName(BooleanTriState gui) { return gui != BooleanTriState.UNSET ? "my_gui_tool" //$NON-NLS-1$ - : "my_default_toolname"; //$NON-NLS-1$ + : config.getDefaultToolName(); } /** @@ -109,11 +139,58 @@ public class MergeTools { return config.isPrompt(); } + private ExternalMergeTool guessTool(String toolName, BooleanTriState gui) + throws ToolException { + if ((toolName == null) || toolName.isEmpty()) { + toolName = getDefaultToolName(gui); + } + ExternalMergeTool tool = getTool(toolName); + if (tool == null) { + throw new ToolException("Unknown diff tool " + toolName); //$NON-NLS-1$ + } + return tool; + } + + private ExternalMergeTool getTool(final String name) { + ExternalMergeTool tool = userDefinedTools.get(name); + if (tool == null) { + tool = predefinedTools.get(name); + } + return tool; + } + private Map<String, ExternalMergeTool> setupPredefinedTools() { - return new TreeMap<>(); + Map<String, ExternalMergeTool> tools = new TreeMap<>(); + for (CommandLineMergeTool tool : CommandLineMergeTool.values()) { + tools.put(tool.name(), new PreDefinedMergeTool(tool)); + } + return tools; } - private Map<String, ExternalMergeTool> setupUserDefinedTools() { - return new TreeMap<>(); + private Map<String, ExternalMergeTool> setupUserDefinedTools( + MergeToolConfig cfg, Map<String, ExternalMergeTool> predefTools) { + Map<String, ExternalMergeTool> tools = new TreeMap<>(); + Map<String, ExternalMergeTool> userTools = cfg.getTools(); + for (String name : userTools.keySet()) { + ExternalMergeTool userTool = userTools.get(name); + // if mergetool.<name>.cmd is defined we have user defined tool + if (userTool.getCommand() != null) { + tools.put(name, userTool); + } else if (userTool.getPath() != null) { + // if mergetool.<name>.path is defined we just overload the path + // of predefined tool + PreDefinedMergeTool predefTool = (PreDefinedMergeTool) predefTools + .get(name); + if (predefTool != null) { + predefTool.setPath(userTool.getPath()); + if (userTool.getTrustExitCode() != BooleanTriState.UNSET) { + predefTool + .setTrustExitCode(userTool.getTrustExitCode()); + } + } + } + } + return tools; } -}
\ No newline at end of file + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedMergeTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedMergeTool.java new file mode 100644 index 0000000000..2c64c16667 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/PreDefinedMergeTool.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2018-2022, Andre Bossert <andre.bossert@siemens.com> + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.internal.diffmergetool; + +import org.eclipse.jgit.lib.internal.BooleanTriState; + +/** + * The pre-defined merge tool. + */ +public class PreDefinedMergeTool extends UserDefinedMergeTool { + + /** + * the tool parameters without base + */ + private final String parametersWithoutBase; + + /** + * Creates the pre-defined merge tool + * + * @param name + * the name + * @param path + * the path + * @param parametersWithBase + * the tool parameters that are used together with path as + * command and "base is present" ($BASE) + * @param parametersWithoutBase + * the tool parameters that are used together with path as + * command and "base is present" ($BASE) + * @param trustExitCode + * the "trust exit code" option + */ + public PreDefinedMergeTool(String name, String path, + String parametersWithBase, String parametersWithoutBase, + BooleanTriState trustExitCode) { + super(name, path, parametersWithBase, trustExitCode); + this.parametersWithoutBase = parametersWithoutBase; + } + + /** + * Creates the pre-defined merge tool + * + * @param tool + * the command line merge tool + * + */ + public PreDefinedMergeTool(CommandLineMergeTool tool) { + this(tool.name(), tool.getPath(), tool.getParameters(true), + tool.getParameters(false), + tool.isExitCodeTrustable() ? BooleanTriState.TRUE + : BooleanTriState.FALSE); + } + + /** + * @param trustExitCode + * the "trust exit code" option + */ + @Override + public void setTrustExitCode(BooleanTriState trustExitCode) { + super.setTrustExitCode(trustExitCode); + } + + /** + * @return the tool command (with base present) + */ + @Override + public String getCommand() { + return getCommand(true); + } + + /** + * @param withBase + * get command with base present (true) or without base present + * (false) + * @return the tool command + */ + @Override + public String getCommand(boolean withBase) { + return getPath() + " " //$NON-NLS-1$ + + (withBase ? super.getCommand() : parametersWithoutBase); + } + +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedMergeTool.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedMergeTool.java index df4d8cb8c6..1dd2f0d793 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedMergeTool.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedMergeTool.java @@ -21,7 +21,7 @@ public class UserDefinedMergeTool extends UserDefinedDiffTool /** * the merge tool "trust exit code" option */ - private final BooleanTriState trustExitCode; + private BooleanTriState trustExitCode; /** * Creates the merge tool @@ -40,20 +40,30 @@ public class UserDefinedMergeTool extends UserDefinedDiffTool super(name, path, cmd); this.trustExitCode = trustExitCode; } - /** * @return the "trust exit code" flag */ @Override - public boolean isTrustExitCode() { - return trustExitCode == BooleanTriState.TRUE; + public BooleanTriState getTrustExitCode() { + return trustExitCode; } /** - * @return the "trust exit code" option + * @param trustExitCode + * the new "trust exit code" flag */ - public BooleanTriState getTrustExitCode() { - return trustExitCode; + protected void setTrustExitCode(BooleanTriState trustExitCode) { + this.trustExitCode = trustExitCode; } + /** + * @param withBase + * not used, because user-defined merge tool can only define one + * cmd -> it must handle with and without base present (empty) + * @return the tool command + */ + @Override + public String getCommand(boolean withBase) { + return getCommand(); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java index e982a33b29..29c66f5165 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -10,6 +10,7 @@ * * SPDX-License-Identifier: BSD-3-Clause */ + package org.eclipse.jgit.lib; /** @@ -66,7 +67,7 @@ public final class ConfigConstants { public static final String CONFIG_KEY_TRUST_EXIT_CODE = "trustExitCode"; /** - * The "cmd" key within "difftool.*." section + * The "cmd" key within "difftool.*." or "mergetool.*." section * * @since 6.1 */ |