Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.kernel.org/pub/scm/git/git.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2023-02-23 01:55:45 +0300
committerJunio C Hamano <gitster@pobox.com>2023-02-23 01:55:45 +0300
commit5048df67b295baeaaa6dafb16ff712bd2a62731a (patch)
tree3c1325ae2d6ddb123323fc30452dd56043e66c51
parent72972ea0b978f20b335339d18e497da617398967 (diff)
parent0414b3891cd3adb80b879c7be49d9b727e2b23f5 (diff)
Merge branch 'ab/hook-api-with-stdin'
Extend the run-hooks API to allow feeding data from the standard input when running the hook script(s). * ab/hook-api-with-stdin: hook: support a --to-stdin=<path> option sequencer: use the new hook API for the simpler "post-rewrite" call hook API: support passing stdin to hooks, convert am's 'post-rewrite' run-command: allow stdin for run_processes_parallel run-command.c: remove dead assignment in while-loop
-rw-r--r--Documentation/git-hook.txt7
-rw-r--r--builtin/am.c20
-rw-r--r--builtin/hook.c4
-rw-r--r--hook.c5
-rw-r--r--hook.h5
-rw-r--r--run-command.c13
-rw-r--r--sequencer.c18
-rwxr-xr-xt/t1800-hook.sh18
8 files changed, 54 insertions, 36 deletions
diff --git a/Documentation/git-hook.txt b/Documentation/git-hook.txt
index 77c3a8ad90..3407f3c2c0 100644
--- a/Documentation/git-hook.txt
+++ b/Documentation/git-hook.txt
@@ -8,7 +8,7 @@ git-hook - Run git hooks
SYNOPSIS
--------
[verse]
-'git hook' run [--ignore-missing] <hook-name> [-- <hook-args>]
+'git hook' run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]
DESCRIPTION
-----------
@@ -31,6 +31,11 @@ linkgit:githooks[5] for arguments hooks might expect (if any).
OPTIONS
-------
+--to-stdin::
+ For "run"; Specify a file which will be streamed into the
+ hook's stdin. The hook will receive the entire file from
+ beginning to EOF.
+
--ignore-missing::
Ignore any missing hook by quietly returning zero. Used for
tools that want to do a blind one-shot run of a hook that may
diff --git a/builtin/am.c b/builtin/am.c
index 8b3dcb66f0..e0848ddadf 100644
--- a/builtin/am.c
+++ b/builtin/am.c
@@ -495,24 +495,12 @@ static int run_applypatch_msg_hook(struct am_state *state)
*/
static int run_post_rewrite_hook(const struct am_state *state)
{
- struct child_process cp = CHILD_PROCESS_INIT;
- const char *hook = find_hook("post-rewrite");
- int ret;
-
- if (!hook)
- return 0;
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
- strvec_push(&cp.args, hook);
- strvec_push(&cp.args, "rebase");
+ strvec_push(&opt.args, "rebase");
+ opt.path_to_stdin = am_path(state, "rewritten");
- cp.in = xopen(am_path(state, "rewritten"), O_RDONLY);
- cp.stdout_to_stderr = 1;
- cp.trace2_hook_name = "post-rewrite";
-
- ret = run_command(&cp);
-
- close(cp.in);
- return ret;
+ return run_hooks_opt("post-rewrite", &opt);
}
/**
diff --git a/builtin/hook.c b/builtin/hook.c
index b6530d189a..f95b7965c5 100644
--- a/builtin/hook.c
+++ b/builtin/hook.c
@@ -7,7 +7,7 @@
#include "strvec.h"
#define BUILTIN_HOOK_RUN_USAGE \
- N_("git hook run [--ignore-missing] <hook-name> [-- <hook-args>]")
+ N_("git hook run [--ignore-missing] [--to-stdin=<path>] <hook-name> [-- <hook-args>]")
static const char * const builtin_hook_usage[] = {
BUILTIN_HOOK_RUN_USAGE,
@@ -28,6 +28,8 @@ static int run(int argc, const char **argv, const char *prefix)
struct option run_options[] = {
OPT_BOOL(0, "ignore-missing", &ignore_missing,
N_("silently ignore missing requested <hook-name>")),
+ OPT_STRING(0, "to-stdin", &opt.path_to_stdin, N_("path"),
+ N_("file to read into hooks' stdin")),
OPT_END(),
};
int ret;
diff --git a/hook.c b/hook.c
index a4fa1031f2..1a84831863 100644
--- a/hook.c
+++ b/hook.c
@@ -55,6 +55,11 @@ static int pick_next_hook(struct child_process *cp,
cp->no_stdin = 1;
strvec_pushv(&cp->env, hook_cb->options->env.v);
+ /* reopen the file for stdin; run_command closes it. */
+ if (hook_cb->options->path_to_stdin) {
+ cp->no_stdin = 0;
+ cp->in = xopen(hook_cb->options->path_to_stdin, O_RDONLY);
+ }
cp->stdout_to_stderr = 1;
cp->trace2_hook_name = hook_cb->hook_name;
cp->dir = hook_cb->options->dir;
diff --git a/hook.h b/hook.h
index 4258b13da0..19ab9a5806 100644
--- a/hook.h
+++ b/hook.h
@@ -30,6 +30,11 @@ struct run_hooks_opt
* was invoked.
*/
int *invoked_hook;
+
+ /**
+ * Path to file which should be piped to stdin for each hook.
+ */
+ const char *path_to_stdin;
};
#define RUN_HOOKS_OPT_INIT { \
diff --git a/run-command.c b/run-command.c
index 50cc011654..6bd16acb06 100644
--- a/run-command.c
+++ b/run-command.c
@@ -1586,6 +1586,14 @@ static int pp_start_one(struct parallel_processes *pp,
if (i == opts->processes)
BUG("bookkeeping is hard");
+ /*
+ * By default, do not inherit stdin from the parent process - otherwise,
+ * all children would share stdin! Users may overwrite this to provide
+ * something to the child's stdin by having their 'get_next_task'
+ * callback assign 0 to .no_stdin and an appropriate integer to .in.
+ */
+ pp->children[i].process.no_stdin = 1;
+
code = opts->get_next_task(&pp->children[i].process,
opts->ungroup ? NULL : &pp->children[i].err,
opts->data,
@@ -1601,7 +1609,6 @@ static int pp_start_one(struct parallel_processes *pp,
pp->children[i].process.err = -1;
pp->children[i].process.stdout_to_stderr = 1;
}
- pp->children[i].process.no_stdin = 1;
if (start_command(&pp->children[i].process)) {
if (opts->start_failure)
@@ -1632,9 +1639,7 @@ static void pp_buffer_stderr(struct parallel_processes *pp,
const struct run_process_parallel_opts *opts,
int output_timeout)
{
- int i;
-
- while ((i = poll(pp->pfd, opts->processes, output_timeout) < 0)) {
+ while (poll(pp->pfd, opts->processes, output_timeout) < 0) {
if (errno == EINTR)
continue;
pp_cleanup(pp, opts);
diff --git a/sequencer.c b/sequencer.c
index fb23f734ad..65a34f9676 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -4844,8 +4844,7 @@ cleanup_head_ref:
if (!stat(rebase_path_rewritten_list(), &st) &&
st.st_size > 0) {
struct child_process child = CHILD_PROCESS_INIT;
- const char *post_rewrite_hook =
- find_hook("post-rewrite");
+ struct run_hooks_opt hook_opt = RUN_HOOKS_OPT_INIT;
child.in = open(rebase_path_rewritten_list(), O_RDONLY);
child.git_cmd = 1;
@@ -4855,18 +4854,9 @@ cleanup_head_ref:
/* we don't care if this copying failed */
run_command(&child);
- if (post_rewrite_hook) {
- struct child_process hook = CHILD_PROCESS_INIT;
-
- hook.in = open(rebase_path_rewritten_list(),
- O_RDONLY);
- hook.stdout_to_stderr = 1;
- hook.trace2_hook_name = "post-rewrite";
- strvec_push(&hook.args, post_rewrite_hook);
- strvec_push(&hook.args, "rebase");
- /* we don't care if this hook failed */
- run_command(&hook);
- }
+ hook_opt.path_to_stdin = rebase_path_rewritten_list();
+ strvec_push(&hook_opt.args, "rebase");
+ run_hooks_opt("post-rewrite", &hook_opt);
}
apply_autostash(rebase_path_autostash());
diff --git a/t/t1800-hook.sh b/t/t1800-hook.sh
index 2ef3579fa7..3506f627b6 100755
--- a/t/t1800-hook.sh
+++ b/t/t1800-hook.sh
@@ -177,4 +177,22 @@ test_expect_success 'git hook run a hook with a bad shebang' '
test_cmp expect actual
'
+test_expect_success 'stdin to hooks' '
+ write_script .git/hooks/test-hook <<-\EOF &&
+ echo BEGIN stdin
+ cat
+ echo END stdin
+ EOF
+
+ cat >expect <<-EOF &&
+ BEGIN stdin
+ hello
+ END stdin
+ EOF
+
+ echo hello >input &&
+ git hook run --to-stdin=input test-hook 2>actual &&
+ test_cmp expect actual
+'
+
test_done