summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java55
-rw-r--r--org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ToolTestCase.java49
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/DiffTool.java94
-rw-r--r--org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java85
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java16
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalMergeToolTest.java13
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java12
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java41
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java81
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/FileElement.java196
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java94
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ToolException.java4
12 files changed, 483 insertions, 257 deletions
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java
index dc34c0d67b..8daaa6ad9e 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/DiffToolTest.java
@@ -21,10 +21,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.internal.diffmergetool.CommandLineDiffTool;
import org.eclipse.jgit.lib.StoredConfig;
-import org.eclipse.jgit.revwalk.RevCommit;
import org.junit.Before;
import org.junit.Test;
@@ -49,9 +47,8 @@ public class DiffToolTest extends ToolTestCase {
"y", // accept launching diff tool
};
- RevCommit commit = createUnstagedChanges();
- List<DiffEntry> changes = getRepositoryChanges(commit);
- String[] expectedOutput = getExpectedCompareOutput(changes);
+ String[] conflictingFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedCompareOutput(conflictingFilenames);
String option = "--tool";
@@ -68,10 +65,9 @@ public class DiffToolTest extends ToolTestCase {
"n", // don't launch diff tool
};
- RevCommit commit = createUnstagedChanges();
- List<DiffEntry> changes = getRepositoryChanges(commit);
+ String[] conflictingFilenames = createUnstagedChanges();
int abortIndex = 1;
- String[] expectedOutput = getExpectedAbortOutput(changes, abortIndex);
+ String[] expectedOutput = getExpectedAbortOutput(conflictingFilenames, abortIndex);
String option = "--tool";
@@ -92,9 +88,8 @@ public class DiffToolTest extends ToolTestCase {
@Test
public void testTool() throws Exception {
- RevCommit commit = createUnstagedChanges();
- List<DiffEntry> changes = getRepositoryChanges(commit);
- String[] expectedOutput = getExpectedToolOutputNoPrompt(changes);
+ String[] conflictFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedToolOutputNoPrompt(conflictFilenames);
String[] options = {
"--tool",
@@ -111,9 +106,8 @@ public class DiffToolTest extends ToolTestCase {
@Test
public void testToolTrustExitCode() throws Exception {
- RevCommit commit = createUnstagedChanges();
- List<DiffEntry> changes = getRepositoryChanges(commit);
- String[] expectedOutput = getExpectedToolOutputNoPrompt(changes);
+ String[] conflictingFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedToolOutputNoPrompt(conflictingFilenames);
String[] options = { "--tool", "-t", };
@@ -126,9 +120,8 @@ public class DiffToolTest extends ToolTestCase {
@Test
public void testToolNoGuiNoPromptNoTrustExitcode() throws Exception {
- RevCommit commit = createUnstagedChanges();
- List<DiffEntry> changes = getRepositoryChanges(commit);
- String[] expectedOutput = getExpectedToolOutputNoPrompt(changes);
+ String[] conflictingFilenames = createUnstagedChanges();
+ String[] expectedOutput = getExpectedToolOutputNoPrompt(conflictingFilenames);
String[] options = { "--tool", "-t", };
@@ -142,9 +135,8 @@ public class DiffToolTest extends ToolTestCase {
@Test
public void testToolCached() throws Exception {
- RevCommit commit = createStagedChanges();
- List<DiffEntry> changes = getRepositoryChanges(commit);
- String[] expectedOutput = getExpectedToolOutputNoPrompt(changes);
+ String[] conflictingFilenames = createStagedChanges();
+ String[] expectedOutput = getExpectedToolOutputNoPrompt(conflictingFilenames);
String[] options = { "--cached", "--staged", };
@@ -201,23 +193,21 @@ public class DiffToolTest extends ToolTestCase {
String.valueOf(false));
}
- private static String[] getExpectedToolOutputNoPrompt(List<DiffEntry> changes) {
- String[] expectedToolOutput = new String[changes.size()];
- for (int i = 0; i < changes.size(); ++i) {
- DiffEntry change = changes.get(i);
- String newPath = change.getNewPath();
+ private static String[] getExpectedToolOutputNoPrompt(String[] conflictingFilenames) {
+ String[] expectedToolOutput = new String[conflictingFilenames.length];
+ for (int i = 0; i < conflictingFilenames.length; ++i) {
+ String newPath = conflictingFilenames[i];
String expectedLine = newPath;
expectedToolOutput[i] = expectedLine;
}
return expectedToolOutput;
}
- private static String[] getExpectedCompareOutput(List<DiffEntry> changes) {
+ private static String[] getExpectedCompareOutput(String[] conflictingFilenames) {
List<String> expected = new ArrayList<>();
- int n = changes.size();
+ int n = conflictingFilenames.length;
for (int i = 0; i < n; ++i) {
- DiffEntry change = changes.get(i);
- String newPath = change.getNewPath();
+ String newPath = conflictingFilenames[i];
expected.add(
"Viewing (" + (i + 1) + "/" + n + "): '" + newPath + "'");
expected.add("Launch '" + TOOL_NAME + "' [Y/n]?");
@@ -226,13 +216,12 @@ public class DiffToolTest extends ToolTestCase {
return expected.toArray(new String[0]);
}
- private static String[] getExpectedAbortOutput(List<DiffEntry> changes,
+ private static String[] getExpectedAbortOutput(String[] conflictingFilenames,
int abortIndex) {
List<String> expected = new ArrayList<>();
- int n = changes.size();
+ int n = conflictingFilenames.length;
for (int i = 0; i < n; ++i) {
- DiffEntry change = changes.get(i);
- String newPath = change.getNewPath();
+ String newPath = conflictingFilenames[i];
expected.add(
"Viewing (" + (i + 1) + "/" + n + "): '" + newPath + "'");
expected.add("Launch '" + TOOL_NAME + "' [Y/n]?");
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ToolTestCase.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ToolTestCase.java
index d13eeb7e4d..933f19bcc4 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ToolTestCase.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ToolTestCase.java
@@ -94,15 +94,15 @@ public abstract class ToolTestCase extends CLIRepositoryTestCase {
protected String[] createMergeConflict() throws Exception {
// create files on initial branch
git.checkout().setName(TEST_BRANCH_NAME).call();
- writeTrashFile("a", "Hello world a");
- writeTrashFile("b", "Hello world b");
+ writeTrashFile("dir1/a", "Hello world a");
+ writeTrashFile("dir2/b", "Hello world b");
git.add().addFilepattern(".").call();
git.commit().setMessage("files a & b added").call();
// create another branch and change files
git.branchCreate().setName("branch_1").call();
git.checkout().setName("branch_1").call();
- writeTrashFile("a", "Hello world a 1");
- writeTrashFile("b", "Hello world b 1");
+ writeTrashFile("dir1/a", "Hello world a 1");
+ writeTrashFile("dir2/b", "Hello world b 1");
git.add().addFilepattern(".").call();
RevCommit commit1 = git.commit()
.setMessage("files a & b modified commit 1").call();
@@ -111,28 +111,28 @@ public abstract class ToolTestCase extends CLIRepositoryTestCase {
// create another branch and change files
git.branchCreate().setName("branch_2").call();
git.checkout().setName("branch_2").call();
- writeTrashFile("a", "Hello world a 2");
- writeTrashFile("b", "Hello world b 2");
+ writeTrashFile("dir1/a", "Hello world a 2");
+ writeTrashFile("dir2/b", "Hello world b 2");
git.add().addFilepattern(".").call();
git.commit().setMessage("files a & b modified commit 2").call();
// cherry-pick conflicting changes
git.cherryPick().include(commit1).call();
- String[] conflictingFilenames = { "a", "b" };
+ String[] conflictingFilenames = { "dir1/a", "dir2/b" };
return conflictingFilenames;
}
protected String[] createDeletedConflict() throws Exception {
// create files on initial branch
git.checkout().setName(TEST_BRANCH_NAME).call();
- writeTrashFile("a", "Hello world a");
- writeTrashFile("b", "Hello world b");
+ writeTrashFile("dir1/a", "Hello world a");
+ writeTrashFile("dir2/b", "Hello world b");
git.add().addFilepattern(".").call();
git.commit().setMessage("files a & b added").call();
// create another branch and change files
git.branchCreate().setName("branch_1").call();
git.checkout().setName("branch_1").call();
- writeTrashFile("a", "Hello world a 1");
- writeTrashFile("b", "Hello world b 1");
+ writeTrashFile("dir1/a", "Hello world a 1");
+ writeTrashFile("dir2/b", "Hello world b 1");
git.add().addFilepattern(".").call();
RevCommit commit1 = git.commit()
.setMessage("files a & b modified commit 1").call();
@@ -141,29 +141,30 @@ public abstract class ToolTestCase extends CLIRepositoryTestCase {
// create another branch and change files
git.branchCreate().setName("branch_2").call();
git.checkout().setName("branch_2").call();
- git.rm().addFilepattern("a").call();
- git.rm().addFilepattern("b").call();
+ git.rm().addFilepattern("dir1/a").call();
+ git.rm().addFilepattern("dir2/b").call();
git.commit().setMessage("files a & b deleted commit 2").call();
// cherry-pick conflicting changes
git.cherryPick().include(commit1).call();
- String[] conflictingFilenames = { "a", "b" };
+ String[] conflictingFilenames = { "dir1/a", "dir2/b" };
return conflictingFilenames;
}
- protected RevCommit createUnstagedChanges() throws Exception {
- writeTrashFile("a", "Hello world a");
- writeTrashFile("b", "Hello world b");
+ protected String[] createUnstagedChanges() throws Exception {
+ writeTrashFile("dir1/a", "Hello world a");
+ writeTrashFile("dir2/b", "Hello world b");
git.add().addFilepattern(".").call();
- RevCommit commit = git.commit().setMessage("files a & b").call();
- writeTrashFile("a", "New Hello world a");
- writeTrashFile("b", "New Hello world b");
- return commit;
+ git.commit().setMessage("files a & b").call();
+ writeTrashFile("dir1/a", "New Hello world a");
+ writeTrashFile("dir2/b", "New Hello world b");
+ String[] conflictingFilenames = { "dir1/a", "dir2/b" };
+ return conflictingFilenames;
}
- protected RevCommit createStagedChanges() throws Exception {
- RevCommit commit = createUnstagedChanges();
+ protected String[] createStagedChanges() throws Exception {
+ String[] conflictingFilenames = createUnstagedChanges();
git.add().addFilepattern(".").call();
- return commit;
+ return conflictingFilenames;
}
protected List<DiffEntry> getRepositoryChanges(RevCommit commit)
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 ffba36fe20..74d91cd3d7 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
@@ -11,9 +11,11 @@
package org.eclipse.jgit.pgm;
import static org.eclipse.jgit.lib.Constants.HEAD;
+import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
@@ -25,27 +27,36 @@ 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.internal.diffmergetool.ToolException;
+import org.eclipse.jgit.internal.diffmergetool.DiffTools;
+import org.eclipse.jgit.internal.diffmergetool.FileElement;
+import org.eclipse.jgit.internal.diffmergetool.ExternalDiffTool;
import org.eclipse.jgit.diff.DiffFormatter;
+import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata;
import org.eclipse.jgit.errors.AmbiguousObjectException;
+import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.NoWorkTreeException;
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.Constants;
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.CoreConfig.EolStreamType;
import org.eclipse.jgit.lib.internal.BooleanTriState;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.pgm.opt.PathTreeFilterHandler;
+import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.AbstractTreeIterator;
import org.eclipse.jgit.treewalk.CanonicalTreeParser;
import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.treewalk.WorkingTreeIterator;
+import org.eclipse.jgit.treewalk.WorkingTreeOptions;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
import org.eclipse.jgit.util.StringUtils;
import org.eclipse.jgit.util.FS.ExecutionResult;
@@ -164,12 +175,6 @@ class DiffTool extends TextBuiltin {
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) {
@@ -178,15 +183,20 @@ class DiffTool extends TextBuiltin {
}
if (launchCompare) {
try {
- // TODO: check how to return the exit-code of
- // the
- // tool
- // to
- // jgit / java runtime ?
+ FileElement local = createFileElement(
+ FileElement.Type.LOCAL, sourcePair, Side.OLD,
+ ent);
+ FileElement remote = createFileElement(
+ FileElement.Type.REMOTE, sourcePair, Side.NEW,
+ ent);
+ FileElement merged = new FileElement(mergedFilePath,
+ FileElement.Type.MERGED);
+ // 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);
+ ExecutionResult result = diffTools.compare(local,
+ remote, merged, toolName, prompt, gui,
+ trustExitCode);
outw.println(new String(result.getStdout().toByteArray()));
errw.println(
new String(result.getStderr().toByteArray()));
@@ -278,16 +288,46 @@ 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;
+ private FileElement createFileElement(FileElement.Type elementType,
+ Pair pair, Side side, DiffEntry entry)
+ throws NoWorkTreeException, CorruptObjectException, IOException,
+ ToolException {
+ String entryPath = side == Side.NEW ? entry.getNewPath()
+ : entry.getOldPath();
+ FileElement fileElement = new FileElement(entryPath, elementType);
+ if (!pair.isWorkingTreeSource(side) && !fileElement.isNullPath()) {
+ try (RevWalk revWalk = new RevWalk(db);
+ TreeWalk treeWalk = new TreeWalk(db,
+ revWalk.getObjectReader())) {
+ treeWalk.setFilter(
+ PathFilterGroup.createFromStrings(entryPath));
+ if (side == Side.NEW) {
+ newTree.reset();
+ treeWalk.addTree(newTree);
+ } else {
+ oldTree.reset();
+ treeWalk.addTree(oldTree);
+ }
+ if (treeWalk.next()) {
+ final EolStreamType eolStreamType = treeWalk
+ .getEolStreamType(CHECKOUT_OP);
+ final String filterCommand = treeWalk.getFilterCommand(
+ Constants.ATTR_FILTER_TYPE_SMUDGE);
+ WorkingTreeOptions opt = db.getConfig()
+ .get(WorkingTreeOptions.KEY);
+ CheckoutMetadata checkoutMetadata = new CheckoutMetadata(
+ eolStreamType, filterCommand);
+ DirCacheCheckout.getContent(db, entryPath,
+ checkoutMetadata, pair.open(side, entry), opt,
+ new FileOutputStream(
+ fileElement.createTempFile(null)));
+ } else {
+ throw new ToolException("Cannot find path '" + entryPath //$NON-NLS-1$
+ + "' in staging area!", null); //$NON-NLS-1$
+ }
}
}
- return stream;
+ return fileElement;
}
private ContentSource source(AbstractTreeIterator iterator) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java
index dce5a7996d..9712770758 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeTool.java
@@ -10,8 +10,11 @@
package org.eclipse.jgit.pgm;
+import static org.eclipse.jgit.treewalk.TreeWalk.OperationType.CHECKOUT_OP;
+
import java.io.BufferedReader;
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.MessageFormat;
@@ -26,8 +29,12 @@ import org.eclipse.jgit.api.Status;
import org.eclipse.jgit.api.StatusCommand;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.diff.ContentSource;
+import org.eclipse.jgit.internal.diffmergetool.FileElement.Type;
import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata;
import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.errors.RevisionSyntaxException;
import org.eclipse.jgit.internal.diffmergetool.ExternalMergeTool;
@@ -35,9 +42,15 @@ import org.eclipse.jgit.internal.diffmergetool.FileElement;
import org.eclipse.jgit.internal.diffmergetool.MergeTools;
import org.eclipse.jgit.internal.diffmergetool.ToolException;
import org.eclipse.jgit.lib.IndexDiff.StageState;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.WorkingTreeOptions;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.internal.BooleanTriState;
+import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
import org.eclipse.jgit.pgm.internal.CLIText;
import org.eclipse.jgit.util.FS.ExecutionResult;
import org.kohsuke.args4j.Argument;
@@ -188,32 +201,67 @@ class MergeTool extends TextBuiltin {
ContentSource baseSource = ContentSource.create(db.newObjectReader());
ContentSource localSource = ContentSource.create(db.newObjectReader());
ContentSource remoteSource = ContentSource.create(db.newObjectReader());
+ // temporary directory if mergetool.writeToTemp == true
+ File tempDir = mergeTools.createTempDirectory();
+ // the parent directory for temp files (can be same as tempDir or just
+ // the worktree dir)
+ File tempFilesParent = tempDir != null ? tempDir : db.getWorkTree();
try {
FileElement base = null;
FileElement local = null;
FileElement remote = null;
+ FileElement merged = new FileElement(mergedFilePath,
+ Type.MERGED);
DirCache cache = db.readDirCache();
- int firstIndex = cache.findEntry(mergedFilePath);
- if (firstIndex >= 0) {
- int nextIndex = cache.nextEntry(firstIndex);
- for (; firstIndex < nextIndex; firstIndex++) {
- DirCacheEntry entry = cache.getEntry(firstIndex);
+ try (RevWalk revWalk = new RevWalk(db);
+ TreeWalk treeWalk = new TreeWalk(db,
+ revWalk.getObjectReader())) {
+ treeWalk.setFilter(
+ PathFilterGroup.createFromStrings(mergedFilePath));
+ DirCacheIterator cacheIter = new DirCacheIterator(cache);
+ treeWalk.addTree(cacheIter);
+ while (treeWalk.next()) {
+ if (treeWalk.isSubtree()) {
+ treeWalk.enterSubtree();
+ continue;
+ }
+ final EolStreamType eolStreamType = treeWalk
+ .getEolStreamType(CHECKOUT_OP);
+ final String filterCommand = treeWalk.getFilterCommand(
+ Constants.ATTR_FILTER_TYPE_SMUDGE);
+ WorkingTreeOptions opt = db.getConfig()
+ .get(WorkingTreeOptions.KEY);
+ CheckoutMetadata checkoutMetadata = new CheckoutMetadata(
+ eolStreamType, filterCommand);
+ DirCacheEntry entry = treeWalk.getTree(DirCacheIterator.class).getDirCacheEntry();
+ if (entry == null) {
+ continue;
+ }
ObjectId id = entry.getObjectId();
switch (entry.getStage()) {
case DirCacheEntry.STAGE_1:
- base = new FileElement(mergedFilePath, id.name(),
- baseSource.open(mergedFilePath, id)
- .openStream());
+ base = new FileElement(mergedFilePath, Type.BASE);
+ DirCacheCheckout.getContent(db, mergedFilePath,
+ checkoutMetadata,
+ baseSource.open(mergedFilePath, id), opt,
+ new FileOutputStream(
+ base.createTempFile(tempFilesParent)));
break;
case DirCacheEntry.STAGE_2:
- local = new FileElement(mergedFilePath, id.name(),
- localSource.open(mergedFilePath, id)
- .openStream());
+ local = new FileElement(mergedFilePath, Type.LOCAL);
+ DirCacheCheckout.getContent(db, mergedFilePath,
+ checkoutMetadata,
+ localSource.open(mergedFilePath, id), opt,
+ new FileOutputStream(
+ local.createTempFile(tempFilesParent)));
break;
case DirCacheEntry.STAGE_3:
- remote = new FileElement(mergedFilePath, id.name(),
- remoteSource.open(mergedFilePath, id)
- .openStream());
+ remote = new FileElement(mergedFilePath, Type.REMOTE);
+ DirCacheCheckout.getContent(db, mergedFilePath,
+ checkoutMetadata,
+ remoteSource.open(mergedFilePath, id), opt,
+ new FileOutputStream(remote
+ .createTempFile(tempFilesParent)));
break;
}
}
@@ -222,14 +270,13 @@ class MergeTool extends TextBuiltin {
throw die(MessageFormat.format(CLIText.get().mergeToolDied,
mergedFilePath));
}
- File merged = new File(mergedFilePath);
- long modifiedBefore = merged.lastModified();
+ long modifiedBefore = merged.getFile().lastModified();
try {
// TODO: check how to return the exit-code of the
// tool to jgit / java runtime ?
// int rc =...
- ExecutionResult executionResult = mergeTools.merge(db, local,
- remote, base, mergedFilePath, toolName, prompt, gui);
+ ExecutionResult executionResult = mergeTools.merge(local,
+ remote, merged, base, tempDir, toolName, prompt, gui);
outw.println(
new String(executionResult.getStdout().toByteArray()));
outw.flush();
@@ -250,7 +297,7 @@ class MergeTool extends TextBuiltin {
}
// if merge was successful check file modified
if (isMergeSuccessful) {
- long modifiedAfter = merged.lastModified();
+ long modifiedAfter = merged.getFile().lastModified();
if (modifiedBefore == modifiedAfter) {
outw.println(MessageFormat.format(
CLIText.get().mergeToolFileUnchanged,
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java
index ebc67c81cb..4fd55c6cad 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalDiffToolTest.java
@@ -54,8 +54,8 @@ public class ExternalDiffToolTest extends ExternalToolTestCase {
BooleanTriState gui = BooleanTriState.UNSET;
BooleanTriState trustExitCode = BooleanTriState.TRUE;
- manager.compare(db, local, remote, merged.getPath(), toolName, prompt,
- gui, trustExitCode);
+ manager.compare(local, remote, merged, toolName, prompt, gui,
+ trustExitCode);
fail("Expected exception to be thrown due to external tool exiting with error code: "
+ errorReturnCode);
@@ -78,8 +78,8 @@ public class ExternalDiffToolTest extends ExternalToolTestCase {
BooleanTriState gui = BooleanTriState.UNSET;
BooleanTriState trustExitCode = BooleanTriState.FALSE;
- manager.compare(db, local, remote, merged.getPath(), toolName, prompt,
- gui, trustExitCode);
+ manager.compare(local, remote, merged, toolName, prompt, gui,
+ trustExitCode);
fail("Expected exception to be thrown due to external tool exiting with error code: "
+ errorReturnCode);
@@ -183,8 +183,8 @@ public class ExternalDiffToolTest extends ExternalToolTestCase {
DiffTools manager = new DiffTools(db);
int expectedCompareResult = 0;
- ExecutionResult compareResult = manager.compare(db, local, remote,
- merged.getPath(), toolName, prompt, gui, trustExitCode);
+ ExecutionResult compareResult = manager.compare(local, remote, merged,
+ toolName, prompt, gui, trustExitCode);
assertEquals("Incorrect compare result for external diff tool",
expectedCompareResult, compareResult.getRc());
}
@@ -263,8 +263,8 @@ public class ExternalDiffToolTest extends ExternalToolTestCase {
BooleanTriState gui = BooleanTriState.UNSET;
BooleanTriState trustExitCode = BooleanTriState.UNSET;
- manager.compare(db, local, remote, merged.getPath(), toolName, prompt,
- gui, trustExitCode);
+ manager.compare(local, remote, merged, toolName, prompt, gui,
+ trustExitCode);
fail("Expected exception to be thrown due to not defined external diff tool");
}
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
index 1dea44eaac..50576682eb 100644
--- 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
@@ -55,8 +55,7 @@ public class ExternalMergeToolTest extends ExternalToolTestCase {
BooleanTriState prompt = BooleanTriState.UNSET;
BooleanTriState gui = BooleanTriState.UNSET;
- manager.merge(db, local, remote, base, merged.getPath(), toolName,
- prompt, gui);
+ manager.merge(local, remote, merged, base, null, toolName, prompt, gui);
fail("Expected exception to be thrown due to external tool exiting with error code: "
+ errorReturnCode);
@@ -78,8 +77,7 @@ public class ExternalMergeToolTest extends ExternalToolTestCase {
BooleanTriState prompt = BooleanTriState.UNSET;
BooleanTriState gui = BooleanTriState.UNSET;
- manager.merge(db, local, remote, base, merged.getPath(), toolName,
- prompt, gui);
+ manager.merge(local, remote, merged, base, null, toolName, prompt, gui);
fail("Expected exception to be thrown due to external tool exiting with error code: "
+ errorReturnCode);
@@ -182,8 +180,8 @@ public class ExternalMergeToolTest extends ExternalToolTestCase {
MergeTools manager = new MergeTools(db);
int expectedCompareResult = 0;
- ExecutionResult compareResult = manager.merge(db, local, remote, base,
- merged.getPath(), toolName, prompt, gui);
+ ExecutionResult compareResult = manager.merge(local, remote, merged,
+ base, null, toolName, prompt, gui);
assertEquals("Incorrect compare result for external merge tool",
expectedCompareResult, compareResult.getRc());
}
@@ -262,8 +260,7 @@ public class ExternalMergeToolTest extends ExternalToolTestCase {
BooleanTriState prompt = BooleanTriState.UNSET;
BooleanTriState gui = BooleanTriState.UNSET;
- manager.merge(db, local, remote, base, merged.getPath(), toolName,
- prompt, gui);
+ manager.merge(local, remote, merged, base, null, toolName, prompt, gui);
fail("Expected exception to be thrown due to not defined external merge tool");
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java
index 6757eb4635..0fd85cb456 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/diffmergetool/ExternalToolTestCase.java
@@ -60,10 +60,14 @@ public abstract class ExternalToolTestCase extends RepositoryTestCase {
commandResult = writeTrashFile("commandResult.txt", "");
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");
+ local = new FileElement(localFile.getAbsolutePath(),
+ FileElement.Type.LOCAL);
+ remote = new FileElement(remoteFile.getAbsolutePath(),
+ FileElement.Type.REMOTE);
+ merged = new FileElement(mergedFile.getAbsolutePath(),
+ FileElement.Type.MERGED);
+ base = new FileElement(baseFile.getAbsolutePath(),
+ FileElement.Type.BASE);
}
@After
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java
index 2f2b9de818..1dcc523bf8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/DiffTools.java
@@ -12,12 +12,10 @@ package org.eclipse.jgit.internal.diffmergetool;
import java.util.TreeMap;
import java.util.Collections;
-import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
-import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.internal.BooleanTriState;
import org.eclipse.jgit.util.FS.ExecutionResult;
@@ -28,6 +26,8 @@ import org.eclipse.jgit.util.StringUtils;
*/
public class DiffTools {
+ private final Repository repo;
+
private final DiffToolConfig config;
private final Map<String, ExternalDiffTool> predefinedTools;
@@ -41,6 +41,7 @@ public class DiffTools {
* the repository
*/
public DiffTools(Repository repo) {
+ this.repo = repo;
config = repo.getConfig().get(DiffToolConfig.KEY);
predefinedTools = setupPredefinedTools();
userDefinedTools = setupUserDefinedTools(config, predefinedTools);
@@ -49,14 +50,13 @@ public class DiffTools {
/**
* Compare two versions of a file.
*
- * @param repo
- * the repository
* @param localFile
* the local file element
* @param remoteFile
* the remote file element
- * @param mergedFilePath
- * the path of 'merged' file, it equals local or remote path
+ * @param mergedFile
+ * the merged file element, it's path equals local or remote
+ * element path
* @param toolName
* the selected tool name (can be null)
* @param prompt
@@ -68,36 +68,31 @@ public class DiffTools {
* @return the execution result from tool
* @throws ToolException
*/
- public ExecutionResult compare(Repository repo, FileElement localFile,
- FileElement remoteFile, String mergedFilePath, String toolName,
+ public ExecutionResult compare(FileElement localFile,
+ FileElement remoteFile, FileElement mergedFile, String toolName,
BooleanTriState prompt, BooleanTriState gui,
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$
+ // prepare the command (replace the file paths)
+ String command = ExternalToolUtils.prepareCommand(
+ guessTool(toolName, gui).getCommand(), localFile,
+ remoteFile, mergedFile, null);
+ // prepare the environment
+ Map<String, String> env = ExternalToolUtils.prepareEnvironment(repo,
+ localFile, remoteFile, mergedFile, null);
boolean trust = config.isTrustExitCode();
if (trustExitCode != BooleanTriState.UNSET) {
trust = trustExitCode == BooleanTriState.TRUE;
}
+ // execute the tool
CommandExecutor cmdExec = new CommandExecutor(repo.getFS(), trust);
- return cmdExec.run(command, workingDir, env);
+ return cmdExec.run(command, repo.getWorkTree(), env);
} catch (IOException | InterruptedException e) {
throw new ToolException(e);
} finally {
localFile.cleanTemporaries();
remoteFile.cleanTemporaries();
+ mergedFile.cleanTemporaries();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java
new file mode 100644
index 0000000000..3efb90c490
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java
@@ -0,0 +1,81 @@
+/*
+ * 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.util.TreeMap;
+import java.io.IOException;
+import java.util.Map;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * Utilities for diff- and merge-tools.
+ */
+public class ExternalToolUtils {
+
+ /**
+ * Prepare command for execution.
+ *
+ * @param command
+ * the input "command" string
+ * @param localFile
+ * the local file (ours)
+ * @param remoteFile
+ * the remote file (theirs)
+ * @param mergedFile
+ * the merged file (worktree)
+ * @param baseFile
+ * the base file (can be null)
+ * @return the prepared (with replaced variables) command string
+ * @throws IOException
+ */
+ public static String prepareCommand(String command, FileElement localFile,
+ FileElement remoteFile, FileElement mergedFile,
+ FileElement baseFile) throws IOException {
+ command = localFile.replaceVariable(command);
+ command = remoteFile.replaceVariable(command);
+ command = mergedFile.replaceVariable(command);
+ if (baseFile != null) {
+ command = baseFile.replaceVariable(command);
+ }
+ return command;
+ }
+
+ /**
+ * Prepare environment needed for execution.
+ *
+ * @param repo
+ * the repository
+ * @param localFile
+ * the local file (ours)
+ * @param remoteFile
+ * the remote file (theirs)
+ * @param mergedFile
+ * the merged file (worktree)
+ * @param baseFile
+ * the base file (can be null)
+ * @return the environment map with variables and values (file paths)
+ * @throws IOException
+ */
+ public static Map<String, String> prepareEnvironment(Repository repo,
+ FileElement localFile, FileElement remoteFile,
+ FileElement mergedFile, FileElement baseFile) throws IOException {
+ Map<String, String> env = new TreeMap<>();
+ env.put(Constants.GIT_DIR_KEY, repo.getDirectory().getAbsolutePath());
+ localFile.addToEnv(env);
+ remoteFile.addToEnv(env);
+ mergedFile.addToEnv(env);
+ if (baseFile != null) {
+ baseFile.addToEnv(env);
+ }
+ return env;
+ }
+
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/FileElement.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/FileElement.java
index 1ae87aaa62..5902c1e1b8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/FileElement.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/FileElement.java
@@ -14,10 +14,11 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Map;
import org.eclipse.jgit.diff.DiffEntry;
-import org.eclipse.jgit.lib.ObjectStream;
/**
* The element used as left or right file for compare.
@@ -25,36 +26,71 @@ import org.eclipse.jgit.lib.ObjectStream;
*/
public class FileElement {
+ /**
+ * The file element type.
+ *
+ */
+ public enum Type {
+ /**
+ * The local file element (ours).
+ */
+ LOCAL,
+ /**
+ * The remote file element (theirs).
+ */
+ REMOTE,
+ /**
+ * The merged file element (path in worktree).
+ */
+ MERGED,
+ /**
+ * The base file element (of ours and theirs).
+ */
+ BASE,
+ /**
+ * The backup file element (copy of merged / conflicted).
+ */
+ BACKUP
+ }
+
private final String path;
- private final String id;
+ private final Type type;
- private ObjectStream stream;
+ private InputStream stream;
private File tempFile;
/**
+ * Creates file element for path.
+ *
* @param path
* the file path
- * @param id
- * the file id
+ * @param type
+ * the element type
*/
- public FileElement(final String path, final String id) {
- this(path, id, null);
+ public FileElement(String path, Type type) {
+ this(path, type, null, null);
}
/**
+ * Creates file element for path.
+ *
* @param path
* the file path
- * @param id
- * the file id
+ * @param type
+ * the element type
+ * @param tempFile
+ * the temporary file to be used (can be null and will be created
+ * then)
* @param stream
* the object stream to load instead of file
*/
- public FileElement(final String path, final String id,
- ObjectStream stream) {
+ public FileElement(String path, Type type, File tempFile,
+ InputStream stream) {
this.path = path;
- this.id = id;
+ this.type = type;
+ this.tempFile = tempFile;
this.stream = stream;
}
@@ -66,71 +102,101 @@ public class FileElement {
}
/**
- * @return the file id
+ * @return the element type
*/
- public String getId() {
- return id;
+ public Type getType() {
+ return type;
}
/**
- * @param stream
- * the object stream
- */
- public void setStream(ObjectStream stream) {
- this.stream = stream;
- }
-
- /**
- * Returns a temporary file with in passed working directory and fills it
- * with stream if valid.
+ * Return a temporary file within passed directory and fills it with stream
+ * if valid.
*
* @param directory
- * the working directory where the temporary file is created
+ * the directory where the temporary file is created
* @param midName
* name added in the middle of generated temporary file name
* @return the object stream
* @throws IOException
*/
public File getFile(File directory, String midName) throws IOException {
- if (tempFile != null) {
+ if ((tempFile != null) && (stream == null)) {
return tempFile;
}
- String[] fileNameAndExtension = splitBaseFileNameAndExtension(
- new File(path));
- tempFile = File.createTempFile(
- fileNameAndExtension[0] + "_" + midName + "_", //$NON-NLS-1$ //$NON-NLS-2$
- fileNameAndExtension[1], directory);
- copyFromStream();
- return tempFile;
+ tempFile = getTempFile(path, directory, midName);
+ return copyFromStream(tempFile, stream);
}
/**
- * Returns a real file from work tree or a temporary file with content if
+ * Return 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) {
+ if ((tempFile != null) && (stream == 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$
- copyFromStream();
- return tempFile;
+ if ((stream != null) || isNullPath()) {
+ tempFile = getTempFile(file);
+ return copyFromStream(tempFile, stream);
}
return file;
}
/**
- * Deletes and invalidates temporary file if necessary.
+ * Check if path id "/dev/null"
+ *
+ * @return true if path is "/dev/null"
+ */
+ public boolean isNullPath() {
+ return path.equals(DiffEntry.DEV_NULL);
+ }
+
+ /**
+ * Create temporary file in given or system temporary directory
+ *
+ * @param directory
+ * the directory for the file (can be null); if null system
+ * temporary directory is used
+ * @return temporary file in directory or in the system temporary directory
+ * @throws IOException
+ */
+ public File createTempFile(File directory) throws IOException {
+ if (tempFile == null) {
+ File file = new File(path);
+ if (directory != null) {
+ tempFile = getTempFile(file, directory, type.name());
+ } else {
+ tempFile = getTempFile(file);
+ }
+ }
+ return tempFile;
+ }
+
+ private static File getTempFile(File file) throws IOException {
+ return File.createTempFile(".__", "__" + file.getName()); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ private static File getTempFile(File file, File directory, String midName)
+ throws IOException {
+ String[] fileNameAndExtension = splitBaseFileNameAndExtension(file);
+ return File.createTempFile(
+ fileNameAndExtension[0] + "_" + midName + "_", //$NON-NLS-1$ //$NON-NLS-2$
+ fileNameAndExtension[1], directory);
+ }
+
+ private static File getTempFile(String path, File directory, String midName)
+ throws IOException {
+ return getTempFile(new File(path), directory, midName);
+ }
+
+ /**
+ * Delete and invalidate temporary file if necessary.
*/
public void cleanTemporaries() {
if (tempFile != null && tempFile.exists())
@@ -138,9 +204,10 @@ public class FileElement {
tempFile = null;
}
- private void copyFromStream() throws IOException, FileNotFoundException {
+ private static File copyFromStream(File file, final InputStream stream)
+ throws IOException, FileNotFoundException {
if (stream != null) {
- try (OutputStream outStream = new FileOutputStream(tempFile)) {
+ try (OutputStream outStream = new FileOutputStream(file)) {
int read = 0;
byte[] bytes = new byte[8 * 1024];
while ((read = stream.read(bytes)) != -1) {
@@ -149,23 +216,46 @@ public class FileElement {
} finally {
// stream can only be consumed once --> close it
stream.close();
- stream = null;
}
}
+ return file;
}
private static String[] splitBaseFileNameAndExtension(File file) {
String[] result = new String[2];
result[0] = file.getName();
result[1] = ""; //$NON-NLS-1$
- if (!result[0].startsWith(".")) { //$NON-NLS-1$
- int idx = result[0].lastIndexOf("."); //$NON-NLS-1$
- if (idx != -1) {
- result[1] = result[0].substring(idx, result[0].length());
- result[0] = result[0].substring(0, idx);
- }
+ int idx = result[0].lastIndexOf("."); //$NON-NLS-1$
+ // if "." was found (>-1) and last-index is not first char (>0), then
+ // split (same behavior like cgit)
+ if (idx > 0) {
+ result[1] = result[0].substring(idx, result[0].length());
+ result[0] = result[0].substring(0, idx);
}
return result;
}
+ /**
+ * Replace variable in input
+ *
+ * @param input
+ * the input string
+ * @return the replaced input string
+ * @throws IOException
+ */
+ public String replaceVariable(String input) throws IOException {
+ return input.replace("$" + type.name(), getFile().getPath()); //$NON-NLS-1$
+ }
+
+ /**
+ * Add variable to environment map.
+ *
+ * @param env
+ * the environment where this element should be added
+ * @throws IOException
+ */
+ public void addToEnv(Map<String, String> env) throws IOException {
+ env.put(type.name(), getFile().getPath());
+ }
+
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java
index c4c2ceccff..9a2a8304eb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/MergeTools.java
@@ -19,7 +19,7 @@ import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
-import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.internal.diffmergetool.FileElement.Type;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.internal.BooleanTriState;
import org.eclipse.jgit.util.FS.ExecutionResult;
@@ -29,6 +29,8 @@ import org.eclipse.jgit.util.FS.ExecutionResult;
*/
public class MergeTools {
+ Repository repo;
+
private final MergeToolConfig config;
private final Map<String, ExternalMergeTool> predefinedTools;
@@ -37,25 +39,27 @@ public class MergeTools {
/**
* @param repo
- * the repository database
+ * the repository
*/
public MergeTools(Repository repo) {
+ this.repo = repo;
config = repo.getConfig().get(MergeToolConfig.KEY);
predefinedTools = setupPredefinedTools();
userDefinedTools = setupUserDefinedTools(config, predefinedTools);
}
/**
- * @param repo
- * the repository
* @param localFile
* the local file element
* @param remoteFile
* the remote file element
+ * @param mergedFile
+ * the merged file element
* @param baseFile
* the base file element (can be null)
- * @param mergedFilePath
- * the path of 'merged' file
+ * @param tempDir
+ * the temporary directory (needed for backup and auto-remove,
+ * can be null)
* @param toolName
* the selected tool name (can be null)
* @param prompt
@@ -65,47 +69,35 @@ public class MergeTools {
* @return the execution result from tool
* @throws ToolException
*/
- public ExecutionResult merge(Repository repo, FileElement localFile,
- FileElement remoteFile, FileElement baseFile, String mergedFilePath,
+ public ExecutionResult merge(FileElement localFile, FileElement remoteFile,
+ FileElement mergedFile, FileElement baseFile, File tempDir,
String toolName, BooleanTriState prompt, BooleanTriState gui)
throws ToolException {
ExternalMergeTool tool = guessTool(toolName, gui);
FileElement backup = null;
- File tempDir = null;
ExecutionResult result = null;
try {
File workingDir = repo.getWorkTree();
- // crate temp-directory or use working directory
- tempDir = config.isWriteToTemp()
- ? Files.createTempDirectory("jgit-mergetool-").toFile() //$NON-NLS-1$
- : workingDir;
// create additional backup file (copy worktree file)
- backup = createBackupFile(mergedFilePath, tempDir);
- // get local, remote and base file paths
- String localFilePath = localFile.getFile(tempDir, "LOCAL") //$NON-NLS-1$
- .getPath();
- String remoteFilePath = remoteFile.getFile(tempDir, "REMOTE") //$NON-NLS-1$
- .getPath();
- String baseFilePath = ""; //$NON-NLS-1$
- if (baseFile != null) {
- baseFilePath = baseFile.getFile(tempDir, "BASE").getPath(); //$NON-NLS-1$
- }
+ backup = createBackupFile(mergedFile.getPath(),
+ tempDir != null ? tempDir : workingDir);
// prepare the command (replace the file paths)
boolean trust = tool.getTrustExitCode() == BooleanTriState.TRUE;
- String command = prepareCommand(mergedFilePath, localFilePath,
- remoteFilePath, baseFilePath,
- tool.getCommand(baseFile != null));
+ String command = ExternalToolUtils.prepareCommand(
+ tool.getCommand(baseFile != null), localFile, remoteFile,
+ mergedFile, baseFile);
// prepare the environment
- Map<String, String> env = prepareEnvironment(repo, mergedFilePath,
- localFilePath, remoteFilePath, baseFilePath);
+ Map<String, String> env = ExternalToolUtils.prepareEnvironment(repo,
+ localFile, remoteFile, mergedFile, baseFile);
+ // execute the tool
CommandExecutor cmdExec = new CommandExecutor(repo.getFS(), trust);
result = cmdExec.run(command, workingDir, env);
// keep backup as .orig file
if (backup != null) {
- keepBackupFile(mergedFilePath, backup);
+ keepBackupFile(mergedFile.getPath(), backup);
}
return result;
- } catch (Exception e) {
+ } catch (IOException | InterruptedException e) {
throw new ToolException(e);
} finally {
// always delete backup file (ignore that it was may be already
@@ -131,19 +123,30 @@ public class MergeTools {
}
}
- private static FileElement createBackupFile(String mergedFilePath,
- File tempDir) throws IOException {
+ private FileElement createBackupFile(String filePath, File parentDir)
+ throws IOException {
FileElement backup = null;
- Path path = Paths.get(tempDir.getPath(), mergedFilePath);
+ Path path = Paths.get(filePath);
if (Files.exists(path)) {
- backup = new FileElement(mergedFilePath, "NOID", null); //$NON-NLS-1$
- Files.copy(path, backup.getFile(tempDir, "BACKUP").toPath(), //$NON-NLS-1$
+ backup = new FileElement(filePath, Type.BACKUP);
+ Files.copy(path, backup.createTempFile(parentDir).toPath(),
StandardCopyOption.REPLACE_EXISTING);
}
return backup;
}
/**
+ * @return the created temporary directory if (mergetol.writeToTemp == true)
+ * or null if not configured or false.
+ * @throws IOException
+ */
+ public File createTempDirectory() throws IOException {
+ return config.isWriteToTemp()
+ ? Files.createTempDirectory("jgit-mergetool-").toFile() //$NON-NLS-1$
+ : null;
+ }
+
+ /**
* @return the tool names
*/
public Set<String> getToolNames() {
@@ -208,27 +211,6 @@ public class MergeTools {
return tool;
}
- private String prepareCommand(String mergedFilePath, String localFilePath,
- String remoteFilePath, String baseFilePath, String command) {
- command = command.replace("$LOCAL", localFilePath); //$NON-NLS-1$
- command = command.replace("$REMOTE", remoteFilePath); //$NON-NLS-1$
- command = command.replace("$MERGED", mergedFilePath); //$NON-NLS-1$
- command = command.replace("$BASE", baseFilePath); //$NON-NLS-1$
- return command;
- }
-
- private Map<String, String> prepareEnvironment(Repository repo,
- String mergedFilePath, String localFilePath, String remoteFilePath,
- String baseFilePath) {
- Map<String, String> env = new TreeMap<>();
- env.put(Constants.GIT_DIR_KEY, repo.getDirectory().getAbsolutePath());
- env.put("LOCAL", localFilePath); //$NON-NLS-1$
- env.put("REMOTE", remoteFilePath); //$NON-NLS-1$
- env.put("MERGED", mergedFilePath); //$NON-NLS-1$
- env.put("BASE", baseFilePath); //$NON-NLS-1$
- return env;
- }
-
private void keepBackupFile(String mergedFilePath, FileElement backup)
throws IOException {
if (config.isKeepBackup()) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ToolException.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ToolException.java
index 1ae0780ac8..27f7d12e66 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ToolException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ToolException.java
@@ -113,7 +113,7 @@ public class ToolException extends Exception {
try {
return new String(result.getStderr().toByteArray());
} catch (Exception e) {
- LOG.warn(e.getMessage());
+ LOG.warn("Failed to retrieve standard error output", e); //$NON-NLS-1$
}
return ""; //$NON-NLS-1$
}
@@ -125,7 +125,7 @@ public class ToolException extends Exception {
try {
return new String(result.getStdout().toByteArray());
} catch (Exception e) {
- LOG.warn(e.getMessage());
+ LOG.warn("Failed to retrieve standard output", e); //$NON-NLS-1$
}
return ""; //$NON-NLS-1$
}