diff options
author | Andre Bossert <andre.bossert@siemens.com> | 2020-01-19 20:50:14 +0100 |
---|---|---|
committer | Andrey Loskutov <loskutov@gmx.de> | 2022-05-25 13:23:50 +0200 |
commit | b63c2f39a16f1607cc65e82c0271c8c29a6038f1 (patch) | |
tree | bbb9e4155b28c72fb2bb986cfbe4c376c2f5cfce /org.eclipse.jgit.pgm | |
parent | 0c749d33ba59f864e18400141b2510398a8dd77c (diff) | |
download | jgit-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.properties | 2 | ||||
-rw-r--r-- | org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java | 100 |
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()); + } + } |