Support for core.hooksPath
Support the core.hooksPath git config. This can be an absolute or relative path of a directory where to find git hooks; a relative path is resolved relative to the directory the hook will run in. Bug: 500266 Change-Id: I671999a6386a837e897c31718583c91d8035f3ba Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
parent
b138f16945
commit
385b503ae8
|
@ -58,6 +58,8 @@
|
|||
import org.eclipse.jgit.hooks.PreCommitHook;
|
||||
import org.eclipse.jgit.junit.JGitTestUtil;
|
||||
import org.eclipse.jgit.junit.RepositoryTestCase;
|
||||
import org.eclipse.jgit.lib.ConfigConstants;
|
||||
import org.eclipse.jgit.lib.StoredConfig;
|
||||
import org.eclipse.jgit.revwalk.RevCommit;
|
||||
import org.junit.Assume;
|
||||
import org.junit.Test;
|
||||
|
@ -220,6 +222,75 @@ public void testRunHook() throws Exception {
|
|||
res.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunHookHooksPathRelative() throws Exception {
|
||||
assumeSupportedPlatform();
|
||||
|
||||
writeHookFile(PreCommitHook.NAME,
|
||||
"#!/bin/sh\necho \"Wrong hook $1 $2\"\nread INPUT\necho $INPUT\n"
|
||||
+ "echo $GIT_DIR\necho $GIT_WORK_TREE\necho 1>&2 \"stderr\"");
|
||||
writeHookFile("../../" + PreCommitHook.NAME,
|
||||
"#!/bin/sh\necho \"test $1 $2\"\nread INPUT\necho $INPUT\n"
|
||||
+ "echo $GIT_DIR\necho $GIT_WORK_TREE\necho 1>&2 \"stderr\"");
|
||||
StoredConfig cfg = db.getConfig();
|
||||
cfg.load();
|
||||
cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
|
||||
ConfigConstants.CONFIG_KEY_HOOKS_PATH, ".");
|
||||
cfg.save();
|
||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream err = new ByteArrayOutputStream()) {
|
||||
ProcessResult res = FS.DETECTED.runHookIfPresent(db,
|
||||
PreCommitHook.NAME, new String[] { "arg1", "arg2" },
|
||||
new PrintStream(out), new PrintStream(err), "stdin");
|
||||
|
||||
assertEquals("unexpected hook output",
|
||||
"test arg1 arg2\nstdin\n"
|
||||
+ db.getDirectory().getAbsolutePath() + '\n'
|
||||
+ db.getWorkTree().getAbsolutePath() + '\n',
|
||||
out.toString("UTF-8"));
|
||||
assertEquals("unexpected output on stderr stream", "stderr\n",
|
||||
err.toString("UTF-8"));
|
||||
assertEquals("unexpected exit code", 0, res.getExitCode());
|
||||
assertEquals("unexpected process status", ProcessResult.Status.OK,
|
||||
res.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunHookHooksPathAbsolute() throws Exception {
|
||||
assumeSupportedPlatform();
|
||||
|
||||
writeHookFile(PreCommitHook.NAME,
|
||||
"#!/bin/sh\necho \"Wrong hook $1 $2\"\nread INPUT\necho $INPUT\n"
|
||||
+ "echo $GIT_DIR\necho $GIT_WORK_TREE\necho 1>&2 \"stderr\"");
|
||||
writeHookFile("../../" + PreCommitHook.NAME,
|
||||
"#!/bin/sh\necho \"test $1 $2\"\nread INPUT\necho $INPUT\n"
|
||||
+ "echo $GIT_DIR\necho $GIT_WORK_TREE\necho 1>&2 \"stderr\"");
|
||||
StoredConfig cfg = db.getConfig();
|
||||
cfg.load();
|
||||
cfg.setString(ConfigConstants.CONFIG_CORE_SECTION, null,
|
||||
ConfigConstants.CONFIG_KEY_HOOKS_PATH,
|
||||
db.getWorkTree().getAbsolutePath());
|
||||
cfg.save();
|
||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteArrayOutputStream err = new ByteArrayOutputStream()) {
|
||||
ProcessResult res = FS.DETECTED.runHookIfPresent(db,
|
||||
PreCommitHook.NAME, new String[] { "arg1", "arg2" },
|
||||
new PrintStream(out), new PrintStream(err), "stdin");
|
||||
|
||||
assertEquals("unexpected hook output",
|
||||
"test arg1 arg2\nstdin\n"
|
||||
+ db.getDirectory().getAbsolutePath() + '\n'
|
||||
+ db.getWorkTree().getAbsolutePath() + '\n',
|
||||
out.toString("UTF-8"));
|
||||
assertEquals("unexpected output on stderr stream", "stderr\n",
|
||||
err.toString("UTF-8"));
|
||||
assertEquals("unexpected exit code", 0, res.getExitCode());
|
||||
assertEquals("unexpected process status", ProcessResult.Status.OK,
|
||||
res.getStatus());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailedPreCommitHookBlockCommit() throws Exception {
|
||||
assumeSupportedPlatform();
|
||||
|
|
|
@ -348,6 +348,7 @@ invalidFilter=Invalid filter: {0}
|
|||
invalidGitdirRef = Invalid .git reference in file ''{0}''
|
||||
invalidGitModules=Invalid .gitmodules file
|
||||
invalidGitType=invalid git type: {0}
|
||||
invalidHooksPath=Invalid git config core.hooksPath = {0}
|
||||
invalidId=Invalid id: {0}
|
||||
invalidId0=Invalid id
|
||||
invalidIdLength=Invalid id length {0}; should be {1}
|
||||
|
|
|
@ -162,9 +162,14 @@ protected void doRun() throws AbortedByHookException {
|
|||
} catch (UnsupportedEncodingException e) {
|
||||
// UTF-8 is guaranteed to be available
|
||||
}
|
||||
ProcessResult result = FS.DETECTED.runHookIfPresent(getRepository(),
|
||||
getHookName(), getParameters(), getOutputStream(),
|
||||
hookErrRedirect, getStdinArgs());
|
||||
Repository repository = getRepository();
|
||||
FS fs = repository.getFS();
|
||||
if (fs == null) {
|
||||
fs = FS.DETECTED;
|
||||
}
|
||||
ProcessResult result = fs.runHookIfPresent(repository, getHookName(),
|
||||
getParameters(), getOutputStream(), hookErrRedirect,
|
||||
getStdinArgs());
|
||||
if (result.isExecutedWithError()) {
|
||||
throw new AbortedByHookException(
|
||||
new String(errorByteArray.toByteArray(), UTF_8),
|
||||
|
@ -180,7 +185,11 @@ protected void doRun() throws AbortedByHookException {
|
|||
* @since 4.11
|
||||
*/
|
||||
public boolean isNativeHookPresent() {
|
||||
return FS.DETECTED.findHook(getRepository(), getHookName()) != null;
|
||||
FS fs = getRepository().getFS();
|
||||
if (fs == null) {
|
||||
fs = FS.DETECTED;
|
||||
}
|
||||
return fs.findHook(getRepository(), getHookName()) != null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -409,6 +409,7 @@ public static JGitText get() {
|
|||
/***/ public String invalidGitdirRef;
|
||||
/***/ public String invalidGitModules;
|
||||
/***/ public String invalidGitType;
|
||||
/***/ public String invalidHooksPath;
|
||||
/***/ public String invalidId;
|
||||
/***/ public String invalidId0;
|
||||
/***/ public String invalidIdLength;
|
||||
|
|
|
@ -149,6 +149,12 @@ public final class ConfigConstants {
|
|||
*/
|
||||
public static final String CONFIG_KEY_GPGSIGN = "gpgSign";
|
||||
|
||||
/**
|
||||
* The "hooksPath" key.
|
||||
* @since 5.6
|
||||
*/
|
||||
public static final String CONFIG_KEY_HOOKS_PATH = "hooksPath";
|
||||
|
||||
/** The "algorithm" key */
|
||||
public static final String CONFIG_KEY_ALGORITHM = "algorithm";
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
import java.nio.file.AccessDeniedException;
|
||||
import java.nio.file.FileStore;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.InvalidPathException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
|
@ -98,6 +99,7 @@
|
|||
import org.eclipse.jgit.errors.LockFailedException;
|
||||
import org.eclipse.jgit.internal.JGitText;
|
||||
import org.eclipse.jgit.internal.storage.file.FileSnapshot;
|
||||
import org.eclipse.jgit.lib.Config;
|
||||
import org.eclipse.jgit.lib.ConfigConstants;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
|
@ -1730,20 +1732,18 @@ protected ProcessResult internalRunHookIfPresent(Repository repository,
|
|||
final String hookName, String[] args, PrintStream outRedirect,
|
||||
PrintStream errRedirect, String stdinArgs)
|
||||
throws JGitInternalException {
|
||||
final File hookFile = findHook(repository, hookName);
|
||||
if (hookFile == null)
|
||||
File hookFile = findHook(repository, hookName);
|
||||
if (hookFile == null || hookName == 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);
|
||||
File runDirectory = getRunDirectory(repository, hookName);
|
||||
if (runDirectory == null) {
|
||||
return new ProcessResult(Status.NOT_PRESENT);
|
||||
}
|
||||
String cmd = hookFile.getAbsolutePath();
|
||||
ProcessBuilder hookProcess = runInShell(cmd, args);
|
||||
hookProcess.directory(runDirectory);
|
||||
hookProcess.directory(runDirectory.getAbsoluteFile());
|
||||
Map<String, String> environment = hookProcess.environment();
|
||||
environment.put(Constants.GIT_DIR_KEY,
|
||||
repository.getDirectory().getAbsolutePath());
|
||||
|
@ -1778,12 +1778,71 @@ protected ProcessResult internalRunHookIfPresent(Repository repository,
|
|||
* @since 4.0
|
||||
*/
|
||||
public File findHook(Repository repository, String hookName) {
|
||||
File gitDir = repository.getDirectory();
|
||||
if (gitDir == null)
|
||||
if (hookName == null) {
|
||||
return null;
|
||||
final File hookFile = new File(new File(gitDir,
|
||||
Constants.HOOKS), hookName);
|
||||
return hookFile.isFile() ? hookFile : null;
|
||||
}
|
||||
File hookDir = getHooksDirectory(repository);
|
||||
if (hookDir == null) {
|
||||
return null;
|
||||
}
|
||||
File hookFile = new File(hookDir, hookName);
|
||||
if (hookFile.isAbsolute()) {
|
||||
if (!hookFile.exists() || FS.DETECTED.supportsExecute()
|
||||
&& !FS.DETECTED.canExecute(hookFile)) {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
File runDirectory = getRunDirectory(repository, hookName);
|
||||
if (runDirectory == null) {
|
||||
return null;
|
||||
}
|
||||
Path hookPath = runDirectory.getAbsoluteFile().toPath()
|
||||
.resolve(hookFile.toPath());
|
||||
FS fs = repository.getFS();
|
||||
if (fs == null) {
|
||||
fs = FS.DETECTED;
|
||||
}
|
||||
if (!Files.exists(hookPath) || fs.supportsExecute()
|
||||
&& !fs.canExecute(hookPath.toFile())) {
|
||||
return null;
|
||||
}
|
||||
hookFile = hookPath.toFile();
|
||||
} catch (InvalidPathException e) {
|
||||
LOG.warn(MessageFormat.format(JGitText.get().invalidHooksPath,
|
||||
hookFile));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return hookFile;
|
||||
}
|
||||
|
||||
private File getRunDirectory(Repository repository,
|
||||
@NonNull String hookName) {
|
||||
if (repository.isBare()) {
|
||||
return repository.getDirectory();
|
||||
}
|
||||
switch (hookName) {
|
||||
case "pre-receive": //$NON-NLS-1$
|
||||
case "update": //$NON-NLS-1$
|
||||
case "post-receive": //$NON-NLS-1$
|
||||
case "post-update": //$NON-NLS-1$
|
||||
case "push-to-checkout": //$NON-NLS-1$
|
||||
return repository.getDirectory();
|
||||
default:
|
||||
return repository.getWorkTree();
|
||||
}
|
||||
}
|
||||
|
||||
private File getHooksDirectory(Repository repository) {
|
||||
Config config = repository.getConfig();
|
||||
String hooksDir = config.getString(ConfigConstants.CONFIG_CORE_SECTION,
|
||||
null, ConfigConstants.CONFIG_KEY_HOOKS_PATH);
|
||||
if (hooksDir != null) {
|
||||
return new File(hooksDir);
|
||||
}
|
||||
File dir = repository.getDirectory();
|
||||
return dir == null ? null : new File(dir, Constants.HOOKS);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -74,7 +74,6 @@
|
|||
import org.eclipse.jgit.errors.CommandFailedException;
|
||||
import org.eclipse.jgit.errors.ConfigInvalidException;
|
||||
import org.eclipse.jgit.internal.JGitText;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.eclipse.jgit.lib.StoredConfig;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -309,20 +308,6 @@ public String normalize(String name) {
|
|||
return FileUtils.normalize(name);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public File findHook(Repository repository, String hookName) {
|
||||
final File gitdir = repository.getDirectory();
|
||||
if (gitdir == null) {
|
||||
return null;
|
||||
}
|
||||
final Path hookPath = gitdir.toPath().resolve(Constants.HOOKS)
|
||||
.resolve(hookName);
|
||||
if (Files.isExecutable(hookPath))
|
||||
return hookPath.toFile();
|
||||
return null;
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public boolean supportsAtomicCreateNewFile() {
|
||||
|
|
|
@ -47,8 +47,6 @@
|
|||
|
||||
import java.io.File;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
|
@ -57,7 +55,6 @@
|
|||
|
||||
import org.eclipse.jgit.api.errors.JGitInternalException;
|
||||
import org.eclipse.jgit.errors.CommandFailedException;
|
||||
import org.eclipse.jgit.lib.Constants;
|
||||
import org.eclipse.jgit.lib.Repository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -175,18 +172,4 @@ public ProcessResult runHookIfPresent(Repository repository, String hookName,
|
|||
return internalRunHookIfPresent(repository, hookName, args, outRedirect,
|
||||
errRedirect, stdinArgs);
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public File findHook(Repository repository, String hookName) {
|
||||
final File gitdir = repository.getDirectory();
|
||||
if (gitdir == null) {
|
||||
return null;
|
||||
}
|
||||
final Path hookPath = gitdir.toPath().resolve(Constants.HOOKS)
|
||||
.resolve(hookName);
|
||||
if (Files.isExecutable(hookPath))
|
||||
return hookPath.toFile();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue