summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.pgm
diff options
context:
space:
mode:
authorAndre Bossert <andre.bossert@siemens.com>2020-01-19 20:50:14 +0100
committerAndrey Loskutov <loskutov@gmx.de>2022-05-25 13:23:50 +0200
commitb63c2f39a16f1607cc65e82c0271c8c29a6038f1 (patch)
treebbb9e4155b28c72fb2bb986cfbe4c376c2f5cfce /org.eclipse.jgit.pgm
parent0c749d33ba59f864e18400141b2510398a8dd77c (diff)
downloadjgit-b63c2f39a16f1607cc65e82c0271c8c29a6038f1.tar.gz
jgit-b63c2f39a16f1607cc65e82c0271c8c29a6038f1.zip
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>
Diffstat (limited to 'org.eclipse.jgit.pgm')
-rw-r--r--org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties2
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java100
2 files changed, 71 insertions, 31 deletions
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index fda0bf6ff4..3653b9d8fc 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -60,7 +60,7 @@ deletedBranch=Deleted 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.
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
dontOverwriteLocalChanges=error: Your local changes to the following file would be overwritten by merge:
everythingUpToDate=Everything up-to-date
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java
index 128881779b..2f74177452 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java
@@ -21,8 +21,10 @@ import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
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.Side;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.AmbiguousObjectException;
@@ -30,8 +32,11 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.internal.diffmergetool.DiffTools;
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.ObjectReader;
+import org.eclipse.jgit.lib.ObjectStream;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.TextProgressMonitor;
import org.eclipse.jgit.lib.internal.BooleanTriState;
@@ -40,8 +45,10 @@ import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.util.StringUtils;
+import org.eclipse.jgit.util.FS.ExecutionResult;
import org.kohsuke.args4j.Argument;
import org.kohsuke.args4j.Option;
@@ -145,40 +152,54 @@ class DiffTool extends TextBuiltin {
private void compare(List<DiffEntry> files, boolean showPrompt,
String toolNamePrompt) throws IOException {
- for (int fileIndex = 0; fileIndex < files.size(); fileIndex++) {
- DiffEntry ent = files.get(fileIndex);
- String mergedFilePath = ent.getNewPath();
- if (mergedFilePath.equals(DiffEntry.DEV_NULL)) {
- mergedFilePath = ent.getOldPath();
- }
- // check if user wants to launch compare
- boolean launchCompare = true;
- if (showPrompt) {
- launchCompare = isLaunchCompare(fileIndex + 1, files.size(),
- mergedFilePath, toolNamePrompt);
- }
- if (launchCompare) {
- switch (ent.getChangeType()) {
- case MODIFY:
- outw.println("M\t" + ent.getNewPath() //$NON-NLS-1$
- + " (" + ent.getNewId().name() + ")" //$NON-NLS-1$ //$NON-NLS-2$
- + "\t" + ent.getOldPath() //$NON-NLS-1$
- + " (" + ent.getOldId().name() + ")"); //$NON-NLS-1$ //$NON-NLS-2$
- int ret = diffTools.compare(ent.getNewPath(),
- ent.getOldPath(), ent.getNewId().name(),
- ent.getOldId().name(), toolName, prompt, gui,
- trustExitCode);
- if (ret != 0) {
+ ContentSource.Pair sourcePair = new ContentSource.Pair(source(oldTree),
+ source(newTree));
+ try {
+ for (int fileIndex = 0; fileIndex < files.size(); fileIndex++) {
+ DiffEntry ent = files.get(fileIndex);
+ String mergedFilePath = ent.getNewPath();
+ if (mergedFilePath.equals(DiffEntry.DEV_NULL)) {
+ mergedFilePath = ent.getOldPath();
+ }
+ FileElement local = new FileElement(ent.getOldPath(),
+ ent.getOldId().name(),
+ getObjectStream(sourcePair, Side.OLD, ent));
+ FileElement remote = new FileElement(ent.getNewPath(),
+ ent.getNewId().name(),
+ getObjectStream(sourcePair, Side.NEW, ent));
+ // check if user wants to launch compare
+ boolean launchCompare = true;
+ if (showPrompt) {
+ launchCompare = isLaunchCompare(fileIndex + 1, files.size(),
+ mergedFilePath, toolNamePrompt);
+ }
+ if (launchCompare) {
+ try {
+ // 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(
- CLIText.get().diffToolDied, mergedFilePath));
+ CLIText.get().diffToolDied, mergedFilePath, e));
}
- break;
- default:
+ } else {
break;
}
- } else {
- break;
}
+ } finally {
+ sourcePair.close();
}
}
@@ -254,4 +275,23 @@ class DiffTool extends TextBuiltin {
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());
+ }
+
}