aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEmily Shaffer <emilyshaffer@google.com>2025-10-17 17:15:36 +0300
committerJunio C Hamano <gitster@pobox.com>2025-10-17 14:32:52 -0700
commitbc0afba2f1c9c3dc8e806c6865c4669cf54dd9e0 (patch)
tree54698d7b79c3e291134850c8315f97f84c066002
parentrun-command: add stdin callback for parallelization (diff)
downloadgit-bc0afba2f1c9c3dc8e806c6865c4669cf54dd9e0.tar.gz
git-bc0afba2f1c9c3dc8e806c6865c4669cf54dd9e0.zip
hook: provide stdin via callback
This adds a callback mechanism for feeding stdin to hooks alongside the existing path_to_stdin (which slurps a file's content to stdin). The advantage of this new callback is that it can feed stdin without going through the FS layer. This helps when feeding large amount of data and uses the run-command parallel stdin callback introduced in the preceding commit. Signed-off-by: Emily Shaffer <emilyshaffer@google.com> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--hook.c15
-rw-r--r--hook.h23
2 files changed, 38 insertions, 0 deletions
diff --git a/hook.c b/hook.c
index b3de1048bf..7537cf0f9e 100644
--- a/hook.c
+++ b/hook.c
@@ -65,11 +65,22 @@ static int pick_next_hook(struct child_process *cp,
cp->no_stdin = 1;
strvec_pushv(&cp->env, hook_cb->options->env.v);
+
+ if (hook_cb->options->path_to_stdin && hook_cb->options->feed_pipe)
+ BUG("options path_to_stdin and feed_pipe are mutually exclusive");
+
/* 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);
}
+
+ if (hook_cb->options->feed_pipe) {
+ cp->no_stdin = 0;
+ /* start_command() will allocate a pipe / stdin fd for us */
+ cp->in = -1;
+ }
+
cp->stdout_to_stderr = 1;
cp->trace2_hook_name = hook_cb->hook_name;
cp->dir = hook_cb->options->dir;
@@ -140,6 +151,7 @@ int run_hooks_opt(struct repository *r, const char *hook_name,
.get_next_task = pick_next_hook,
.start_failure = notify_start_failure,
+ .feed_pipe = options->feed_pipe,
.task_finished = notify_hook_finished,
.data = &cb_data,
@@ -148,6 +160,9 @@ int run_hooks_opt(struct repository *r, const char *hook_name,
if (!options)
BUG("a struct run_hooks_opt must be provided to run_hooks");
+ if (options->path_to_stdin && options->feed_pipe)
+ BUG("choose only one method to populate hook stdin");
+
if (options->invoked_hook)
*options->invoked_hook = 0;
diff --git a/hook.h b/hook.h
index 11863fa734..ebe5dc450e 100644
--- a/hook.h
+++ b/hook.h
@@ -1,6 +1,7 @@
#ifndef HOOK_H
#define HOOK_H
#include "strvec.h"
+#include "run-command.h"
struct repository;
@@ -37,6 +38,28 @@ struct run_hooks_opt
* Path to file which should be piped to stdin for each hook.
*/
const char *path_to_stdin;
+
+ /**
+ * Callback to ask for more content to pipe to each hook stdin.
+ *
+ * If a hook needs to consume large quantities of data (e.g. a
+ * list of all refs received in a client push), feeding data via
+ * in-memory strings or slurping to/from files via path_to_stdin
+ * is inefficient, so this callback allows for piecemeal writes.
+ *
+ * Add initalization context to hook.feed_pipe_ctx.
+ *
+ * The caller owns hook.feed_pipe_ctx and has to release any
+ * resources after hooks finish execution.
+ */
+ feed_pipe_fn feed_pipe;
+ void *feed_pipe_ctx;
+
+ /**
+ * Use this to keep internal state for your feed_pipe_fn callback.
+ * Only useful when using run_hooks_opt.feed_pipe, otherwise ignore it.
+ */
+ void *feed_pipe_cb_data;
};
#define RUN_HOOKS_OPT_INIT { \