Add difftool compare feature (execute external tool)
see: http://git-scm.com/docs/git-difftool * add CommandExecutor that handles tool execution with help of "jgit.FS" * it handles tool execution with temporary created "command file" --> for for all "command interpreters" and parameters with spaces etc. * using of external bash.exe at Windows (MinGW) if shell-script is used as difftool command. It can be enabled with parameter "jgit.usemsys2bash=auto" that checks if command contains ".sh" or enabled / disabled with "jgit.usemsys2bash=true|false" * added special handling for empty files (e.g. deleted, added etc.) that are named "/dev/null" * added creation and deletion of temporary files needed for compare * added own Exception class for reporting to pgm / command line / EGit * added prompt option handling before executing difftool * reworked trustExitCode option for specific difftool and override for all difftools from config and command line * tested with command line options "--[no]-trust-exit-code", "--tool=<toolname>", "--[no]-gui", --[no]-prompt * ContentSource * added close() methods to close / cleanup used resources (like ObjectReader TreeWalk etc.) * added isWorkingTreeSource() methods to check if file can be used from working tree instead of copy from "ObjectLoader / ObjectReader" to temporary file (fixes "difftool <commit> <commit>") Bug: 356832 Change-Id: I5462fb6dbe4ecfd9da7c74117fce4070bbfd4d7a Signed-off-by: Andre Bossert <andre.bossert@siemens.com> Signed-off-by: Simeon Andreev <simeon.danailov.andreev@gmail.com>
This commit is contained in:
parent
0c749d33ba
commit
b63c2f39a1
|
@ -9,7 +9,13 @@
|
||||||
*/
|
*/
|
||||||
package org.eclipse.jgit.pgm;
|
package org.eclipse.jgit.pgm;
|
||||||
|
|
||||||
|
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFFTOOL_SECTION;
|
||||||
|
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION;
|
||||||
|
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD;
|
||||||
|
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PROMPT;
|
||||||
|
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_TOOL;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
@ -19,6 +25,7 @@
|
||||||
import org.eclipse.jgit.diff.DiffEntry;
|
import org.eclipse.jgit.diff.DiffEntry;
|
||||||
import org.eclipse.jgit.internal.diffmergetool.CommandLineDiffTool;
|
import org.eclipse.jgit.internal.diffmergetool.CommandLineDiffTool;
|
||||||
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
|
import org.eclipse.jgit.lib.CLIRepositoryTestCase;
|
||||||
|
import org.eclipse.jgit.lib.StoredConfig;
|
||||||
import org.eclipse.jgit.pgm.opt.CmdLineParser;
|
import org.eclipse.jgit.pgm.opt.CmdLineParser;
|
||||||
import org.eclipse.jgit.pgm.opt.SubcommandHandler;
|
import org.eclipse.jgit.pgm.opt.SubcommandHandler;
|
||||||
import org.eclipse.jgit.revwalk.RevCommit;
|
import org.eclipse.jgit.revwalk.RevCommit;
|
||||||
|
@ -60,6 +67,7 @@ private String[] runAndCaptureUsingInitRaw(String... args)
|
||||||
return result.outLines().toArray(new String[0]);
|
return result.outLines().toArray(new String[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final String TOOL_NAME = "some_tool";
|
||||||
private Git git;
|
private Git git;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -68,6 +76,15 @@ public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
git = new Git(db);
|
git = new Git(db);
|
||||||
git.commit().setMessage("initial commit").call();
|
git.commit().setMessage("initial commit").call();
|
||||||
|
configureEchoTool(TOOL_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = Die.class)
|
||||||
|
public void testNotDefinedTool() throws Exception {
|
||||||
|
createUnstagedChanges();
|
||||||
|
|
||||||
|
runAndCaptureUsingInitRaw("difftool", "--tool", "undefined");
|
||||||
|
fail("Expected exception when trying to run undefined tool");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -85,7 +102,7 @@ public void testTool() throws Exception {
|
||||||
assertArrayOfLinesEquals("Incorrect output for option: " + option,
|
assertArrayOfLinesEquals("Incorrect output for option: " + option,
|
||||||
expectedOutput,
|
expectedOutput,
|
||||||
runAndCaptureUsingInitRaw("difftool", option,
|
runAndCaptureUsingInitRaw("difftool", option,
|
||||||
"some_tool"));
|
TOOL_NAME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,7 +117,7 @@ public void testToolTrustExitCode() throws Exception {
|
||||||
for (String option : options) {
|
for (String option : options) {
|
||||||
assertArrayOfLinesEquals("Incorrect output for option: " + option,
|
assertArrayOfLinesEquals("Incorrect output for option: " + option,
|
||||||
expectedOutput, runAndCaptureUsingInitRaw("difftool",
|
expectedOutput, runAndCaptureUsingInitRaw("difftool",
|
||||||
"--trust-exit-code", option, "some_tool"));
|
"--trust-exit-code", option, TOOL_NAME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +133,7 @@ public void testToolNoGuiNoPromptNoTrustExitcode() throws Exception {
|
||||||
assertArrayOfLinesEquals("Incorrect output for option: " + option,
|
assertArrayOfLinesEquals("Incorrect output for option: " + option,
|
||||||
expectedOutput, runAndCaptureUsingInitRaw("difftool",
|
expectedOutput, runAndCaptureUsingInitRaw("difftool",
|
||||||
"--no-gui", "--no-prompt", "--no-trust-exit-code",
|
"--no-gui", "--no-prompt", "--no-trust-exit-code",
|
||||||
option, "some_tool"));
|
option, TOOL_NAME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,7 +148,7 @@ public void testToolCached() throws Exception {
|
||||||
for (String option : options) {
|
for (String option : options) {
|
||||||
assertArrayOfLinesEquals("Incorrect output for option: " + option,
|
assertArrayOfLinesEquals("Incorrect output for option: " + option,
|
||||||
expectedOutput, runAndCaptureUsingInitRaw("difftool",
|
expectedOutput, runAndCaptureUsingInitRaw("difftool",
|
||||||
option, "--tool", "some_tool"));
|
option, "--tool", TOOL_NAME));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,8 +161,11 @@ public void testToolHelp() throws Exception {
|
||||||
String toolName = defaultTool.name();
|
String toolName = defaultTool.name();
|
||||||
expectedOutput.add(toolName);
|
expectedOutput.add(toolName);
|
||||||
}
|
}
|
||||||
|
String customToolHelpLine = TOOL_NAME + "." + CONFIG_KEY_CMD + " "
|
||||||
|
+ getEchoCommand();
|
||||||
|
expectedOutput.add("user-defined:");
|
||||||
|
expectedOutput.add(customToolHelpLine);
|
||||||
String[] userDefinedToolsHelp = {
|
String[] userDefinedToolsHelp = {
|
||||||
"user-defined:",
|
|
||||||
"The following tools are valid, but not currently available:",
|
"The following tools are valid, but not currently available:",
|
||||||
"Some of the tools listed above only work in a windowed",
|
"Some of the tools listed above only work in a windowed",
|
||||||
"environment. If run in a terminal-only session, they will fail.",
|
"environment. If run in a terminal-only session, they will fail.",
|
||||||
|
@ -157,6 +177,25 @@ public void testToolHelp() throws Exception {
|
||||||
expectedOutput.toArray(new String[0]), runAndCaptureUsingInitRaw("difftool", option));
|
expectedOutput.toArray(new String[0]), runAndCaptureUsingInitRaw("difftool", option));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void configureEchoTool(String toolName) {
|
||||||
|
StoredConfig config = db.getConfig();
|
||||||
|
// the default diff tool is configured without a subsection
|
||||||
|
String subsection = null;
|
||||||
|
config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
|
||||||
|
toolName);
|
||||||
|
|
||||||
|
String command = getEchoCommand();
|
||||||
|
|
||||||
|
config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
|
||||||
|
command);
|
||||||
|
/*
|
||||||
|
* prevent prompts as we are running in tests and there is no user to
|
||||||
|
* interact with on the command line
|
||||||
|
*/
|
||||||
|
config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_PROMPT,
|
||||||
|
String.valueOf(false));
|
||||||
|
}
|
||||||
|
|
||||||
private RevCommit createUnstagedChanges() throws Exception {
|
private RevCommit createUnstagedChanges() throws Exception {
|
||||||
writeTrashFile("a", "Hello world a");
|
writeTrashFile("a", "Hello world a");
|
||||||
writeTrashFile("b", "Hello world b");
|
writeTrashFile("b", "Hello world b");
|
||||||
|
@ -188,11 +227,7 @@ private String[] getExpectedDiffToolOutput(List<DiffEntry> changes) {
|
||||||
for (int i = 0; i < changes.size(); ++i) {
|
for (int i = 0; i < changes.size(); ++i) {
|
||||||
DiffEntry change = changes.get(i);
|
DiffEntry change = changes.get(i);
|
||||||
String newPath = change.getNewPath();
|
String newPath = change.getNewPath();
|
||||||
String oldPath = change.getOldPath();
|
String expectedLine = newPath;
|
||||||
String newIdName = change.getNewId().name();
|
|
||||||
String oldIdName = change.getOldId().name();
|
|
||||||
String expectedLine = "M\t" + newPath + " (" + newIdName + ")"
|
|
||||||
+ "\t" + oldPath + " (" + oldIdName + ")";
|
|
||||||
expectedToolOutput[i] = expectedLine;
|
expectedToolOutput[i] = expectedLine;
|
||||||
}
|
}
|
||||||
return expectedToolOutput;
|
return expectedToolOutput;
|
||||||
|
@ -202,4 +237,12 @@ private static void assertArrayOfLinesEquals(String failMessage,
|
||||||
String[] expected, String[] actual) {
|
String[] expected, String[] actual) {
|
||||||
assertEquals(failMessage, toString(expected), toString(actual));
|
assertEquals(failMessage, toString(expected), toString(actual));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getEchoCommand() {
|
||||||
|
/*
|
||||||
|
* use 'MERGED' placeholder, as both 'LOCAL' and 'REMOTE' will be
|
||||||
|
* replaced with full paths to a temporary file during some of the tests
|
||||||
|
*/
|
||||||
|
return "(echo \"$MERGED\")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ deletedBranch=Deleted branch {0}
|
||||||
deletedRemoteBranch=Deleted remote branch {0}
|
deletedRemoteBranch=Deleted remote branch {0}
|
||||||
diffToolHelpSetToFollowing='git difftool --tool=<tool>' may be set to one of the following:\n{0}\n\tuser-defined:\n{1}\nThe following tools are valid, but not currently available:\n{2}\nSome of the tools listed above only work in a windowed\nenvironment. If run in a terminal-only session, they will fail.
|
diffToolHelpSetToFollowing='git difftool --tool=<tool>' may be set to one of the following:\n{0}\n\tuser-defined:\n{1}\nThe following tools are valid, but not currently available:\n{2}\nSome of the tools listed above only work in a windowed\nenvironment. If run in a terminal-only session, they will fail.
|
||||||
diffToolLaunch=Viewing ({0}/{1}): '{2}'\nLaunch '{3}' [Y/n]?
|
diffToolLaunch=Viewing ({0}/{1}): '{2}'\nLaunch '{3}' [Y/n]?
|
||||||
diffToolDied=external diff died, stopping at {0}
|
diffToolDied=external diff died, stopping at path ''{0}'' due to exception: {1}
|
||||||
doesNotExist={0} does not exist
|
doesNotExist={0} does not exist
|
||||||
dontOverwriteLocalChanges=error: Your local changes to the following file would be overwritten by merge:
|
dontOverwriteLocalChanges=error: Your local changes to the following file would be overwritten by merge:
|
||||||
everythingUpToDate=Everything up-to-date
|
everythingUpToDate=Everything up-to-date
|
||||||
|
|
|
@ -21,8 +21,10 @@
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import org.eclipse.jgit.diff.ContentSource;
|
||||||
|
import org.eclipse.jgit.diff.ContentSource.Pair;
|
||||||
import org.eclipse.jgit.diff.DiffEntry;
|
import org.eclipse.jgit.diff.DiffEntry;
|
||||||
|
import org.eclipse.jgit.diff.DiffEntry.Side;
|
||||||
import org.eclipse.jgit.diff.DiffFormatter;
|
import org.eclipse.jgit.diff.DiffFormatter;
|
||||||
import org.eclipse.jgit.dircache.DirCacheIterator;
|
import org.eclipse.jgit.dircache.DirCacheIterator;
|
||||||
import org.eclipse.jgit.errors.AmbiguousObjectException;
|
import org.eclipse.jgit.errors.AmbiguousObjectException;
|
||||||
|
@ -30,8 +32,11 @@
|
||||||
import org.eclipse.jgit.errors.RevisionSyntaxException;
|
import org.eclipse.jgit.errors.RevisionSyntaxException;
|
||||||
import org.eclipse.jgit.internal.diffmergetool.DiffTools;
|
import org.eclipse.jgit.internal.diffmergetool.DiffTools;
|
||||||
import org.eclipse.jgit.internal.diffmergetool.ExternalDiffTool;
|
import org.eclipse.jgit.internal.diffmergetool.ExternalDiffTool;
|
||||||
|
import org.eclipse.jgit.internal.diffmergetool.FileElement;
|
||||||
|
import org.eclipse.jgit.internal.diffmergetool.ToolException;
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectReader;
|
import org.eclipse.jgit.lib.ObjectReader;
|
||||||
|
import org.eclipse.jgit.lib.ObjectStream;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.lib.TextProgressMonitor;
|
import org.eclipse.jgit.lib.TextProgressMonitor;
|
||||||
import org.eclipse.jgit.lib.internal.BooleanTriState;
|
import org.eclipse.jgit.lib.internal.BooleanTriState;
|
||||||
|
@ -40,8 +45,10 @@
|
||||||
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
|
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
|
||||||
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
|
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
|
||||||
import org.eclipse.jgit.treewalk.FileTreeIterator;
|
import org.eclipse.jgit.treewalk.FileTreeIterator;
|
||||||
|
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
|
||||||
import org.eclipse.jgit.treewalk.filter.TreeFilter;
|
import org.eclipse.jgit.treewalk.filter.TreeFilter;
|
||||||
import org.eclipse.jgit.util.StringUtils;
|
import org.eclipse.jgit.util.StringUtils;
|
||||||
|
import org.eclipse.jgit.util.FS.ExecutionResult;
|
||||||
import org.kohsuke.args4j.Argument;
|
import org.kohsuke.args4j.Argument;
|
||||||
import org.kohsuke.args4j.Option;
|
import org.kohsuke.args4j.Option;
|
||||||
|
|
||||||
|
@ -145,40 +152,54 @@ protected void run() {
|
||||||
|
|
||||||
private void compare(List<DiffEntry> files, boolean showPrompt,
|
private void compare(List<DiffEntry> files, boolean showPrompt,
|
||||||
String toolNamePrompt) throws IOException {
|
String toolNamePrompt) throws IOException {
|
||||||
for (int fileIndex = 0; fileIndex < files.size(); fileIndex++) {
|
ContentSource.Pair sourcePair = new ContentSource.Pair(source(oldTree),
|
||||||
DiffEntry ent = files.get(fileIndex);
|
source(newTree));
|
||||||
String mergedFilePath = ent.getNewPath();
|
try {
|
||||||
if (mergedFilePath.equals(DiffEntry.DEV_NULL)) {
|
for (int fileIndex = 0; fileIndex < files.size(); fileIndex++) {
|
||||||
mergedFilePath = ent.getOldPath();
|
DiffEntry ent = files.get(fileIndex);
|
||||||
}
|
String mergedFilePath = ent.getNewPath();
|
||||||
// check if user wants to launch compare
|
if (mergedFilePath.equals(DiffEntry.DEV_NULL)) {
|
||||||
boolean launchCompare = true;
|
mergedFilePath = ent.getOldPath();
|
||||||
if (showPrompt) {
|
}
|
||||||
launchCompare = isLaunchCompare(fileIndex + 1, files.size(),
|
FileElement local = new FileElement(ent.getOldPath(),
|
||||||
mergedFilePath, toolNamePrompt);
|
ent.getOldId().name(),
|
||||||
}
|
getObjectStream(sourcePair, Side.OLD, ent));
|
||||||
if (launchCompare) {
|
FileElement remote = new FileElement(ent.getNewPath(),
|
||||||
switch (ent.getChangeType()) {
|
ent.getNewId().name(),
|
||||||
case MODIFY:
|
getObjectStream(sourcePair, Side.NEW, ent));
|
||||||
outw.println("M\t" + ent.getNewPath() //$NON-NLS-1$
|
// check if user wants to launch compare
|
||||||
+ " (" + ent.getNewId().name() + ")" //$NON-NLS-1$ //$NON-NLS-2$
|
boolean launchCompare = true;
|
||||||
+ "\t" + ent.getOldPath() //$NON-NLS-1$
|
if (showPrompt) {
|
||||||
+ " (" + ent.getOldId().name() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
|
launchCompare = isLaunchCompare(fileIndex + 1, files.size(),
|
||||||
int ret = diffTools.compare(ent.getNewPath(),
|
mergedFilePath, toolNamePrompt);
|
||||||
ent.getOldPath(), ent.getNewId().name(),
|
}
|
||||||
ent.getOldId().name(), toolName, prompt, gui,
|
if (launchCompare) {
|
||||||
trustExitCode);
|
try {
|
||||||
if (ret != 0) {
|
// TODO: check how to return the exit-code of
|
||||||
|
// the
|
||||||
|
// tool
|
||||||
|
// to
|
||||||
|
// jgit / java runtime ?
|
||||||
|
// int rc =...
|
||||||
|
ExecutionResult result = diffTools.compare(db, local,
|
||||||
|
remote, mergedFilePath,
|
||||||
|
toolName, prompt, gui, trustExitCode);
|
||||||
|
outw.println(new String(result.getStdout().toByteArray()));
|
||||||
|
errw.println(
|
||||||
|
new String(result.getStderr().toByteArray()));
|
||||||
|
} catch (ToolException e) {
|
||||||
|
outw.println(e.getResultStdout());
|
||||||
|
outw.flush();
|
||||||
|
errw.println(e.getMessage());
|
||||||
throw die(MessageFormat.format(
|
throw die(MessageFormat.format(
|
||||||
CLIText.get().diffToolDied, mergedFilePath));
|
CLIText.get().diffToolDied, mergedFilePath, e));
|
||||||
}
|
}
|
||||||
break;
|
} else {
|
||||||
default:
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
sourcePair.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,4 +275,23 @@ private List<DiffEntry> getFiles()
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ObjectStream getObjectStream(Pair pair, Side side, DiffEntry ent) {
|
||||||
|
ObjectStream stream = null;
|
||||||
|
if (!pair.isWorkingTreeSource(side)) {
|
||||||
|
try {
|
||||||
|
stream = pair.open(side, ent).openStream();
|
||||||
|
} catch (Exception e) {
|
||||||
|
stream = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ContentSource source(AbstractTreeIterator iterator) {
|
||||||
|
if (iterator instanceof WorkingTreeIterator) {
|
||||||
|
return ContentSource.create((WorkingTreeIterator) iterator);
|
||||||
|
}
|
||||||
|
return ContentSource.create(db.newObjectReader());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,13 +10,17 @@
|
||||||
package org.eclipse.jgit.internal.diffmergetool;
|
package org.eclipse.jgit.internal.diffmergetool;
|
||||||
|
|
||||||
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFFTOOL_SECTION;
|
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFFTOOL_SECTION;
|
||||||
|
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION;
|
||||||
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CMD;
|
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_GUITOOL;
|
||||||
import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_PATH;
|
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_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_TRUST_EXIT_CODE;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
|
@ -25,6 +29,7 @@
|
||||||
|
|
||||||
import org.eclipse.jgit.lib.internal.BooleanTriState;
|
import org.eclipse.jgit.lib.internal.BooleanTriState;
|
||||||
import org.eclipse.jgit.storage.file.FileBasedConfig;
|
import org.eclipse.jgit.storage.file.FileBasedConfig;
|
||||||
|
import org.eclipse.jgit.util.FS.ExecutionResult;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,6 +37,54 @@
|
||||||
*/
|
*/
|
||||||
public class ExternalDiffToolTest extends ExternalToolTestCase {
|
public class ExternalDiffToolTest extends ExternalToolTestCase {
|
||||||
|
|
||||||
|
@Test(expected = ToolException.class)
|
||||||
|
public void testUserToolWithError() throws Exception {
|
||||||
|
String toolName = "customTool";
|
||||||
|
|
||||||
|
int errorReturnCode = 1;
|
||||||
|
String command = "exit " + errorReturnCode;
|
||||||
|
|
||||||
|
FileBasedConfig config = db.getConfig();
|
||||||
|
config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
|
||||||
|
command);
|
||||||
|
|
||||||
|
DiffTools manager = new DiffTools(db);
|
||||||
|
|
||||||
|
BooleanTriState prompt = BooleanTriState.UNSET;
|
||||||
|
BooleanTriState gui = BooleanTriState.UNSET;
|
||||||
|
BooleanTriState trustExitCode = BooleanTriState.TRUE;
|
||||||
|
|
||||||
|
manager.compare(db, local, remote, merged.getPath(), toolName, prompt,
|
||||||
|
gui, trustExitCode);
|
||||||
|
|
||||||
|
fail("Expected exception to be thrown due to external tool exiting with error code: "
|
||||||
|
+ errorReturnCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ToolException.class)
|
||||||
|
public void testUserToolWithCommandNotFoundError() throws Exception {
|
||||||
|
String toolName = "customTool";
|
||||||
|
|
||||||
|
int errorReturnCode = 127; // command not found
|
||||||
|
String command = "exit " + errorReturnCode;
|
||||||
|
|
||||||
|
FileBasedConfig config = db.getConfig();
|
||||||
|
config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
|
||||||
|
command);
|
||||||
|
|
||||||
|
DiffTools manager = new DiffTools(db);
|
||||||
|
|
||||||
|
BooleanTriState prompt = BooleanTriState.UNSET;
|
||||||
|
BooleanTriState gui = BooleanTriState.UNSET;
|
||||||
|
BooleanTriState trustExitCode = BooleanTriState.FALSE;
|
||||||
|
|
||||||
|
manager.compare(db, local, remote, merged.getPath(), toolName, prompt,
|
||||||
|
gui, trustExitCode);
|
||||||
|
|
||||||
|
fail("Expected exception to be thrown due to external tool exiting with error code: "
|
||||||
|
+ errorReturnCode);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testToolNames() {
|
public void testToolNames() {
|
||||||
DiffTools manager = new DiffTools(db);
|
DiffTools manager = new DiffTools(db);
|
||||||
|
@ -86,11 +139,11 @@ public void testUserDefinedTools() {
|
||||||
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
|
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
|
||||||
CONFIG_KEY_PATH, "/usr/bin/echo");
|
CONFIG_KEY_PATH, "/usr/bin/echo");
|
||||||
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
|
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
|
||||||
CONFIG_KEY_PROMPT, "--no-prompt");
|
CONFIG_KEY_PROMPT, String.valueOf(false));
|
||||||
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
|
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
|
||||||
CONFIG_KEY_GUITOOL, "--no-gui");
|
CONFIG_KEY_GUITOOL, String.valueOf(false));
|
||||||
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
|
config.setString(CONFIG_DIFFTOOL_SECTION, customToolname,
|
||||||
CONFIG_KEY_TRUST_EXIT_CODE, "--no-trust-exit-code");
|
CONFIG_KEY_TRUST_EXIT_CODE, String.valueOf(false));
|
||||||
DiffTools manager = new DiffTools(db);
|
DiffTools manager = new DiffTools(db);
|
||||||
Set<String> actualToolNames = manager.getUserDefinedTools().keySet();
|
Set<String> actualToolNames = manager.getUserDefinedTools().keySet();
|
||||||
Set<String> expectedToolNames = new LinkedHashSet<>();
|
Set<String> expectedToolNames = new LinkedHashSet<>();
|
||||||
|
@ -109,38 +162,50 @@ public void testNotAvailableTools() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCompare() {
|
public void testCompare() throws ToolException {
|
||||||
DiffTools manager = new DiffTools(db);
|
String toolName = "customTool";
|
||||||
|
|
||||||
|
FileBasedConfig config = db.getConfig();
|
||||||
|
// the default diff tool is configured without a subsection
|
||||||
|
String subsection = null;
|
||||||
|
config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
|
||||||
|
toolName);
|
||||||
|
|
||||||
|
String command = getEchoCommand();
|
||||||
|
|
||||||
|
config.setString(CONFIG_DIFFTOOL_SECTION, toolName, CONFIG_KEY_CMD,
|
||||||
|
command);
|
||||||
|
|
||||||
String newPath = "";
|
|
||||||
String oldPath = "";
|
|
||||||
String newId = "";
|
|
||||||
String oldId = "";
|
|
||||||
String toolName = "";
|
|
||||||
BooleanTriState prompt = BooleanTriState.UNSET;
|
BooleanTriState prompt = BooleanTriState.UNSET;
|
||||||
BooleanTriState gui = BooleanTriState.UNSET;
|
BooleanTriState gui = BooleanTriState.UNSET;
|
||||||
BooleanTriState trustExitCode = BooleanTriState.UNSET;
|
BooleanTriState trustExitCode = BooleanTriState.UNSET;
|
||||||
|
|
||||||
|
DiffTools manager = new DiffTools(db);
|
||||||
|
|
||||||
int expectedCompareResult = 0;
|
int expectedCompareResult = 0;
|
||||||
int compareResult = manager.compare(newPath, oldPath, newId, oldId,
|
ExecutionResult compareResult = manager.compare(db, local, remote,
|
||||||
toolName, prompt, gui, trustExitCode);
|
merged.getPath(), toolName, prompt, gui, trustExitCode);
|
||||||
assertEquals("Incorrect compare result for external diff tool",
|
assertEquals("Incorrect compare result for external diff tool",
|
||||||
expectedCompareResult, compareResult);
|
expectedCompareResult, compareResult.getRc());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultTool() throws Exception {
|
public void testDefaultTool() throws Exception {
|
||||||
|
String toolName = "customTool";
|
||||||
|
String guiToolName = "customGuiTool";
|
||||||
|
|
||||||
FileBasedConfig config = db.getConfig();
|
FileBasedConfig config = db.getConfig();
|
||||||
// the default diff tool is configured without a subsection
|
// the default diff tool is configured without a subsection
|
||||||
String subsection = null;
|
String subsection = null;
|
||||||
config.setString("diff", subsection, "tool", "customTool");
|
config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_TOOL,
|
||||||
|
toolName);
|
||||||
|
|
||||||
DiffTools manager = new DiffTools(db);
|
DiffTools manager = new DiffTools(db);
|
||||||
BooleanTriState gui = BooleanTriState.UNSET;
|
BooleanTriState gui = BooleanTriState.UNSET;
|
||||||
String defaultToolName = manager.getDefaultToolName(gui);
|
String defaultToolName = manager.getDefaultToolName(gui);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"Expected configured difftool to be the default external diff tool",
|
"Expected configured difftool to be the default external diff tool",
|
||||||
"my_default_toolname", defaultToolName);
|
toolName, defaultToolName);
|
||||||
|
|
||||||
gui = BooleanTriState.TRUE;
|
gui = BooleanTriState.TRUE;
|
||||||
String defaultGuiToolName = manager.getDefaultToolName(gui);
|
String defaultGuiToolName = manager.getDefaultToolName(gui);
|
||||||
|
@ -148,11 +213,63 @@ public void testDefaultTool() throws Exception {
|
||||||
"Expected configured difftool to be the default external diff tool",
|
"Expected configured difftool to be the default external diff tool",
|
||||||
"my_gui_tool", defaultGuiToolName);
|
"my_gui_tool", defaultGuiToolName);
|
||||||
|
|
||||||
config.setString("diff", subsection, "guitool", "customGuiTool");
|
config.setString(CONFIG_DIFF_SECTION, subsection, CONFIG_KEY_GUITOOL,
|
||||||
|
guiToolName);
|
||||||
manager = new DiffTools(db);
|
manager = new DiffTools(db);
|
||||||
defaultGuiToolName = manager.getDefaultToolName(gui);
|
defaultGuiToolName = manager.getDefaultToolName(gui);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"Expected configured difftool to be the default external diff guitool",
|
"Expected configured difftool to be the default external diff guitool",
|
||||||
"my_gui_tool", defaultGuiToolName);
|
"my_gui_tool", defaultGuiToolName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testOverridePreDefinedToolPath() {
|
||||||
|
String newToolPath = "/tmp/path/";
|
||||||
|
|
||||||
|
CommandLineDiffTool[] defaultTools = CommandLineDiffTool.values();
|
||||||
|
assertTrue("Expected to find pre-defined external diff tools",
|
||||||
|
defaultTools.length > 0);
|
||||||
|
|
||||||
|
CommandLineDiffTool overridenTool = defaultTools[0];
|
||||||
|
String overridenToolName = overridenTool.name();
|
||||||
|
String overridenToolPath = newToolPath + overridenToolName;
|
||||||
|
FileBasedConfig config = db.getConfig();
|
||||||
|
config.setString(CONFIG_DIFFTOOL_SECTION, overridenToolName,
|
||||||
|
CONFIG_KEY_PATH, overridenToolPath);
|
||||||
|
|
||||||
|
DiffTools manager = new DiffTools(db);
|
||||||
|
Map<String, ExternalDiffTool> availableTools = manager
|
||||||
|
.getAvailableTools();
|
||||||
|
ExternalDiffTool externalDiffTool = availableTools
|
||||||
|
.get(overridenToolName);
|
||||||
|
String actualDiffToolPath = externalDiffTool.getPath();
|
||||||
|
assertEquals(
|
||||||
|
"Expected pre-defined external diff tool to have overriden path",
|
||||||
|
overridenToolPath, actualDiffToolPath);
|
||||||
|
String expectedDiffToolCommand = overridenToolPath + " "
|
||||||
|
+ overridenTool.getParameters();
|
||||||
|
String actualDiffToolCommand = externalDiffTool.getCommand();
|
||||||
|
assertEquals(
|
||||||
|
"Expected pre-defined external diff tool to have overriden command",
|
||||||
|
expectedDiffToolCommand, actualDiffToolCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = ToolException.class)
|
||||||
|
public void testUndefinedTool() throws Exception {
|
||||||
|
DiffTools manager = new DiffTools(db);
|
||||||
|
|
||||||
|
String toolName = "undefined";
|
||||||
|
BooleanTriState prompt = BooleanTriState.UNSET;
|
||||||
|
BooleanTriState gui = BooleanTriState.UNSET;
|
||||||
|
BooleanTriState trustExitCode = BooleanTriState.UNSET;
|
||||||
|
|
||||||
|
manager.compare(db, local, remote, merged.getPath(), toolName, prompt,
|
||||||
|
gui, trustExitCode);
|
||||||
|
fail("Expected exception to be thrown due to not defined external diff tool");
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getEchoCommand() {
|
||||||
|
return "(echo \"$LOCAL\" \"$REMOTE\") > "
|
||||||
|
+ commandResult.getAbsolutePath();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,14 @@ public abstract class ExternalToolTestCase extends RepositoryTestCase {
|
||||||
|
|
||||||
protected File commandResult;
|
protected File commandResult;
|
||||||
|
|
||||||
|
protected FileElement local;
|
||||||
|
|
||||||
|
protected FileElement remote;
|
||||||
|
|
||||||
|
protected FileElement merged;
|
||||||
|
|
||||||
|
protected FileElement base;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
|
@ -51,6 +59,11 @@ public void setUp() throws Exception {
|
||||||
baseFile.deleteOnExit();
|
baseFile.deleteOnExit();
|
||||||
commandResult = writeTrashFile("commandResult.txt", "");
|
commandResult = writeTrashFile("commandResult.txt", "");
|
||||||
commandResult.deleteOnExit();
|
commandResult.deleteOnExit();
|
||||||
|
|
||||||
|
local = new FileElement(localFile.getAbsolutePath(), "LOCAL");
|
||||||
|
remote = new FileElement(remoteFile.getAbsolutePath(), "REMOTE");
|
||||||
|
merged = new FileElement(mergedFile.getAbsolutePath(), "MERGED");
|
||||||
|
base = new FileElement(baseFile.getAbsolutePath(), "BASE");
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2010, 2020 Google Inc. and others
|
* Copyright (C) 2010, 2021 Google Inc. and others
|
||||||
*
|
*
|
||||||
* This program and the accompanying materials are made available under the
|
* This program and the accompanying materials are made available under the
|
||||||
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
@ -91,6 +91,29 @@ public static ContentSource create(WorkingTreeIterator iterator) {
|
||||||
public abstract ObjectLoader open(String path, ObjectId id)
|
public abstract ObjectLoader open(String path, ObjectId id)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the used resources like ObjectReader, TreeWalk etc. Default
|
||||||
|
* implementation does nothing.
|
||||||
|
*
|
||||||
|
* @since 6.2
|
||||||
|
*/
|
||||||
|
public void close() {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the source is from "working tree", so it can be accessed as a
|
||||||
|
* file directly.
|
||||||
|
*
|
||||||
|
* @since 6.2
|
||||||
|
*
|
||||||
|
* @return true if working tree source and false otherwise (loader must be
|
||||||
|
* used)
|
||||||
|
*/
|
||||||
|
public boolean isWorkingTreeSource() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private static class ObjectReaderSource extends ContentSource {
|
private static class ObjectReaderSource extends ContentSource {
|
||||||
private final ObjectReader reader;
|
private final ObjectReader reader;
|
||||||
|
|
||||||
|
@ -111,6 +134,16 @@ public long size(String path, ObjectId id) throws IOException {
|
||||||
public ObjectLoader open(String path, ObjectId id) throws IOException {
|
public ObjectLoader open(String path, ObjectId id) throws IOException {
|
||||||
return reader.open(id, Constants.OBJ_BLOB);
|
return reader.open(id, Constants.OBJ_BLOB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWorkingTreeSource() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class WorkingTreeSource extends ContentSource {
|
private static class WorkingTreeSource extends ContentSource {
|
||||||
|
@ -194,6 +227,16 @@ private void seek(String path) throws IOException {
|
||||||
throw new FileNotFoundException(path);
|
throw new FileNotFoundException(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
tw.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWorkingTreeSource() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A pair of sources to access the old and new sides of a DiffEntry. */
|
/** A pair of sources to access the old and new sides of a DiffEntry. */
|
||||||
|
@ -261,5 +304,37 @@ public ObjectLoader open(DiffEntry.Side side, DiffEntry ent)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes used resources.
|
||||||
|
*
|
||||||
|
* @since 6.2
|
||||||
|
*/
|
||||||
|
public void close() {
|
||||||
|
oldSource.close();
|
||||||
|
newSource.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if source (side) is a "working tree".
|
||||||
|
*
|
||||||
|
* @since 6.2
|
||||||
|
*
|
||||||
|
* @param side
|
||||||
|
* which side of the entry to read (OLD or NEW).
|
||||||
|
* @return is the source a "working tree"
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public boolean isWorkingTreeSource(DiffEntry.Side side) {
|
||||||
|
switch (side) {
|
||||||
|
case OLD:
|
||||||
|
return oldSource.isWorkingTreeSource();
|
||||||
|
case NEW:
|
||||||
|
return newSource.isWorkingTreeSource();
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,182 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2021, 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 java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Map;
|
||||||
|
import org.eclipse.jgit.util.FS;
|
||||||
|
import org.eclipse.jgit.util.FS.ExecutionResult;
|
||||||
|
import org.eclipse.jgit.util.FS_POSIX;
|
||||||
|
import org.eclipse.jgit.util.FS_Win32;
|
||||||
|
import org.eclipse.jgit.util.FS_Win32_Cygwin;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs a command with help of FS.
|
||||||
|
*/
|
||||||
|
public class CommandExecutor {
|
||||||
|
|
||||||
|
private FS fs;
|
||||||
|
|
||||||
|
private boolean checkExitCode;
|
||||||
|
|
||||||
|
private File commandFile;
|
||||||
|
|
||||||
|
private boolean useMsys2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param fs
|
||||||
|
* the file system
|
||||||
|
* @param checkExitCode
|
||||||
|
* should the exit code be checked for errors ?
|
||||||
|
*/
|
||||||
|
public CommandExecutor(FS fs, boolean checkExitCode) {
|
||||||
|
this.fs = fs;
|
||||||
|
this.checkExitCode = checkExitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param command
|
||||||
|
* the command string
|
||||||
|
* @param workingDir
|
||||||
|
* the working directory
|
||||||
|
* @param env
|
||||||
|
* the environment
|
||||||
|
* @return the execution result
|
||||||
|
* @throws ToolException
|
||||||
|
* @throws InterruptedException
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public ExecutionResult run(String command, File workingDir,
|
||||||
|
Map<String, String> env)
|
||||||
|
throws ToolException, IOException, InterruptedException {
|
||||||
|
String[] commandArray = createCommandArray(command);
|
||||||
|
try {
|
||||||
|
ProcessBuilder pb = fs.runInShell(commandArray[0],
|
||||||
|
Arrays.copyOfRange(commandArray, 1, commandArray.length));
|
||||||
|
pb.directory(workingDir);
|
||||||
|
Map<String, String> envp = pb.environment();
|
||||||
|
if (env != null) {
|
||||||
|
envp.putAll(env);
|
||||||
|
}
|
||||||
|
ExecutionResult result = fs.execute(pb, null);
|
||||||
|
int rc = result.getRc();
|
||||||
|
if ((rc != 0) && (checkExitCode
|
||||||
|
|| isCommandExecutionError(rc))) {
|
||||||
|
throw new ToolException(
|
||||||
|
new String(result.getStderr().toByteArray()), result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} finally {
|
||||||
|
deleteCommandArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteCommandArray() {
|
||||||
|
deleteCommandFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] createCommandArray(String command)
|
||||||
|
throws ToolException, IOException {
|
||||||
|
String[] commandArray = null;
|
||||||
|
checkUseMsys2(command);
|
||||||
|
createCommandFile(command);
|
||||||
|
if (fs instanceof FS_POSIX) {
|
||||||
|
commandArray = new String[1];
|
||||||
|
commandArray[0] = commandFile.getCanonicalPath();
|
||||||
|
} else if (fs instanceof FS_Win32) {
|
||||||
|
if (useMsys2) {
|
||||||
|
commandArray = new String[3];
|
||||||
|
commandArray[0] = "bash.exe"; //$NON-NLS-1$
|
||||||
|
commandArray[1] = "-c"; //$NON-NLS-1$
|
||||||
|
commandArray[2] = commandFile.getCanonicalPath().replace("\\", //$NON-NLS-1$
|
||||||
|
"/"); //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
commandArray = new String[1];
|
||||||
|
commandArray[0] = commandFile.getCanonicalPath();
|
||||||
|
}
|
||||||
|
} else if (fs instanceof FS_Win32_Cygwin) {
|
||||||
|
commandArray = new String[1];
|
||||||
|
commandArray[0] = commandFile.getCanonicalPath().replace("\\", "/"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
} else {
|
||||||
|
throw new ToolException(
|
||||||
|
"JGit: file system not supported: " + fs.toString()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
return commandArray;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkUseMsys2(String command) {
|
||||||
|
useMsys2 = false;
|
||||||
|
String useMsys2Str = System.getProperty("jgit.usemsys2bash"); //$NON-NLS-1$
|
||||||
|
if (useMsys2Str != null && !useMsys2Str.isEmpty()) {
|
||||||
|
if (useMsys2Str.equalsIgnoreCase("auto")) { //$NON-NLS-1$
|
||||||
|
useMsys2 = command.contains(".sh"); //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
useMsys2 = Boolean.parseBoolean(useMsys2Str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createCommandFile(String command)
|
||||||
|
throws ToolException, IOException {
|
||||||
|
String fileExtension = null;
|
||||||
|
if (useMsys2 || fs instanceof FS_POSIX
|
||||||
|
|| fs instanceof FS_Win32_Cygwin) {
|
||||||
|
fileExtension = ".sh"; //$NON-NLS-1$
|
||||||
|
} else if (fs instanceof FS_Win32) {
|
||||||
|
fileExtension = ".cmd"; //$NON-NLS-1$
|
||||||
|
command = "@echo off" + System.lineSeparator() + command //$NON-NLS-1$
|
||||||
|
+ System.lineSeparator() + "exit /B %ERRORLEVEL%"; //$NON-NLS-1$
|
||||||
|
} else {
|
||||||
|
throw new ToolException(
|
||||||
|
"JGit: file system not supported: " + fs.toString()); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
commandFile = File.createTempFile(".__", //$NON-NLS-1$
|
||||||
|
"__jgit_tool" + fileExtension); //$NON-NLS-1$
|
||||||
|
try (OutputStream outStream = new FileOutputStream(commandFile)) {
|
||||||
|
byte[] strToBytes = command.getBytes();
|
||||||
|
outStream.write(strToBytes);
|
||||||
|
outStream.close();
|
||||||
|
}
|
||||||
|
commandFile.setExecutable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void deleteCommandFile() {
|
||||||
|
if (commandFile != null && commandFile.exists()) {
|
||||||
|
commandFile.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCommandExecutionError(int rc) {
|
||||||
|
if (useMsys2 || fs instanceof FS_POSIX
|
||||||
|
|| fs instanceof FS_Win32_Cygwin) {
|
||||||
|
// 126: permission for executing command denied
|
||||||
|
// 127: command not found
|
||||||
|
if ((rc == 126) || (rc == 127)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (fs instanceof FS_Win32) {
|
||||||
|
// 9009, 0x2331: Program is not recognized as an internal or
|
||||||
|
// external command, operable program or batch file. Indicates that
|
||||||
|
// command, application name or path has been misspelled when
|
||||||
|
// configuring the Action.
|
||||||
|
if (rc == 9009) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -49,9 +49,10 @@ private DiffToolConfig(Config rc) {
|
||||||
toolName = rc.getString(CONFIG_DIFF_SECTION, null, CONFIG_KEY_TOOL);
|
toolName = rc.getString(CONFIG_DIFF_SECTION, null, CONFIG_KEY_TOOL);
|
||||||
guiToolName = rc.getString(CONFIG_DIFF_SECTION, null,
|
guiToolName = rc.getString(CONFIG_DIFF_SECTION, null,
|
||||||
CONFIG_KEY_GUITOOL);
|
CONFIG_KEY_GUITOOL);
|
||||||
prompt = rc.getBoolean(CONFIG_DIFFTOOL_SECTION, CONFIG_KEY_PROMPT,
|
prompt = rc.getBoolean(CONFIG_DIFFTOOL_SECTION, toolName,
|
||||||
|
CONFIG_KEY_PROMPT,
|
||||||
true);
|
true);
|
||||||
String trustStr = rc.getString(CONFIG_DIFFTOOL_SECTION, null,
|
String trustStr = rc.getString(CONFIG_DIFFTOOL_SECTION, toolName,
|
||||||
CONFIG_KEY_TRUST_EXIT_CODE);
|
CONFIG_KEY_TRUST_EXIT_CODE);
|
||||||
if (trustStr != null) {
|
if (trustStr != null) {
|
||||||
trustExitCode = Boolean.parseBoolean(trustStr)
|
trustExitCode = Boolean.parseBoolean(trustStr)
|
||||||
|
|
|
@ -12,11 +12,16 @@
|
||||||
|
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.lib.Constants;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
import org.eclipse.jgit.lib.Repository;
|
||||||
import org.eclipse.jgit.lib.internal.BooleanTriState;
|
import org.eclipse.jgit.lib.internal.BooleanTriState;
|
||||||
|
import org.eclipse.jgit.util.FS.ExecutionResult;
|
||||||
|
import org.eclipse.jgit.util.StringUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages diff tools.
|
* Manages diff tools.
|
||||||
|
@ -25,9 +30,9 @@ public class DiffTools {
|
||||||
|
|
||||||
private final DiffToolConfig config;
|
private final DiffToolConfig config;
|
||||||
|
|
||||||
private Map<String, ExternalDiffTool> predefinedTools;
|
private final Map<String, ExternalDiffTool> predefinedTools;
|
||||||
|
|
||||||
private Map<String, ExternalDiffTool> userDefinedTools;
|
private final Map<String, ExternalDiffTool> userDefinedTools;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the external diff-tools manager for given repository.
|
* Creates the external diff-tools manager for given repository.
|
||||||
|
@ -37,21 +42,22 @@ public class DiffTools {
|
||||||
*/
|
*/
|
||||||
public DiffTools(Repository repo) {
|
public DiffTools(Repository repo) {
|
||||||
config = repo.getConfig().get(DiffToolConfig.KEY);
|
config = repo.getConfig().get(DiffToolConfig.KEY);
|
||||||
setupPredefinedTools();
|
predefinedTools = setupPredefinedTools();
|
||||||
setupUserDefinedTools();
|
userDefinedTools = setupUserDefinedTools(config, predefinedTools);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compare two versions of a file.
|
* Compare two versions of a file.
|
||||||
*
|
*
|
||||||
* @param newPath
|
* @param repo
|
||||||
* the new file path
|
* the repository
|
||||||
* @param oldPath
|
* @param localFile
|
||||||
* the old file path
|
* the local file element
|
||||||
* @param newId
|
* @param remoteFile
|
||||||
* the new object ID
|
* the remote file element
|
||||||
* @param oldId
|
* @param mergedFilePath
|
||||||
* the old object ID
|
* the path of 'merged' file, it equals local or remote path for
|
||||||
|
* difftool
|
||||||
* @param toolName
|
* @param toolName
|
||||||
* the selected tool name (can be null)
|
* the selected tool name (can be null)
|
||||||
* @param prompt
|
* @param prompt
|
||||||
|
@ -61,11 +67,39 @@ public DiffTools(Repository repo) {
|
||||||
* @param trustExitCode
|
* @param trustExitCode
|
||||||
* the "trust exit code" option
|
* the "trust exit code" option
|
||||||
* @return the return code from executed tool
|
* @return the return code from executed tool
|
||||||
|
* @throws ToolException
|
||||||
*/
|
*/
|
||||||
public int compare(String newPath, String oldPath, String newId,
|
public ExecutionResult compare(Repository repo, FileElement localFile,
|
||||||
String oldId, String toolName, BooleanTriState prompt,
|
FileElement remoteFile, String mergedFilePath, String toolName,
|
||||||
BooleanTriState gui, BooleanTriState trustExitCode) {
|
BooleanTriState prompt, BooleanTriState gui,
|
||||||
return 0;
|
BooleanTriState trustExitCode) throws ToolException {
|
||||||
|
ExternalDiffTool tool = guessTool(toolName, gui);
|
||||||
|
try {
|
||||||
|
File workingDir = repo.getWorkTree();
|
||||||
|
String localFilePath = localFile.getFile().getPath();
|
||||||
|
String remoteFilePath = remoteFile.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$
|
||||||
|
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$
|
||||||
|
boolean trust = config.isTrustExitCode();
|
||||||
|
if (trustExitCode != BooleanTriState.UNSET) {
|
||||||
|
trust = trustExitCode == BooleanTriState.TRUE;
|
||||||
|
}
|
||||||
|
CommandExecutor cmdExec = new CommandExecutor(repo.getFS(), trust);
|
||||||
|
return cmdExec.run(command, workingDir, env);
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
throw new ToolException(e);
|
||||||
|
} finally {
|
||||||
|
localFile.cleanTemporaries();
|
||||||
|
remoteFile.cleanTemporaries();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,41 +137,64 @@ public Map<String, ExternalDiffTool> getNotAvailableTools() {
|
||||||
*/
|
*/
|
||||||
public String getDefaultToolName(BooleanTriState gui) {
|
public String getDefaultToolName(BooleanTriState gui) {
|
||||||
return gui != BooleanTriState.UNSET ? "my_gui_tool" //$NON-NLS-1$
|
return gui != BooleanTriState.UNSET ? "my_gui_tool" //$NON-NLS-1$
|
||||||
: "my_default_toolname"; //$NON-NLS-1$
|
: config.getDefaultToolName();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return is interactive (config prompt enabled) ?
|
* @return is interactive (config prompt enabled) ?
|
||||||
*/
|
*/
|
||||||
public boolean isInteractive() {
|
public boolean isInteractive() {
|
||||||
return false;
|
return config.isPrompt();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupPredefinedTools() {
|
private ExternalDiffTool guessTool(String toolName, BooleanTriState gui)
|
||||||
predefinedTools = new TreeMap<>();
|
throws ToolException {
|
||||||
for (CommandLineDiffTool tool : CommandLineDiffTool.values()) {
|
if (StringUtils.isEmptyOrNull(toolName)) {
|
||||||
predefinedTools.put(tool.name(), new PreDefinedDiffTool(tool));
|
toolName = getDefaultToolName(gui);
|
||||||
}
|
}
|
||||||
|
ExternalDiffTool tool = getTool(toolName);
|
||||||
|
if (tool == null) {
|
||||||
|
throw new ToolException("Unknown diff tool " + toolName); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
return tool;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupUserDefinedTools() {
|
private ExternalDiffTool getTool(final String name) {
|
||||||
userDefinedTools = new TreeMap<>();
|
ExternalDiffTool tool = userDefinedTools.get(name);
|
||||||
Map<String, ExternalDiffTool> userTools = config.getTools();
|
if (tool == null) {
|
||||||
|
tool = predefinedTools.get(name);
|
||||||
|
}
|
||||||
|
return tool;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, ExternalDiffTool> setupPredefinedTools() {
|
||||||
|
Map<String, ExternalDiffTool> tools = new TreeMap<>();
|
||||||
|
for (CommandLineDiffTool tool : CommandLineDiffTool.values()) {
|
||||||
|
tools.put(tool.name(), new PreDefinedDiffTool(tool));
|
||||||
|
}
|
||||||
|
return tools;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, ExternalDiffTool> setupUserDefinedTools(
|
||||||
|
DiffToolConfig cfg, Map<String, ExternalDiffTool> predefTools) {
|
||||||
|
Map<String, ExternalDiffTool> tools = new TreeMap<>();
|
||||||
|
Map<String, ExternalDiffTool> userTools = cfg.getTools();
|
||||||
for (String name : userTools.keySet()) {
|
for (String name : userTools.keySet()) {
|
||||||
ExternalDiffTool userTool = userTools.get(name);
|
ExternalDiffTool userTool = userTools.get(name);
|
||||||
// if difftool.<name>.cmd is defined we have user defined tool
|
// if difftool.<name>.cmd is defined we have user defined tool
|
||||||
if (userTool.getCommand() != null) {
|
if (userTool.getCommand() != null) {
|
||||||
userDefinedTools.put(name, userTool);
|
tools.put(name, userTool);
|
||||||
} else if (userTool.getPath() != null) {
|
} else if (userTool.getPath() != null) {
|
||||||
// if difftool.<name>.path is defined we just overload the path
|
// if difftool.<name>.path is defined we just overload the path
|
||||||
// of predefined tool
|
// of predefined tool
|
||||||
PreDefinedDiffTool predefTool = (PreDefinedDiffTool) predefinedTools
|
PreDefinedDiffTool predefTool = (PreDefinedDiffTool) predefTools
|
||||||
.get(name);
|
.get(name);
|
||||||
if (predefTool != null) {
|
if (predefTool != null) {
|
||||||
predefTool.setPath(userTool.getPath());
|
predefTool.setPath(userTool.getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return tools;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2021, 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 java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.diff.DiffEntry;
|
||||||
|
import org.eclipse.jgit.lib.ObjectStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The element used as left or right file for compare.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class FileElement {
|
||||||
|
|
||||||
|
private final String path;
|
||||||
|
|
||||||
|
private final String id;
|
||||||
|
|
||||||
|
private ObjectStream stream;
|
||||||
|
|
||||||
|
private File tempFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param path
|
||||||
|
* the file path
|
||||||
|
* @param id
|
||||||
|
* the file id
|
||||||
|
*/
|
||||||
|
public FileElement(final String path, final String id) {
|
||||||
|
this(path, id, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param path
|
||||||
|
* the file path
|
||||||
|
* @param id
|
||||||
|
* the file id
|
||||||
|
* @param stream
|
||||||
|
* the object stream to load instead of file
|
||||||
|
*/
|
||||||
|
public FileElement(final String path, final String id,
|
||||||
|
ObjectStream stream) {
|
||||||
|
this.path = path;
|
||||||
|
this.id = id;
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the file path
|
||||||
|
*/
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the file id
|
||||||
|
*/
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param stream
|
||||||
|
* the object stream
|
||||||
|
*/
|
||||||
|
public void setStream(ObjectStream stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param workingDir the working directory used if file cannot be found (e.g. /dev/null)
|
||||||
|
* @return the object stream
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public File getFile(File workingDir) throws IOException {
|
||||||
|
if (tempFile != null) {
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
File file = new File(path);
|
||||||
|
String name = file.getName();
|
||||||
|
if (path.equals(DiffEntry.DEV_NULL)) {
|
||||||
|
file = new File(workingDir, "nul"); //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
else if (stream != null) {
|
||||||
|
tempFile = File.createTempFile(".__", "__" + name); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
try (OutputStream outStream = new FileOutputStream(tempFile)) {
|
||||||
|
int read = 0;
|
||||||
|
byte[] bytes = new byte[8 * 1024];
|
||||||
|
while ((read = stream.read(bytes)) != -1) {
|
||||||
|
outStream.write(bytes, 0, read);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// stream can only be consumed once --> close it
|
||||||
|
stream.close();
|
||||||
|
stream = null;
|
||||||
|
}
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a real file from work tree or a temporary file with content if
|
||||||
|
* stream is valid or if path is "/dev/null"
|
||||||
|
*
|
||||||
|
* @return the object stream
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public File getFile() throws IOException {
|
||||||
|
if (tempFile != null) {
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
File file = new File(path);
|
||||||
|
String name = file.getName();
|
||||||
|
// if we have a stream or file is missing ("/dev/null") then create
|
||||||
|
// temporary file
|
||||||
|
if ((stream != null) || path.equals(DiffEntry.DEV_NULL)) {
|
||||||
|
// TODO: avoid long random file name (number generated by
|
||||||
|
// createTempFile)
|
||||||
|
tempFile = File.createTempFile(".__", "__" + name); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
if (stream != null) {
|
||||||
|
try (OutputStream outStream = new FileOutputStream(tempFile)) {
|
||||||
|
int read = 0;
|
||||||
|
byte[] bytes = new byte[8 * 1024];
|
||||||
|
while ((read = stream.read(bytes)) != -1) {
|
||||||
|
outStream.write(bytes, 0, read);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// stream can only be consumed once --> close it
|
||||||
|
stream.close();
|
||||||
|
stream = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tempFile;
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes and invalidates temporary file if necessary.
|
||||||
|
*/
|
||||||
|
public void cleanTemporaries() {
|
||||||
|
if (tempFile != null && tempFile.exists())
|
||||||
|
tempFile.delete();
|
||||||
|
tempFile = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -46,17 +46,6 @@ public PreDefinedDiffTool(CommandLineDiffTool tool) {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void setPath(String path) {
|
public void setPath(String path) {
|
||||||
// handling of spaces in path
|
|
||||||
if (path.contains(" ")) { //$NON-NLS-1$
|
|
||||||
// add quotes before if needed
|
|
||||||
if (!path.startsWith("\"")) { //$NON-NLS-1$
|
|
||||||
path = "\"" + path; //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
// add quotes after if needed
|
|
||||||
if (!path.endsWith("\"")) { //$NON-NLS-1$
|
|
||||||
path = path + "\""; //$NON-NLS-1$
|
|
||||||
}
|
|
||||||
}
|
|
||||||
super.setPath(path);
|
super.setPath(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2021, 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.util.FS.ExecutionResult;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tool exception for differentiation.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ToolException extends Exception {
|
||||||
|
|
||||||
|
private final static Logger LOG = LoggerFactory
|
||||||
|
.getLogger(ToolException.class);
|
||||||
|
|
||||||
|
private final ExecutionResult result;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the serial version UID
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public ToolException() {
|
||||||
|
super();
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message
|
||||||
|
* the exception message
|
||||||
|
*/
|
||||||
|
public ToolException(String message) {
|
||||||
|
super(message);
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message
|
||||||
|
* the exception message
|
||||||
|
* @param result
|
||||||
|
* the execution result
|
||||||
|
*/
|
||||||
|
public ToolException(String message, ExecutionResult result) {
|
||||||
|
super(message);
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param message
|
||||||
|
* the exception message
|
||||||
|
* @param cause
|
||||||
|
* the cause for throw
|
||||||
|
*/
|
||||||
|
public ToolException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cause
|
||||||
|
* the cause for throw
|
||||||
|
*/
|
||||||
|
public ToolException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
result = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if result is valid, false else
|
||||||
|
*/
|
||||||
|
public boolean isResult() {
|
||||||
|
return result != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the execution result
|
||||||
|
*/
|
||||||
|
public ExecutionResult getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the result Stderr
|
||||||
|
*/
|
||||||
|
public String getResultStderr() {
|
||||||
|
try {
|
||||||
|
return new String(result.getStderr().toByteArray());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn(e.getMessage());
|
||||||
|
}
|
||||||
|
return ""; //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the result Stdout
|
||||||
|
*/
|
||||||
|
public String getResultStdout() {
|
||||||
|
try {
|
||||||
|
return new String(result.getStdout().toByteArray());
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn(e.getMessage());
|
||||||
|
}
|
||||||
|
return ""; //$NON-NLS-1$
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue