aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java251
1 files changed, 251 insertions, 0 deletions
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..e5947102eb
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/diffmergetool/ExternalToolUtils.java
@@ -0,0 +1,251 @@
+/*
+ * 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.File;
+import java.io.IOException;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import org.eclipse.jgit.attributes.Attributes;
+import org.eclipse.jgit.errors.RevisionSyntaxException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.WorkingTreeIterator;
+import org.eclipse.jgit.treewalk.filter.NotIgnoredFilter;
+import org.eclipse.jgit.util.FS;
+
+/**
+ * Utilities for diff- and merge-tools.
+ */
+public class ExternalToolUtils {
+
+ /**
+ * Key for merge tool git configuration section
+ */
+ public static final String KEY_MERGE_TOOL = "mergetool"; //$NON-NLS-1$
+
+ /**
+ * Key for diff tool git configuration section
+ */
+ public static final String KEY_DIFF_TOOL = "difftool"; //$NON-NLS-1$
+
+ /**
+ * 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
+ * if an IO error occurred
+ */
+ public static String prepareCommand(String command, FileElement localFile,
+ FileElement remoteFile, FileElement mergedFile,
+ FileElement baseFile) throws IOException {
+ if (localFile != null) {
+ command = localFile.replaceVariable(command);
+ }
+ if (remoteFile != null) {
+ command = remoteFile.replaceVariable(command);
+ }
+ if (mergedFile != null) {
+ command = mergedFile.replaceVariable(command);
+ }
+ if (baseFile != null) {
+ command = baseFile.replaceVariable(command);
+ }
+ return command;
+ }
+
+ /**
+ * Prepare environment needed for execution.
+ *
+ * @param gitDir
+ * the .git directory
+ * @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
+ * if an IO error occurred
+ */
+ public static Map<String, String> prepareEnvironment(File gitDir,
+ FileElement localFile, FileElement remoteFile,
+ FileElement mergedFile, FileElement baseFile) throws IOException {
+ Map<String, String> env = new TreeMap<>();
+ if (gitDir != null) {
+ env.put(Constants.GIT_DIR_KEY, gitDir.getAbsolutePath());
+ }
+ if (localFile != null) {
+ localFile.addToEnv(env);
+ }
+ if (remoteFile != null) {
+ remoteFile.addToEnv(env);
+ }
+ if (mergedFile != null) {
+ mergedFile.addToEnv(env);
+ }
+ if (baseFile != null) {
+ baseFile.addToEnv(env);
+ }
+ return env;
+ }
+
+ /**
+ * Quote path
+ *
+ * @param path
+ * the path to be quoted
+ * @return quoted path if it contains spaces
+ */
+ @SuppressWarnings("nls")
+ public static String quotePath(String path) {
+ // handling of spaces in path
+ if (path.contains(" ")) {
+ // add quotes before if needed
+ if (!path.startsWith("\"")) {
+ path = "\"" + path;
+ }
+ // add quotes after if needed
+ if (!path.endsWith("\"")) {
+ path = path + "\"";
+ }
+ }
+ return path;
+ }
+
+ /**
+ * Whether tool is available
+ *
+ * @param fs
+ * the file system abstraction
+ * @param gitDir
+ * the .git directory
+ * @param directory
+ * the working directory
+ * @param path
+ * the tool path
+ * @return true if tool available and false otherwise
+ */
+ public static boolean isToolAvailable(FS fs, File gitDir, File directory,
+ String path) {
+ boolean available = true;
+ try {
+ CommandExecutor cmdExec = new CommandExecutor(fs, false);
+ available = cmdExec.checkExecutable(path, directory,
+ prepareEnvironment(gitDir, null, null, null, null));
+ } catch (Exception e) {
+ available = false;
+ }
+ return available;
+ }
+
+ /**
+ * Create sorted tool set
+ *
+ * @param defaultName
+ * the default tool name
+ * @param userDefinedNames
+ * the user defined tool names
+ * @param preDefinedNames
+ * the pre defined tool names
+ * @return the sorted tool names set: first element is default tool name if
+ * valid, then user defined tool names and then pre defined tool
+ * names
+ */
+ public static Set<String> createSortedToolSet(String defaultName,
+ Set<String> userDefinedNames, Set<String> preDefinedNames) {
+ Set<String> names = new LinkedHashSet<>();
+ if (defaultName != null) {
+ // remove defaultName from both sets
+ Set<String> namesPredef = new LinkedHashSet<>();
+ Set<String> namesUser = new LinkedHashSet<>();
+ namesUser.addAll(userDefinedNames);
+ namesUser.remove(defaultName);
+ namesPredef.addAll(preDefinedNames);
+ namesPredef.remove(defaultName);
+ // add defaultName as first in set
+ names.add(defaultName);
+ names.addAll(namesUser);
+ names.addAll(namesPredef);
+ } else {
+ names.addAll(userDefinedNames);
+ names.addAll(preDefinedNames);
+ }
+ return names;
+ }
+
+ /**
+ * Provides {@link Optional} with the name of an external tool if specified
+ * in git configuration for a path.
+ *
+ * The formed git configuration results from global rules as well as merged
+ * rules from info and worktree attributes.
+ *
+ * Triggers {@link TreeWalk} until specified path found in the tree.
+ *
+ * @param repository
+ * target repository to traverse into
+ * @param path
+ * path to the node in repository to parse git attributes for
+ * @param toolKey
+ * config key name for the tool
+ * @return attribute value for the given tool key if set
+ * @throws ToolException
+ * if the tool failed
+ */
+ public static Optional<String> getExternalToolFromAttributes(
+ final Repository repository, final String path,
+ final String toolKey) throws ToolException {
+ try {
+ WorkingTreeIterator treeIterator = new FileTreeIterator(repository);
+ try (TreeWalk walk = new TreeWalk(repository)) {
+ walk.addTree(treeIterator);
+ walk.setFilter(new NotIgnoredFilter(0));
+ while (walk.next()) {
+ String treePath = walk.getPathString();
+ if (treePath.equals(path)) {
+ Attributes attrs = walk.getAttributes();
+ if (attrs.containsKey(toolKey)) {
+ return Optional.of(attrs.getValue(toolKey));
+ }
+ }
+ if (walk.isSubtree()) {
+ walk.enterSubtree();
+ }
+ }
+ // no external tool specified
+ return Optional.empty();
+ }
+
+ } catch (RevisionSyntaxException | IOException e) {
+ throw new ToolException(e);
+ }
+ }
+
+}