diff options
| author | Junio C Hamano <gitster@pobox.com> | 2026-01-15 11:12:53 -0800 |
|---|---|---|
| committer | Junio C Hamano <gitster@pobox.com> | 2026-01-15 13:02:38 -0800 |
| commit | a3d1f391d35762162356201028fb73774a6c4a8b (patch) | |
| tree | 4b27ddcff1e2c2a24f34eccd2c50cb0275b39b2f /builtin | |
| parent | 7264e61d87e58b9d0f5e6424c47c11e9657dfb75 (diff) | |
| download | git-a3d1f391d35762162356201028fb73774a6c4a8b.tar.xz | |
Revert "Merge branch 'ar/run-command-hook'"
This reverts commit f406b8955295d01089ba2baf35eceadff2d11cae,
reversing changes made to 1627809eeff75e6ec936fc609e7be46d5eb2fa9e.
It seems to have caused a few regressions, two of the three known
ones we have proposed solutions for. Let's give ourselves a bit
more room to maneuver during the pre-release freeze period and
restart once the 2.53 ships.
Diffstat (limited to 'builtin')
| -rw-r--r-- | builtin/hook.c | 6 | ||||
| -rw-r--r-- | builtin/receive-pack.c | 266 |
2 files changed, 153 insertions, 119 deletions
diff --git a/builtin/hook.c b/builtin/hook.c index 73e7b8c2e8..7afec380d2 100644 --- a/builtin/hook.c +++ b/builtin/hook.c @@ -44,12 +44,6 @@ static int run(int argc, const char **argv, const char *prefix, goto usage; /* - * All current "hook run" use-cases require ungrouped child output. - * If this changes, a hook run argument can be added to toggle it. - */ - opt.ungroup = 1; - - /* * Having a -- for "run" when providing <hook-args> is * mandatory. */ diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c index ef1f77be8c..9c49174616 100644 --- a/builtin/receive-pack.c +++ b/builtin/receive-pack.c @@ -749,7 +749,7 @@ static int check_cert_push_options(const struct string_list *push_options) return retval; } -static void prepare_push_cert_sha1(struct run_hooks_opt *opt) +static void prepare_push_cert_sha1(struct child_process *proc) { static int already_done; @@ -775,23 +775,23 @@ static void prepare_push_cert_sha1(struct run_hooks_opt *opt) nonce_status = check_nonce(sigcheck.payload); } if (!is_null_oid(&push_cert_oid)) { - strvec_pushf(&opt->env, "GIT_PUSH_CERT=%s", + strvec_pushf(&proc->env, "GIT_PUSH_CERT=%s", oid_to_hex(&push_cert_oid)); - strvec_pushf(&opt->env, "GIT_PUSH_CERT_SIGNER=%s", + strvec_pushf(&proc->env, "GIT_PUSH_CERT_SIGNER=%s", sigcheck.signer ? sigcheck.signer : ""); - strvec_pushf(&opt->env, "GIT_PUSH_CERT_KEY=%s", + strvec_pushf(&proc->env, "GIT_PUSH_CERT_KEY=%s", sigcheck.key ? sigcheck.key : ""); - strvec_pushf(&opt->env, "GIT_PUSH_CERT_STATUS=%c", + strvec_pushf(&proc->env, "GIT_PUSH_CERT_STATUS=%c", sigcheck.result); if (push_cert_nonce) { - strvec_pushf(&opt->env, + strvec_pushf(&proc->env, "GIT_PUSH_CERT_NONCE=%s", push_cert_nonce); - strvec_pushf(&opt->env, + strvec_pushf(&proc->env, "GIT_PUSH_CERT_NONCE_STATUS=%s", nonce_status); if (nonce_status == NONCE_SLOP) - strvec_pushf(&opt->env, + strvec_pushf(&proc->env, "GIT_PUSH_CERT_NONCE_SLOP=%ld", nonce_stamp_slop); } @@ -803,74 +803,119 @@ struct receive_hook_feed_state { struct ref_push_report *report; int skip_broken; struct strbuf buf; + const struct string_list *push_options; }; -static int feed_receive_hook_cb(int hook_stdin_fd, void *pp_cb UNUSED, void *pp_task_cb) +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 receive_hook_feed_state *state = pp_task_cb; - struct command *cmd = state->cmd; - unsigned int lines_batch_size = 500; - - strbuf_reset(&state->buf); + struct child_process proc = CHILD_PROCESS_INIT; + struct async muxer; + int code; + const char *hook_path = find_hook(the_repository, hook_name); - /* batch lines to avoid going through run-command's poll loop for each line */ - for (unsigned int i = 0; i < lines_batch_size; i++) { - while (cmd && - state->skip_broken && (cmd->error_string || cmd->did_not_exist)) - cmd = cmd->next; + if (!hook_path) + return 0; - if (!cmd) - break; /* no more commands left */ + strvec_push(&proc.args, hook_path); + proc.in = -1; + proc.stdout_to_stderr = 1; + proc.trace2_hook_name = hook_name; - if (!state->report) - state->report = cmd->report; + if (feed_state->push_options) { + size_t i; + for (i = 0; i < feed_state->push_options->nr; i++) + strvec_pushf(&proc.env, + "GIT_PUSH_OPTION_%"PRIuMAX"=%s", + (uintmax_t)i, + feed_state->push_options->items[i].string); + strvec_pushf(&proc.env, "GIT_PUSH_OPTION_COUNT=%"PRIuMAX"", + (uintmax_t)feed_state->push_options->nr); + } else + strvec_pushf(&proc.env, "GIT_PUSH_OPTION_COUNT"); - if (state->report) { - struct object_id *old_oid; - struct object_id *new_oid; - const char *ref_name; + if (tmp_objdir) + strvec_pushv(&proc.env, tmp_objdir_env(tmp_objdir)); - old_oid = state->report->old_oid ? state->report->old_oid : &cmd->old_oid; - new_oid = state->report->new_oid ? state->report->new_oid : &cmd->new_oid; - ref_name = state->report->ref_name ? state->report->ref_name : cmd->ref_name; + 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; + } - strbuf_addf(&state->buf, "%s %s %s\n", - oid_to_hex(old_oid), oid_to_hex(new_oid), - ref_name); + prepare_push_cert_sha1(&proc); - state->report = state->report->next; - if (!state->report) - cmd = cmd->next; - } else { - strbuf_addf(&state->buf, "%s %s %s\n", - oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid), - cmd->ref_name); - cmd = cmd->next; - } + code = start_command(&proc); + if (code) { + if (use_sideband) + finish_async(&muxer); + return code; } - state->cmd = cmd; + sigchain_push(SIGPIPE, SIG_IGN); - if (state->buf.len > 0) { - int ret = write_in_full(hook_stdin_fd, state->buf.buf, state->buf.len); - if (ret < 0) { - if (errno == EPIPE) - return 1; /* child closed pipe */ - return ret; - } + 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); - return state->cmd ? 0 : 1; /* 0 = more to come, 1 = EOF */ + sigchain_pop(SIGPIPE); + + return finish_command(&proc); } -static void hook_output_to_sideband(struct strbuf *output, void *cb_data UNUSED) +static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep) { - if (!output) - BUG("output must be non-NULL"); + struct receive_hook_feed_state *state = state_; + struct command *cmd = state->cmd; + + while (cmd && + 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. */ + strbuf_reset(&state->buf); + if (!state->report) + state->report = cmd->report; + if (state->report) { + struct object_id *old_oid; + struct object_id *new_oid; + const char *ref_name; - /* buffer might be empty for keepalives */ - if (output->len) - send_sideband(1, 2, output->buf, output->len, use_sideband); + old_oid = state->report->old_oid ? state->report->old_oid : &cmd->old_oid; + new_oid = state->report->new_oid ? state->report->new_oid : &cmd->new_oid; + ref_name = state->report->ref_name ? state->report->ref_name : cmd->ref_name; + strbuf_addf(&state->buf, "%s %s %s\n", + oid_to_hex(old_oid), oid_to_hex(new_oid), + ref_name); + state->report = state->report->next; + if (!state->report) + state->cmd = cmd->next; + } else { + strbuf_addf(&state->buf, "%s %s %s\n", + oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid), + 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, @@ -878,65 +923,47 @@ static int run_receive_hook(struct command *commands, int skip_broken, const struct string_list *push_options) { - struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT; - struct command *iter = commands; - struct receive_hook_feed_state feed_state; - int ret; + struct receive_hook_feed_state state; + int status; - /* 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) + 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; - - if (push_options) { - for (int 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=%"PRIuMAX"", - (uintmax_t)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_output = hook_output_to_sideband; - - /* set up stdin callback */ - feed_state.cmd = commands; - feed_state.skip_broken = skip_broken; - feed_state.report = NULL; - strbuf_init(&feed_state.buf, 0); - opt.feed_pipe_cb_data = &feed_state; - opt.feed_pipe = feed_receive_hook_cb; - - ret = run_hooks_opt(the_repository, hook_name, &opt); - - strbuf_release(&feed_state.buf); - - return ret; + 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; } static int run_update_hook(struct command *cmd) { - struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT; + struct child_process proc = CHILD_PROCESS_INIT; + int code; + const char *hook_path = find_hook(the_repository, "update"); - strvec_pushl(&opt.args, - cmd->ref_name, - oid_to_hex(&cmd->old_oid), - oid_to_hex(&cmd->new_oid), - NULL); + if (!hook_path) + return 0; - if (use_sideband) - opt.consume_output = hook_output_to_sideband; + strvec_push(&proc.args, hook_path); + strvec_push(&proc.args, cmd->ref_name); + strvec_push(&proc.args, oid_to_hex(&cmd->old_oid)); + strvec_push(&proc.args, oid_to_hex(&cmd->new_oid)); + + proc.no_stdin = 1; + proc.stdout_to_stderr = 1; + proc.err = use_sideband ? -1 : 0; + proc.trace2_hook_name = "update"; - return run_hooks_opt(the_repository, "update", &opt); + code = start_command(&proc); + if (code) + return code; + if (use_sideband) + copy_to_sideband(proc.err, -1, NULL); + return finish_command(&proc); } static struct command *find_command_by_refname(struct command *list, @@ -1613,20 +1640,33 @@ out: static void run_update_post_hook(struct command *commands) { struct command *cmd; - struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT; + struct child_process proc = CHILD_PROCESS_INIT; + const char *hook; + + hook = find_hook(the_repository, "post-update"); + if (!hook) + return; for (cmd = commands; cmd; cmd = cmd->next) { if (cmd->error_string || cmd->did_not_exist) continue; - strvec_push(&opt.args, cmd->ref_name); + if (!proc.args.nr) + strvec_push(&proc.args, hook); + strvec_push(&proc.args, cmd->ref_name); } - if (!opt.args.nr) + if (!proc.args.nr) return; - if (use_sideband) - opt.consume_output = hook_output_to_sideband; + proc.no_stdin = 1; + proc.stdout_to_stderr = 1; + proc.err = use_sideband ? -1 : 0; + proc.trace2_hook_name = "post-update"; - run_hooks_opt(the_repository, "post-update", &opt); + if (!start_command(&proc)) { + if (use_sideband) + copy_to_sideband(proc.err, -1, NULL); + finish_command(&proc); + } } static void check_aliased_update_internal(struct command *cmd, |
