From: Emily Shaffer <emilyshaffer@google.com>
To: git@vger.kernel.org
Cc: Emily Shaffer <emilyshaffer@google.com>
Subject: [PATCH v3 16/17] receive-pack: convert receive hooks to hook.h
Date: Mon, 21 Dec 2020 16:04:34 -0800 [thread overview]
Message-ID: <20201222000435.1529768-17-emilyshaffer@google.com> (raw)
In-Reply-To: <20201222000435.1529768-1-emilyshaffer@google.com>
By using the hook.h library to run receive hooks, they can be specified
in the config as well as in the hookdir.
Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
---
Documentation/githooks.txt | 4 +
builtin/receive-pack.c | 197 +++++++++++++++++--------------------
2 files changed, 94 insertions(+), 107 deletions(-)
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index 1412cd5846..c450f7a27e 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -314,6 +314,8 @@ will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
See the section on "Quarantine Environment" in
linkgit:git-receive-pack[1] for some caveats.
+Hooks executed during 'pre-receive' will not be parallelized.
+
[[update]]
update
~~~~~~
@@ -466,6 +468,8 @@ environment variables will not be set. If the client selects
to use push options, but doesn't transmit any, the count variable
will be set to zero, `GIT_PUSH_OPTION_COUNT=0`.
+Hooks executed during 'post-receive' are run in parallel by default.
+
[[post-update]]
post-update
~~~~~~~~~~~
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index 5c23d5ed86..348d5b0a9b 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -748,7 +748,7 @@ static int check_cert_push_options(const struct string_list *push_options)
return retval;
}
-static void prepare_push_cert_sha1(struct child_process *proc)
+static void prepare_push_cert_sha1(struct run_hooks_opt *opt)
{
static int already_done;
@@ -772,110 +772,42 @@ static void prepare_push_cert_sha1(struct child_process *proc)
nonce_status = check_nonce(push_cert.buf, bogs);
}
if (!is_null_oid(&push_cert_oid)) {
- strvec_pushf(&proc->env_array, "GIT_PUSH_CERT=%s",
+ strvec_pushf(&opt->env, "GIT_PUSH_CERT=%s",
oid_to_hex(&push_cert_oid));
- strvec_pushf(&proc->env_array, "GIT_PUSH_CERT_SIGNER=%s",
+ strvec_pushf(&opt->env, "GIT_PUSH_CERT_SIGNER=%s",
sigcheck.signer ? sigcheck.signer : "");
- strvec_pushf(&proc->env_array, "GIT_PUSH_CERT_KEY=%s",
+ strvec_pushf(&opt->env, "GIT_PUSH_CERT_KEY=%s",
sigcheck.key ? sigcheck.key : "");
- strvec_pushf(&proc->env_array, "GIT_PUSH_CERT_STATUS=%c",
+ strvec_pushf(&opt->env, "GIT_PUSH_CERT_STATUS=%c",
sigcheck.result);
if (push_cert_nonce) {
- strvec_pushf(&proc->env_array,
+ strvec_pushf(&opt->env,
"GIT_PUSH_CERT_NONCE=%s",
push_cert_nonce);
- strvec_pushf(&proc->env_array,
+ strvec_pushf(&opt->env,
"GIT_PUSH_CERT_NONCE_STATUS=%s",
nonce_status);
if (nonce_status == NONCE_SLOP)
- strvec_pushf(&proc->env_array,
+ strvec_pushf(&opt->env,
"GIT_PUSH_CERT_NONCE_SLOP=%ld",
nonce_stamp_slop);
}
}
}
+struct receive_hook_feed_context {
+ struct command *cmd;
+ int skip_broken;
+};
+
struct receive_hook_feed_state {
struct command *cmd;
struct ref_push_report *report;
int skip_broken;
struct strbuf buf;
- const struct string_list *push_options;
};
-typedef int (*feed_fn)(void *, const char **, size_t *);
-static int run_and_feed_hook(const char *hook_name, feed_fn feed,
- struct receive_hook_feed_state *feed_state)
-{
- struct child_process proc = CHILD_PROCESS_INIT;
- struct async muxer;
- const char *argv[2];
- int code;
-
- argv[0] = find_hook(hook_name);
- if (!argv[0])
- return 0;
-
- argv[1] = NULL;
-
- proc.argv = argv;
- proc.in = -1;
- proc.stdout_to_stderr = 1;
- proc.trace2_hook_name = hook_name;
-
- if (feed_state->push_options) {
- int i;
- for (i = 0; i < feed_state->push_options->nr; i++)
- strvec_pushf(&proc.env_array,
- "GIT_PUSH_OPTION_%d=%s", i,
- feed_state->push_options->items[i].string);
- strvec_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT=%d",
- feed_state->push_options->nr);
- } else
- strvec_pushf(&proc.env_array, "GIT_PUSH_OPTION_COUNT");
-
- if (tmp_objdir)
- strvec_pushv(&proc.env_array, tmp_objdir_env(tmp_objdir));
-
- if (use_sideband) {
- memset(&muxer, 0, sizeof(muxer));
- muxer.proc = copy_to_sideband;
- muxer.in = -1;
- code = start_async(&muxer);
- if (code)
- return code;
- proc.err = muxer.in;
- }
-
- prepare_push_cert_sha1(&proc);
-
- code = start_command(&proc);
- if (code) {
- if (use_sideband)
- finish_async(&muxer);
- return code;
- }
-
- sigchain_push(SIGPIPE, SIG_IGN);
-
- while (1) {
- const char *buf;
- size_t n;
- if (feed(feed_state, &buf, &n))
- break;
- if (write_in_full(proc.in, buf, n) < 0)
- break;
- }
- close(proc.in);
- if (use_sideband)
- finish_async(&muxer);
-
- sigchain_pop(SIGPIPE);
-
- return finish_command(&proc);
-}
-
-static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
+static int feed_receive_hook(void *state_)
{
struct receive_hook_feed_state *state = state_;
struct command *cmd = state->cmd;
@@ -884,9 +816,7 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
state->skip_broken && (cmd->error_string || cmd->did_not_exist))
cmd = cmd->next;
if (!cmd)
- return -1; /* EOF */
- if (!bufp)
- return 0; /* OK, can feed something. */
+ return 1; /* EOF - close the pipe*/
strbuf_reset(&state->buf);
if (!state->report)
state->report = cmd->report;
@@ -910,32 +840,36 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
cmd->ref_name);
state->cmd = cmd->next;
}
- if (bufp) {
- *bufp = state->buf.buf;
- *sizep = state->buf.len;
- }
return 0;
}
-static int run_receive_hook(struct command *commands,
- const char *hook_name,
- int skip_broken,
- const struct string_list *push_options)
+static int feed_receive_hook_cb(struct strbuf *pipe, void *pp_cb, void *pp_task_cb)
{
- struct receive_hook_feed_state state;
- int status;
-
- strbuf_init(&state.buf, 0);
- state.cmd = commands;
- state.skip_broken = skip_broken;
- state.report = NULL;
- if (feed_receive_hook(&state, NULL, NULL))
- return 0;
- state.cmd = commands;
- state.push_options = push_options;
- status = run_and_feed_hook(hook_name, feed_receive_hook, &state);
- strbuf_release(&state.buf);
- return status;
+ struct hook *hook = pp_task_cb;
+ struct receive_hook_feed_state *feed_state = hook->feed_pipe_cb_data;
+ int rc;
+
+ /* first-time setup */
+ if (!feed_state) {
+ struct hook_cb_data *hook_cb = pp_cb;
+ struct run_hooks_opt *opt = hook_cb->options;
+ struct receive_hook_feed_context *ctx = opt->feed_pipe_ctx;
+ if (!ctx)
+ BUG("run_hooks_opt.feed_pipe_ctx required for receive hook");
+
+ feed_state = xmalloc(sizeof(struct receive_hook_feed_state));
+ strbuf_init(&feed_state->buf, 0);
+ feed_state->cmd = ctx->cmd;
+ feed_state->skip_broken = ctx->skip_broken;
+ feed_state->report = NULL;
+
+ hook->feed_pipe_cb_data = feed_state;
+ }
+
+ rc = feed_receive_hook(feed_state);
+ if (!rc)
+ strbuf_addbuf(pipe, &feed_state->buf);
+ return rc;
}
static void hook_output_to_sideband(struct strbuf *output, void *cb_data)
@@ -971,6 +905,55 @@ static void hook_output_to_sideband(struct strbuf *output, void *cb_data)
send_sideband(1, 2, output->buf, output->len, use_sideband);
}
+static int run_receive_hook(struct command *commands,
+ const char *hook_name,
+ int skip_broken,
+ const struct string_list *push_options)
+{
+ struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_ASYNC;
+ struct receive_hook_feed_context ctx;
+ int rc;
+ struct command *iter = commands;
+
+ /* if there are no valid commands, don't invoke the hook at all. */
+ while (iter && skip_broken && (iter->error_string || iter->did_not_exist))
+ iter = iter->next;
+ if (!iter)
+ return 0;
+
+ /* pre-receive hooks should run in series as the hook updates refs */
+ if (!strcmp(hook_name, "pre-receive"))
+ opt.jobs = 1;
+
+ if (push_options) {
+ int i;
+ for (i = 0; i < push_options->nr; i++)
+ strvec_pushf(&opt.env, "GIT_PUSH_OPTION_%d=%s", i,
+ push_options->items[i].string);
+ strvec_pushf(&opt.env, "GIT_PUSH_OPTION_COUNT=%d", push_options->nr);
+ } else
+ strvec_push(&opt.env, "GIT_PUSH_OPTION_COUNT");
+
+ if (tmp_objdir)
+ strvec_pushv(&opt.env, tmp_objdir_env(tmp_objdir));
+
+ prepare_push_cert_sha1(&opt);
+
+ /* set up sideband printer */
+ if (use_sideband)
+ opt.consume_sideband = hook_output_to_sideband;
+
+ /* set up stdin callback */
+ ctx.cmd = commands;
+ ctx.skip_broken = skip_broken;
+ opt.feed_pipe = feed_receive_hook_cb;
+ opt.feed_pipe_ctx = &ctx;
+
+ rc = run_hooks(hook_name, &opt);
+ run_hooks_opt_clear(&opt);
+ return rc;
+}
+
static int run_update_hook(struct command *cmd)
{
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT_ASYNC;
--
2.28.0.rc0.142.g3c755180ce-goog
next prev parent reply other threads:[~2020-12-22 0:07 UTC|newest]
Thread overview: 53+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-10-14 23:25 [PATCH] commit: use config-based hooks (config-based hooks part II) Emily Shaffer
2020-10-16 18:34 ` Junio C Hamano
2020-12-05 1:49 ` [PATCH 00/17] use config-based hooks (config-based hooks part Emily Shaffer
2020-12-05 1:49 ` [PATCH 01/17] commit: use config-based hooks Emily Shaffer
2020-12-05 1:49 ` [PATCH 02/17] am: convert applypatch hooks to use config Emily Shaffer
2020-12-05 1:49 ` [PATCH 03/17] merge: use config-based hooks for post-merge hook Emily Shaffer
2020-12-05 1:49 ` [PATCH 04/17] gc: use hook library for pre-auto-gc hook Emily Shaffer
2020-12-05 1:49 ` [PATCH 05/17] rebase: teach pre-rebase to use hook.h Emily Shaffer
2020-12-05 1:49 ` [PATCH 06/17] read-cache: convert post-index-change hook to use config Emily Shaffer
2020-12-05 1:49 ` [PATCH 07/17] receive-pack: convert push-to-checkout hook to hook.h Emily Shaffer
2020-12-05 1:49 ` [PATCH 08/17] git-p4: use 'git hook' to run hooks Emily Shaffer
2020-12-16 0:27 ` Josh Steadmon
2020-12-16 20:19 ` Emily Shaffer
2020-12-05 1:49 ` [PATCH 09/17] hooks: convert 'post-checkout' hook to hook library Emily Shaffer
2020-12-05 1:49 ` [PATCH 10/17] hook: convert 'post-rewrite' hook to config Emily Shaffer
2020-12-08 23:02 ` Josh Steadmon
2020-12-15 23:42 ` Emily Shaffer
2020-12-05 1:49 ` [PATCH 11/17] transport: convert pre-push hook to use config Emily Shaffer
2020-12-05 1:49 ` [PATCH 12/17] reference-transaction: look for hooks in config Emily Shaffer
2020-12-05 1:49 ` [PATCH 13/17] receive-pack: convert 'update' hook to hook.h Emily Shaffer
2020-12-05 1:49 ` [PATCH 14/17] proc-receive: acquire hook list from hook.h Emily Shaffer
2020-12-05 1:49 ` [PATCH 15/17] post-update: use hook.h library Emily Shaffer
2020-12-05 1:49 ` [PATCH 16/17] receive-pack: convert receive hooks to hook.h Emily Shaffer
2020-12-05 1:49 ` [PATCH 17/17] run-command: stop thinking about hooks Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 00/17] use config-based hooks (config-based hooks part II) Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 01/17] commit: use config-based hooks Emily Shaffer
2021-02-01 22:08 ` Junio C Hamano
2021-03-10 19:51 ` Emily Shaffer
2021-03-10 22:36 ` Junio C Hamano
2021-02-01 23:02 ` Junio C Hamano
2021-03-10 19:39 ` Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 02/17] am: convert applypatch hooks to use config Emily Shaffer
2021-02-01 22:05 ` Junio C Hamano
2020-12-22 0:04 ` [PATCH v3 03/17] merge: use config-based hooks for post-merge hook Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 04/17] gc: use hook library for pre-auto-gc hook Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 05/17] rebase: teach pre-rebase to use hook.h Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 06/17] read-cache: convert post-index-change hook to use config Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 07/17] receive-pack: convert push-to-checkout hook to hook.h Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 08/17] git-p4: use 'git hook' to run hooks Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 09/17] hooks: convert 'post-checkout' hook to hook library Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 10/17] hook: convert 'post-rewrite' hook to config Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 11/17] transport: convert pre-push hook to use config Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 12/17] reference-transaction: look for hooks in config Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 13/17] receive-pack: convert 'update' hook to hook.h Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 14/17] proc-receive: acquire hook list from hook.h Emily Shaffer
2020-12-22 0:04 ` [PATCH v3 15/17] post-update: use hook.h library Emily Shaffer
2020-12-22 0:04 ` Emily Shaffer [this message]
2020-12-22 0:04 ` [PATCH v3 17/17] run-command: stop thinking about hooks Emily Shaffer
2020-12-28 19:59 ` [PATCH v3 00/17] use config-based hooks (config-based hooks part II) Emily Shaffer
2020-12-28 22:40 ` [PATCH v3 18/17] doc: make git-hook.txt point of truth Emily Shaffer
2020-12-28 23:15 ` Emily Shaffer
2021-02-18 22:32 ` [PATCH v3 00/17] use config-based hooks (config-based hooks part II) Josh Steadmon
2020-12-16 0:31 ` [PATCH] commit: " Josh Steadmon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20201222000435.1529768-17-emilyshaffer@google.com \
--to=emilyshaffer@google.com \
--cc=git@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).