@@ -368,6 +368,9 @@ The default 'update' hook, when enabled--and with
`hooks.allowunannotated` config option unset or set to false--prevents
unannotated tags to be pushed.
+Hooks executed during 'update' are run in parallel, unless hook.jobs is
+configured to 1.
+
[[proc-receive]]
proc-receive
~~~~~~~~~~~~
@@ -938,33 +938,57 @@ static int run_receive_hook(struct command *commands,
return status;
}
-static int run_update_hook(struct command *cmd)
+static void hook_output_to_sideband(struct strbuf *output, void *cb_data)
{
- const char *argv[5];
- struct child_process proc = CHILD_PROCESS_INIT;
- int code;
+ int keepalive_active = 0;
- argv[0] = find_hook("update");
- if (!argv[0])
- return 0;
+ if (keepalive_in_sec <= 0)
+ use_keepalive = KEEPALIVE_NEVER;
+ if (use_keepalive == KEEPALIVE_ALWAYS)
+ keepalive_active = 1;
- argv[1] = cmd->ref_name;
- argv[2] = oid_to_hex(&cmd->old_oid);
- argv[3] = oid_to_hex(&cmd->new_oid);
- argv[4] = NULL;
+ /* send a keepalive if there is no data to write */
+ if (keepalive_active && !output->len) {
+ static const char buf[] = "0005\1";
+ write_or_die(1, buf, sizeof(buf) - 1);
+ return;
+ }
- proc.no_stdin = 1;
- proc.stdout_to_stderr = 1;
- proc.err = use_sideband ? -1 : 0;
- proc.argv = argv;
- proc.trace2_hook_name = "update";
+ if (use_keepalive == KEEPALIVE_AFTER_NUL && !keepalive_active) {
+ const char *first_null = memchr(output->buf, '\0', output->len);
+ if (first_null) {
+ /* The null bit is excluded. */
+ size_t before_null = first_null - output->buf;
+ size_t after_null = output->len - (before_null + 1);
+ keepalive_active = 1;
+ send_sideband(1, 2, output->buf, before_null, use_sideband);
+ send_sideband(1, 2, first_null + 1, after_null, use_sideband);
+
+ return;
+ }
+ }
+
+ send_sideband(1, 2, output->buf, output->len, use_sideband);
+}
+
+static int run_update_hook(struct command *cmd)
+{
+ struct run_hooks_opt opt;
+ int code;
+ run_hooks_opt_init_async(&opt);
+
+ strvec_pushl(&opt.args,
+ cmd->ref_name,
+ oid_to_hex(&cmd->old_oid),
+ oid_to_hex(&cmd->new_oid),
+ NULL);
- code = start_command(&proc);
- if (code)
- return code;
if (use_sideband)
- copy_to_sideband(proc.err, -1, NULL);
- return finish_command(&proc);
+ opt.consume_sideband = hook_output_to_sideband;
+
+ code = run_hooks("update", &opt);
+ run_hooks_opt_clear(&opt);
+ return code;
}
static struct command *find_command_by_refname(struct command *list,
@@ -124,10 +124,10 @@ test_expect_success 'interleaving hook calls succeed' '
EOF
cat >expect <<-EOF &&
- hooks/update refs/tags/PRE $ZERO_OID $PRE_OID
+ $(pwd)/target-repo.git/hooks/update refs/tags/PRE $ZERO_OID $PRE_OID
$(pwd)/target-repo.git/hooks/reference-transaction prepared
$(pwd)/target-repo.git/hooks/reference-transaction committed
- hooks/update refs/tags/POST $ZERO_OID $POST_OID
+ $(pwd)/target-repo.git/hooks/update refs/tags/POST $ZERO_OID $POST_OID
$(pwd)/target-repo.git/hooks/reference-transaction prepared
$(pwd)/target-repo.git/hooks/reference-transaction committed
EOF
By using hook.h to invoke the 'update' hook, now hooks can be specified in the config in addition to the hookdir. Signed-off-by: Emily Shaffer <emilyshaffer@google.com> --- Documentation/githooks.txt | 3 ++ builtin/receive-pack.c | 66 ++++++++++++++++++++++---------- t/t1416-ref-transaction-hooks.sh | 4 +- 3 files changed, 50 insertions(+), 23 deletions(-)