diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java new file mode 100644 index 000000000..96fd1026c --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2020-2022, Simeon Andreev and others. + * + * 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 static org.junit.Assert.assertEquals; + +import java.util.Collections; +import java.util.Set; + +import org.eclipse.jgit.lib.internal.BooleanTriState; +import org.eclipse.jgit.storage.file.FileBasedConfig; +import org.junit.Test; + +/** + * Testing external merge tools. + */ +public class ExternalMergeToolTest extends ExternalToolTestCase { + + @Test + public void testToolNames() { + MergeTools manager = new MergeTools(db); + Set actualToolNames = manager.getToolNames(); + Set expectedToolNames = Collections.emptySet(); + assertEquals("Incorrect set of external diff tool names", + expectedToolNames, actualToolNames); + } + + @Test + public void testAllTools() { + MergeTools manager = new MergeTools(db); + Set actualToolNames = manager.getAvailableTools().keySet(); + Set expectedToolNames = Collections.emptySet(); + assertEquals("Incorrect set of available external diff tools", + expectedToolNames, actualToolNames); + } + + @Test + public void testUserDefinedTools() { + MergeTools manager = new MergeTools(db); + Set actualToolNames = manager.getUserDefinedTools().keySet(); + Set expectedToolNames = Collections.emptySet(); + assertEquals("Incorrect set of user defined external diff tools", + expectedToolNames, actualToolNames); + } + + @Test + public void testNotAvailableTools() { + MergeTools manager = new MergeTools(db); + Set actualToolNames = manager.getNotAvailableTools().keySet(); + Set expectedToolNames = Collections.emptySet(); + assertEquals("Incorrect set of not available external diff tools", + expectedToolNames, actualToolNames); + } + + @Test + public void testCompare() throws ToolException { + MergeTools manager = new MergeTools(db); + + String newPath = ""; + String oldPath = ""; + String newId = ""; + String oldId = ""; + String toolName = ""; + BooleanTriState prompt = BooleanTriState.UNSET; + BooleanTriState gui = BooleanTriState.UNSET; + BooleanTriState trustExitCode = BooleanTriState.UNSET; + + int expectedCompareResult = 0; + int compareResult = manager.merge(newPath, oldPath, newId, oldId, + toolName, prompt, gui, trustExitCode); + assertEquals("Incorrect compare result for external diff tool", + expectedCompareResult, compareResult); + } + + @Test + public void testDefaultTool() throws Exception { + FileBasedConfig config = db.getConfig(); + // the default diff tool is configured without a subsection + String subsection = null; + config.setString("diff", subsection, "tool", "customTool"); + + MergeTools manager = new MergeTools(db); + BooleanTriState gui = BooleanTriState.UNSET; + String defaultToolName = manager.getDefaultToolName(gui); + assertEquals( + "Expected configured difftool to be the default external diff tool", + "my_default_toolname", defaultToolName); + + gui = BooleanTriState.TRUE; + String defaultGuiToolName = manager.getDefaultToolName(gui); + assertEquals( + "Expected configured difftool to be the default external diff tool", + "my_gui_tool", defaultGuiToolName); + + config.setString("diff", subsection, "guitool", "customGuiTool"); + manager = new MergeTools(db); + defaultGuiToolName = manager.getDefaultToolName(gui); + assertEquals( + "Expected configured difftool to be the default external diff guitool", + "my_gui_tool", defaultGuiToolName); + } +} 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 new file mode 100644 index 000000000..bcc749ada --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalMergeTool.java @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018-2022, Andre Bossert + * + * 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; + +/** + * The merge tool interface. + */ +public interface ExternalMergeTool extends ExternalDiffTool { + + /** + * @return the tool "trust exit code" option + */ + boolean isTrustExitCode(); + +} 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 new file mode 100644 index 000000000..e91282261 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeToolConfig.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2018-2022, Andre Bossert + * + * 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 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; + +/** + * Keeps track of difftool related configuration options. + */ +public class MergeToolConfig { + + /** Key for {@link Config#get(SectionParser)}. */ + public static final Config.SectionParser KEY = MergeToolConfig::new; + + private final String toolName; + + private final String guiToolName; + + private final boolean prompt; + + private final boolean keepBackup; + + private final boolean keepTemporaries; + + private final boolean writeToTemp; + + private final Map 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); + tools = new HashMap<>(); + Set subsections = rc + .getSubsections(ConfigConstants.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); + BooleanTriState trustExitCode = BooleanTriState.FALSE; + String trustStr = rc.getString( + ConfigConstants.CONFIG_MERGETOOL_SECTION, name, + ConfigConstants.CONFIG_KEY_TRUST_EXIT_CODE); + if (trustStr != null) { + trustExitCode = Boolean.valueOf(trustStr).booleanValue() + ? BooleanTriState.TRUE + : BooleanTriState.FALSE; + } else { + trustExitCode = BooleanTriState.UNSET; + } + if ((cmd != null) || (path != null)) { + tools.put(name, + new UserDefinedMergeTool(name, path, cmd, + trustExitCode)); + } + } + } + + /** + * @return the default merge tool name (merge.tool) + */ + public String getDefaultToolName() { + return toolName; + } + + /** + * @return the default GUI merge tool name (merge.guitool) + */ + public String getDefaultGuiToolName() { + return guiToolName; + } + + /** + * @return the merge tool "prompt" option (mergetool.prompt) + */ + public boolean isPrompt() { + return prompt; + } + + /** + * @return the tool "keep backup" option + */ + public boolean isKeepBackup() { + return keepBackup; + } + + /** + * @return the tool "keepTemporaries" option + */ + public boolean isKeepTemporaries() { + return keepTemporaries; + } + + /** + * @return the tool "write to temp" option + */ + public boolean isWriteToTemp() { + return writeToTemp; + } + + /** + * @return the tools map + */ + public Map getTools() { + return tools; + } + + /** + * @return the tool names + */ + public Set getToolNames() { + return tools.keySet(); + } + +} 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 new file mode 100644 index 000000000..bb5d73eeb --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2018-2022, Andre Bossert + * + * 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 java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.internal.BooleanTriState; + +/** + * Manages merge tools. + */ +public class MergeTools { + private final MergeToolConfig config; + + private final Map predefinedTools; + + private final Map userDefinedTools; + + /** + * @param repo + * the repository database + */ + public MergeTools(Repository repo) { + config = repo.getConfig().get(MergeToolConfig.KEY); + predefinedTools = setupPredefinedTools(); + userDefinedTools = setupUserDefinedTools(); + } + + /** + * @param localFile + * the local file element + * @param remoteFile + * the remote file element + * @param baseFile + * the base file element + * @param mergedFilePath + * the path of 'merged' file + * @param toolName + * 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) + throws ToolException { + return 0; + } + + /** + * @return the tool names + */ + public Set getToolNames() { + return config.getToolNames(); + } + + /** + * @return the user defined tools + */ + public Map getUserDefinedTools() { + return userDefinedTools; + } + + /** + * @return the available predefined tools + */ + public Map getAvailableTools() { + return predefinedTools; + } + + /** + * @return the NOT available predefined tools + */ + public Map getNotAvailableTools() { + return new TreeMap<>(); + } + + /** + * @param gui + * use the diff.guitool setting ? + * @return the default tool name + */ + public String getDefaultToolName(BooleanTriState gui) { + return gui != BooleanTriState.UNSET ? "my_gui_tool" //$NON-NLS-1$ + : "my_default_toolname"; //$NON-NLS-1$ + } + + /** + * @return is interactive (config prompt enabled) ? + */ + public boolean isInteractive() { + return config.isPrompt(); + } + + private Map setupPredefinedTools() { + return new TreeMap<>(); + } + + private Map setupUserDefinedTools() { + return new TreeMap<>(); + } +} \ No newline at end of file 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 new file mode 100644 index 000000000..df4d8cb8c --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/UserDefinedMergeTool.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2018-2022, Andre Bossert + * + * 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 user-defined merge tool. + */ +public class UserDefinedMergeTool extends UserDefinedDiffTool + implements ExternalMergeTool { + + /** + * the merge tool "trust exit code" option + */ + private final BooleanTriState trustExitCode; + + /** + * Creates the merge tool + * + * @param name + * the name + * @param path + * the path + * @param cmd + * the command + * @param trustExitCode + * the "trust exit code" option + */ + public UserDefinedMergeTool(String name, String path, String cmd, + BooleanTriState trustExitCode) { + super(name, path, cmd); + this.trustExitCode = trustExitCode; + } + + /** + * @return the "trust exit code" flag + */ + @Override + public boolean isTrustExitCode() { + return trustExitCode == BooleanTriState.TRUE; + } + + /** + * @return the "trust exit code" option + */ + public BooleanTriState getTrustExitCode() { + return trustExitCode; + } + +} 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 8ad32d41c..e982a33b2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ConfigConstants.java @@ -31,14 +31,14 @@ public final class ConfigConstants { public static final String CONFIG_DIFF_SECTION = "diff"; /** - * The "tool" key within "diff" section + * The "tool" key within "diff" or "merge" section * * @since 6.1 */ public static final String CONFIG_KEY_TOOL = "tool"; /** - * The "guitool" key within "diff" section + * The "guitool" key within "diff" or "merge" section * * @since 6.1 */ @@ -52,14 +52,14 @@ public final class ConfigConstants { public static final String CONFIG_DIFFTOOL_SECTION = "difftool"; /** - * The "prompt" key within "difftool" section + * The "prompt" key within "difftool" or "mergetool" section * * @since 6.1 */ public static final String CONFIG_KEY_PROMPT = "prompt"; /** - * The "trustExitCode" key within "difftool" section + * The "trustExitCode" key within "difftool" or "mergetool.." section * * @since 6.1 */ @@ -123,6 +123,34 @@ public final class ConfigConstants { */ public static final String CONFIG_MERGE_SECTION = "merge"; + /** + * The "mergetool" section + * + * @since 5.13 + */ + public static final String CONFIG_MERGETOOL_SECTION = "mergetool"; + + /** + * The "keepBackup" key within "mergetool" section + * + * @since 5.13 + */ + public static final String CONFIG_KEY_KEEP_BACKUP = "keepBackup"; + + /** + * The "keepTemporaries" key within "mergetool" section + * + * @since 5.13 + */ + public static final String CONFIG_KEY_KEEP_TEMPORARIES = "keepTemporaries"; + + /** + * The "writeToTemp" key within "mergetool" section + * + * @since 5.13 + */ + public static final String CONFIG_KEY_WRITE_TO_TEMP = "writeToTemp"; + /** * The "filter" section * @since 4.6