diff --git a/org.eclipse.jgit.java7/src/org/eclipse/jgit/util/FS_POSIX_Java7.java b/org.eclipse.jgit.java7/src/org/eclipse/jgit/util/FS_POSIX_Java7.java
index 4a73a9bcf..300cf93bc 100644
--- a/org.eclipse.jgit.java7/src/org/eclipse/jgit/util/FS_POSIX_Java7.java
+++ b/org.eclipse.jgit.java7/src/org/eclipse/jgit/util/FS_POSIX_Java7.java
@@ -53,6 +53,9 @@
import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+
/**
* FS implementation for Java7 on unix like systems
*/
@@ -344,4 +347,17 @@ public File normalize(File file) {
public String normalize(String name) {
return FileUtil.normalize(name);
}
+
+ /**
+ * @since 3.7
+ */
+ @Override
+ public File findHook(Repository repository, Hook hook) {
+ final File gitdir = repository.getDirectory();
+ final Path hookPath = gitdir.toPath().resolve(Constants.HOOKS)
+ .resolve(hook.getName());
+ if (Files.isExecutable(hookPath))
+ return hookPath.toFile();
+ return null;
+ }
}
diff --git a/org.eclipse.jgit.java7/src/org/eclipse/jgit/util/FS_Win32_Java7Cygwin.java b/org.eclipse.jgit.java7/src/org/eclipse/jgit/util/FS_Win32_Java7Cygwin.java
index e40d7cf0b..b6e5d9388 100644
--- a/org.eclipse.jgit.java7/src/org/eclipse/jgit/util/FS_Win32_Java7Cygwin.java
+++ b/org.eclipse.jgit.java7/src/org/eclipse/jgit/util/FS_Win32_Java7Cygwin.java
@@ -45,6 +45,11 @@
import java.io.File;
import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
/**
* FS for Java7 on Windows with Cygwin
@@ -135,4 +140,17 @@ public void createSymLink(File path, String target) throws IOException {
public Attributes getAttributes(File path) {
return FileUtil.getFileAttributesBasic(this, path);
}
+
+ /**
+ * @since 3.7
+ */
+ @Override
+ public File findHook(Repository repository, Hook hook) {
+ final File gitdir = repository.getDirectory();
+ final Path hookPath = gitdir.toPath().resolve(Constants.HOOKS)
+ .resolve(hook.getName());
+ if (Files.isExecutable(hookPath))
+ return hookPath.toFile();
+ return null;
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java
index 7b1627854..d4be25c0c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/FileUtilTest.java
@@ -50,6 +50,7 @@
import java.io.File;
import java.io.IOException;
+import java.util.regex.Matcher;
import org.eclipse.jgit.junit.JGitTestUtil;
import org.junit.After;
@@ -434,4 +435,82 @@ public void testCreateSymlink() throws IOException {
String target = fs.readSymLink(new File(trash, "x"));
assertEquals("y", target);
}
+
+ @Test
+ public void testRelativize_doc() {
+ // This is the javadoc example
+ String base = toOSPathString("c:\\Users\\jdoe\\eclipse\\git\\project");
+ String other = toOSPathString("c:\\Users\\jdoe\\eclipse\\git\\another_project\\pom.xml");
+ String expected = toOSPathString("..\\another_project\\pom.xml");
+
+ String actual = FileUtils.relativize(base, other);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testRelativize_mixedCase() {
+ SystemReader systemReader = SystemReader.getInstance();
+ String oldOSName = null;
+ String base = toOSPathString("C:\\git\\jgit");
+ String other = toOSPathString("C:\\Git\\test\\d\\f.txt");
+ String expectedWindows = toOSPathString("..\\test\\d\\f.txt");
+ String expectedUnix = toOSPathString("..\\..\\Git\\test\\d\\f.txt");
+
+ if (!systemReader.isWindows()) {
+ String actual = FileUtils.relativize(base, other);
+ assertEquals(expectedUnix, actual);
+
+ // FS_POSIX#isCaseSensitive will return "false" for mac OS X.
+ // Use this to test both behaviors.
+ oldOSName = System.getProperty("os.name");
+ try {
+ System.setProperty("os.name", "Mac OS X");
+
+ actual = FileUtils.relativize(base, other);
+ assertEquals(expectedWindows, actual);
+ } finally {
+ if (oldOSName != null)
+ System.setProperty("os.name", oldOSName);
+ }
+ } else {
+ String actual = FileUtils.relativize(base, other);
+ assertEquals(expectedWindows, actual);
+ }
+ }
+
+ @Test
+ public void testRelativize_scheme() {
+ String base = toOSPathString("file:/home/eclipse/runtime-New_configuration/project_1/file.java");
+ String other = toOSPathString("file:/home/eclipse/runtime-New_configuration/project");
+ // 'file.java' is treated as a folder
+ String expected = toOSPathString("../../project");
+
+ String actual = FileUtils.relativize(base, other);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testRelativize_equalPaths() {
+ String base = toOSPathString("file:/home/eclipse/runtime-New_configuration/project_1");
+ String other = toOSPathString("file:/home/eclipse/runtime-New_configuration/project_1");
+ String expected = "";
+
+ String actual = FileUtils.relativize(base, other);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testRelativize_whitespaces() {
+ String base = toOSPathString("/home/eclipse 3.4/runtime New_configuration/project_1");
+ String other = toOSPathString("/home/eclipse 3.4/runtime New_configuration/project_1/file");
+ String expected = "file";
+
+ String actual = FileUtils.relativize(base, other);
+ assertEquals(expected, actual);
+ }
+
+ private String toOSPathString(String path) {
+ return path.replaceAll("/|\\\\",
+ Matcher.quoteReplacement(File.separator));
+ }
}
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index 7e5f0b022..71ec6b2bc 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -193,6 +193,7 @@ errorListing=Error listing {0}
errorOccurredDuringUnpackingOnTheRemoteEnd=error occurred during unpacking on the remote end: {0}
errorReadingInfoRefs=error reading info/refs
errorSymlinksNotSupported=Symlinks are not supported with this OS/JRE
+exceptionCaughtDuringExecutionOfHook=Exception caught during execution of "{0}" hook.
exceptionCaughtDuringExecutionOfAddCommand=Exception caught during execution of add command
exceptionCaughtDuringExecutionOfArchiveCommand=Exception caught during execution of archive command
exceptionCaughtDuringExecutionOfCherryPickCommand=Exception caught during execution of cherry-pick command. {0}
@@ -206,6 +207,7 @@ exceptionCaughtDuringExecutionOfResetCommand=Exception caught during execution o
exceptionCaughtDuringExecutionOfRevertCommand=Exception caught during execution of revert command. {0}
exceptionCaughtDuringExecutionOfRmCommand=Exception caught during execution of rm command
exceptionCaughtDuringExecutionOfTagCommand=Exception caught during execution of tag command
+exceptionHookExecutionInterrupted=Execution of "{0}" hook interrupted.
exceptionOccurredDuringAddingOfOptionToALogCommand=Exception occurred during adding of {0} as option to a Log command
exceptionOccurredDuringReadingOfGIT_DIR=Exception occurred during reading of $GIT_DIR/{0}. {1}
exceptionWhileReadingPack=ERROR: Exception caught while accessing pack file {0}, the pack file might be corrupt
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index caf3e9072..138f40f7c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -252,6 +252,7 @@ public static JGitText get() {
/***/ public String errorOccurredDuringUnpackingOnTheRemoteEnd;
/***/ public String errorReadingInfoRefs;
/***/ public String errorSymlinksNotSupported;
+ /***/ public String exceptionCaughtDuringExecutionOfHook;
/***/ public String exceptionCaughtDuringExecutionOfAddCommand;
/***/ public String exceptionCaughtDuringExecutionOfArchiveCommand;
/***/ public String exceptionCaughtDuringExecutionOfCherryPickCommand;
@@ -265,6 +266,7 @@ public static JGitText get() {
/***/ public String exceptionCaughtDuringExecutionOfRevertCommand;
/***/ public String exceptionCaughtDuringExecutionOfRmCommand;
/***/ public String exceptionCaughtDuringExecutionOfTagCommand;
+ /***/ public String exceptionHookExecutionInterrupted;
/***/ public String exceptionOccurredDuringAddingOfOptionToALogCommand;
/***/ public String exceptionOccurredDuringReadingOfGIT_DIR;
/***/ public String exceptionWhileReadingPack;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
index 705d54cfa..ed0ed04d9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java
@@ -386,6 +386,13 @@ public final class Constants {
*/
public static final String MODULES = "modules";
+ /**
+ * Name of the folder (inside gitDir) where the hooks are stored.
+ *
+ * @since 3.7
+ */
+ public static final String HOOKS = "hooks";
+
/**
* Create a new digest function for objects.
*
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index 0c63b190f..081bf87c5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -44,18 +44,31 @@
package org.eclipse.jgit.util;
import java.io.BufferedReader;
+import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintStream;
+import java.io.PrintWriter;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.text.MessageFormat;
import java.util.Arrays;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.errors.SymlinksNotSupportedException;
import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.ProcessResult.Status;
/** Abstraction to support various file system operations not in Java. */
public abstract class FS {
@@ -613,6 +626,288 @@ public void createSymLink(File path, String target) throws IOException {
JGitText.get().errorSymlinksNotSupported);
}
+ /**
+ * See {@link FileUtils#relativize(String, String)}.
+ *
+ * @param base
+ * The path against which other
should be
+ * relativized.
+ * @param other
+ * The path that will be made relative to base
.
+ * @return A relative path that, when resolved against base
,
+ * will yield the original other
.
+ * @see FileUtils#relativize(String, String)
+ * @since 3.7
+ */
+ public String relativize(String base, String other) {
+ return FileUtils.relativize(base, other);
+ }
+
+ /**
+ * Checks whether the given hook is defined for the given repository, then
+ * runs it with the given arguments.
+ *
+ * The hook's standard output and error streams will be redirected to
+ * System.out
and System.err
respectively. The
+ * hook will have no stdin.
+ *
null
,
+ * but can be an empty array.
+ * @return The ProcessResult describing this hook's execution.
+ * @throws JGitInternalException
+ * if we fail to run the hook somehow. Causes may include an
+ * interrupted process or I/O errors.
+ * @since 3.7
+ */
+ public ProcessResult runIfPresent(Repository repository, final Hook hook,
+ String[] args) throws JGitInternalException {
+ return runIfPresent(repository, hook, args, System.out, System.err,
+ null);
+ }
+
+ /**
+ * Checks whether the given hook is defined for the given repository, then
+ * runs it with the given arguments.
+ *
+ * @param repository
+ * The repository for which a hook should be run.
+ * @param hook
+ * The hook to be executed.
+ * @param args
+ * Arguments to pass to this hook. Cannot be null
,
+ * but can be an empty array.
+ * @param outRedirect
+ * A print stream on which to redirect the hook's stdout. Can be
+ * null
, in which case the hook's standard output
+ * will be lost.
+ * @param errRedirect
+ * A print stream on which to redirect the hook's stderr. Can be
+ * null
, in which case the hook's standard error
+ * will be lost.
+ * @param stdinArgs
+ * A string to pass on to the standard input of the hook. May be
+ * null
.
+ * @return The ProcessResult describing this hook's execution.
+ * @throws JGitInternalException
+ * if we fail to run the hook somehow. Causes may include an
+ * interrupted process or I/O errors.
+ * @since 3.7
+ */
+ public ProcessResult runIfPresent(Repository repository, final Hook hook,
+ String[] args, PrintStream outRedirect, PrintStream errRedirect,
+ String stdinArgs) throws JGitInternalException {
+ return new ProcessResult(Status.NOT_SUPPORTED);
+ }
+
+ /**
+ * See
+ * {@link #runIfPresent(Repository, Hook, String[], PrintStream, PrintStream, String)}
+ * . Should only be called by FS supporting shell scripts execution.
+ *
+ * @param repository
+ * The repository for which a hook should be run.
+ * @param hook
+ * The hook to be executed.
+ * @param args
+ * Arguments to pass to this hook. Cannot be null
,
+ * but can be an empty array.
+ * @param outRedirect
+ * A print stream on which to redirect the hook's stdout. Can be
+ * null
, in which case the hook's standard output
+ * will be lost.
+ * @param errRedirect
+ * A print stream on which to redirect the hook's stderr. Can be
+ * null
, in which case the hook's standard error
+ * will be lost.
+ * @param stdinArgs
+ * A string to pass on to the standard input of the hook. May be
+ * null
.
+ * @return The ProcessResult describing this hook's execution.
+ * @throws JGitInternalException
+ * if we fail to run the hook somehow. Causes may include an
+ * interrupted process or I/O errors.
+ * @since 3.7
+ */
+ protected ProcessResult internalRunIfPresent(Repository repository,
+ final Hook hook, String[] args, PrintStream outRedirect,
+ PrintStream errRedirect, String stdinArgs)
+ throws JGitInternalException {
+ final File hookFile = findHook(repository, hook);
+ if (hookFile == null)
+ return new ProcessResult(Status.NOT_PRESENT);
+
+ final String hookPath = hookFile.getAbsolutePath();
+ final File runDirectory;
+ if (repository.isBare())
+ runDirectory = repository.getDirectory();
+ else
+ runDirectory = repository.getWorkTree();
+ final String cmd = relativize(runDirectory.getAbsolutePath(),
+ hookPath);
+ ProcessBuilder hookProcess = runInShell(cmd, args);
+ hookProcess.directory(runDirectory);
+ try {
+ return new ProcessResult(runProcess(hookProcess, outRedirect,
+ errRedirect, stdinArgs), Status.OK);
+ } catch (IOException e) {
+ throw new JGitInternalException(MessageFormat.format(
+ JGitText.get().exceptionCaughtDuringExecutionOfHook,
+ hook.getName()), e);
+ } catch (InterruptedException e) {
+ throw new JGitInternalException(MessageFormat.format(
+ JGitText.get().exceptionHookExecutionInterrupted,
+ hook.getName()), e);
+ }
+ }
+
+
+ /**
+ * Tries to find a hook matching the given one in the given repository.
+ *
+ * @param repository
+ * The repository within which to find a hook.
+ * @param hook
+ * The hook we're trying to find.
+ * @return The {@link File} containing this particular hook if it exists in
+ * the given repository, null
otherwise.
+ * @since 3.7
+ */
+ public File findHook(Repository repository, final Hook hook) {
+ final File hookFile = new File(new File(repository.getDirectory(),
+ Constants.HOOKS), hook.getName());
+ return hookFile.isFile() ? hookFile : null;
+ }
+
+ /**
+ * Runs the given process until termination, clearing its stdout and stderr
+ * streams on-the-fly.
+ *
+ * @param hookProcessBuilder
+ * The process builder configured for this hook.
+ * @param outRedirect
+ * A print stream on which to redirect the hook's stdout. Can be
+ * null
, in which case the hook's standard output
+ * will be lost.
+ * @param errRedirect
+ * A print stream on which to redirect the hook's stderr. Can be
+ * null
, in which case the hook's standard error
+ * will be lost.
+ * @param stdinArgs
+ * A string to pass on to the standard input of the hook. Can be
+ * null
.
+ * @return the exit value of this hook.
+ * @throws IOException
+ * if an I/O error occurs while executing this hook.
+ * @throws InterruptedException
+ * if the current thread is interrupted while waiting for the
+ * process to end.
+ * @since 3.7
+ */
+ protected int runProcess(ProcessBuilder hookProcessBuilder,
+ OutputStream outRedirect, OutputStream errRedirect, String stdinArgs)
+ throws IOException, InterruptedException {
+ final ExecutorService executor = Executors.newFixedThreadPool(2);
+ Process process = null;
+ // We'll record the first I/O exception that occurs, but keep on trying
+ // to dispose of our open streams and file handles
+ IOException ioException = null;
+ try {
+ process = hookProcessBuilder.start();
+ final Callable
+ *
+ * @param pool
+ * the pool to shutdown
+ * @return true
if the pool has been properly shutdown,
+ * false
otherwise.
+ */
+ private static boolean shutdownAndAwaitTermination(ExecutorService pool) {
+ boolean hasShutdown = true;
+ pool.shutdown(); // Disable new tasks from being submitted
+ try {
+ // Wait a while for existing tasks to terminate
+ if (!pool.awaitTermination(5, TimeUnit.SECONDS)) {
+ pool.shutdownNow(); // Cancel currently executing tasks
+ // Wait a while for tasks to respond to being canceled
+ if (!pool.awaitTermination(5, TimeUnit.SECONDS))
+ hasShutdown = false;
+ }
+ } catch (InterruptedException ie) {
+ // (Re-)Cancel if current thread also interrupted
+ pool.shutdownNow();
+ // Preserve interrupt status
+ Thread.currentThread().interrupt();
+ hasShutdown = false;
+ }
+ return hasShutdown;
+ }
+
/**
* Initialize a ProcesssBuilder to run a command using the system shell.
*
@@ -802,4 +1097,50 @@ public File normalize(File file) {
public String normalize(String name) {
return name;
}
+
+ /**
+ * This runnable will consume an input stream's content into an output
+ * stream as soon as it gets available.
+ *
+ * Typically used to empty processes' standard output and error, preventing + * them to choke. + *
+ *+ * Note that a {@link StreamGobbler} will never close either of its + * streams. + *
+ */ + private static class StreamGobbler implements Callable+ * For example, if this is called with the two following paths : + * + *
+ *+ * + * This will return "..\\another_project\\pom.xml". + * + *base = "c:\\Users\\jdoe\\eclipse\\git\\project"
+ *other = "c:\\Users\\jdoe\\eclipse\\git\\another_project\\pom.xml"
+ *
+ * This method uses {@link File#separator} to split the paths into segments. + *
+ *
+ * Note that this will return the empty String if base
+ * and other
are equal.
+ *
other
should be
+ * relativized. This will be assumed to denote the path to a
+ * folder and not a file.
+ * @param other
+ * The path that will be made relative to base
.
+ * @return A relative path that, when resolved against base
,
+ * will yield the original other
.
+ * @since 3.7
+ */
+ public static String relativize(String base, String other) {
+ if (base.equals(other))
+ return ""; //$NON-NLS-1$
+
+ final boolean ignoreCase = !FS.DETECTED.isCaseSensitive();
+ final String[] baseSegments = base.split(Pattern.quote(File.separator));
+ final String[] otherSegments = other.split(Pattern
+ .quote(File.separator));
+
+ int commonPrefix = 0;
+ while (commonPrefix < baseSegments.length
+ && commonPrefix < otherSegments.length) {
+ if (ignoreCase
+ && baseSegments[commonPrefix]
+ .equalsIgnoreCase(otherSegments[commonPrefix]))
+ commonPrefix++;
+ else if (!ignoreCase
+ && baseSegments[commonPrefix]
+ .equals(otherSegments[commonPrefix]))
+ commonPrefix++;
+ else
+ break;
+ }
+
+ final StringBuilder builder = new StringBuilder();
+ for (int i = commonPrefix; i < baseSegments.length; i++)
+ builder.append("..").append(File.separator); //$NON-NLS-1$
+ for (int i = commonPrefix; i < otherSegments.length; i++) {
+ builder.append(otherSegments[i]);
+ if (i < otherSegments.length - 1)
+ builder.append(File.separator);
+ }
+ return builder.toString();
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Hook.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Hook.java
new file mode 100644
index 000000000..c24c9a3d0
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Hook.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2014 Obeo.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.util;
+
+/**
+ * An enum describing the different hooks a user can implement to customize his
+ * repositories.
+ *
+ * @since 3.7
+ */
+public enum Hook {
+ /**
+ * Literal for the "pre-commit" git hook.
+ * + * This hook is invoked by git commit, and can be bypassed with the + * "no-verify" option. It takes no parameter, and is invoked before + * obtaining the proposed commit log message and making a commit. + *
+ *+ * A non-zero exit code from the called hook means that the commit should be + * aborted. + *
+ */ + PRE_COMMIT("pre-commit"), //$NON-NLS-1$ + + /** + * Literal for the "prepare-commit-msg" git hook. + *+ * This hook is invoked by git commit right after preparing the default + * message, and before any editing possibility is displayed to the user. + *
+ *+ * A non-zero exit code from the called hook means that the commit should be + * aborted. + *
+ */ + PREPARE_COMMIT_MSG("prepare-commit-msg"), //$NON-NLS-1$ + + /** + * Literal for the "commit-msg" git hook. + *+ * This hook is invoked by git commit, and can be bypassed with the + * "no-verify" option. Its single parameter is the path to the file + * containing the prepared commit message (typically + * "<gitdir>/COMMIT-EDITMSG"). + *
+ *+ * A non-zero exit code from the called hook means that the commit should be + * aborted. + *
+ */ + COMMIT_MSG("commit-msg"), //$NON-NLS-1$ + + /** + * Literal for the "post-commit" git hook. + *+ * This hook is invoked by git commit. It takes no parameter and is invoked + * after a commit has been made. + *
+ *+ * The exit code of this hook has no significance. + *
+ */ + POST_COMMIT("post-commit"), //$NON-NLS-1$ + + /** + * Literal for the "post-rewrite" git hook. + *
+ * This hook is invoked after commands that rewrite commits (currently, only
+ * "git rebase" and "git commit --amend"). It a single argument denoting the
+ * source of the call (one of rebase
or amend
). It
+ * then accepts a list of rewritten commits through stdin, in the form
+ * <old SHA-1> <new SHA-1>LF
.
+ *
+ * The exit code of this hook has no significance. + *
+ */ + POST_REWRITE("post-rewrite"), //$NON-NLS-1$ + + /** + * Literal for the "pre-rebase" git hook. + *+ *
+ * This hook is invoked right before the rebase operation runs. It accepts + * up to two parameters, the first being the upstream from which the branch + * to rebase has been forked. If the tip of the series of commits to rebase + * is HEAD, the other parameter is unset. Otherwise, that tip is passed as + * the second parameter of the script. + *+ * A non-zero exit code from the called hook means that the rebase should be + * aborted. + *
+ */ + PRE_REBASE("pre-rebase"); //$NON-NLS-1$ + + private final String name; + + private Hook(String name) { + this.name = name; + } + + /** + * @return The name of this hook. + */ + public String getName() { + return name; + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/ProcessResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/ProcessResult.java new file mode 100644 index 000000000..f56bb1577 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/ProcessResult.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2014 Obeo. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.util; + +/** + * Describes the result of running an external process. + * + * @since 3.7 + */ +public class ProcessResult { + /** + * Status of a process' execution. + */ + public static enum Status { + /** + * The script was found and launched properly. It may still have exited + * with a non-zero {@link #exitCode}. + */ + OK, + + /** The script was not found on disk and thus could not be launched. */ + NOT_PRESENT, + + /** + * The script was found but could not be launched since it was not + * supported by the current {@link FS}. + */ + NOT_SUPPORTED; + } + + /** The exit code of the process. */ + private final int exitCode; + + /** Status of the process' execution. */ + private final Status status; + + /** + * Instantiates a process result with the given status and an exit code of + *-1
.
+ *
+ * @param status
+ * Status describing the execution of the external process.
+ */
+ public ProcessResult(Status status) {
+ this(-1, status);
+ }
+
+ /**
+ * @param exitCode
+ * Exit code of the process.
+ * @param status
+ * Status describing the execution of the external process.
+ */
+ public ProcessResult(int exitCode, Status status) {
+ this.exitCode = exitCode;
+ this.status = status;
+ }
+
+ /**
+ * @return The exit code of the process.
+ */
+ public int getExitCode() {
+ return exitCode;
+ }
+
+ /**
+ * @return The status of the process' execution.
+ */
+ public Status getStatus() {
+ return status;
+ }
+}