Skip to content

Commit a3d1f39

Browse files
committed
Revert "Merge branch 'ar/run-command-hook'"
This reverts commit f406b89, reversing changes made to 1627809. 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.
1 parent 7264e61 commit a3d1f39

13 files changed

Lines changed: 292 additions & 586 deletions

File tree

Documentation/RelNotes/2.53.0.adoc

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,6 @@ Performance, Internal Implementation, Development Support etc.
9393
* Prepare test suite for Git for Windows that supports symbolic
9494
links.
9595
96-
* Use hook API to replace ad-hoc invocation of hook scripts with the
97-
run_command() API.
98-
9996
* Import newer version of "clar", unit testing framework.
10097
(merge 84071a6dea ps/clar-integers later to maint).
10198

builtin/hook.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,6 @@ static int run(int argc, const char **argv, const char *prefix,
4343
if (!argc)
4444
goto usage;
4545

46-
/*
47-
* All current "hook run" use-cases require ungrouped child output.
48-
* If this changes, a hook run argument can be added to toggle it.
49-
*/
50-
opt.ungroup = 1;
51-
5246
/*
5347
* Having a -- for "run" when providing <hook-args> is
5448
* mandatory.

builtin/receive-pack.c

Lines changed: 155 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -749,7 +749,7 @@ static int check_cert_push_options(const struct string_list *push_options)
749749
return retval;
750750
}
751751

752-
static void prepare_push_cert_sha1(struct run_hooks_opt *opt)
752+
static void prepare_push_cert_sha1(struct child_process *proc)
753753
{
754754
static int already_done;
755755

@@ -775,23 +775,23 @@ static void prepare_push_cert_sha1(struct run_hooks_opt *opt)
775775
nonce_status = check_nonce(sigcheck.payload);
776776
}
777777
if (!is_null_oid(&push_cert_oid)) {
778-
strvec_pushf(&opt->env, "GIT_PUSH_CERT=%s",
778+
strvec_pushf(&proc->env, "GIT_PUSH_CERT=%s",
779779
oid_to_hex(&push_cert_oid));
780-
strvec_pushf(&opt->env, "GIT_PUSH_CERT_SIGNER=%s",
780+
strvec_pushf(&proc->env, "GIT_PUSH_CERT_SIGNER=%s",
781781
sigcheck.signer ? sigcheck.signer : "");
782-
strvec_pushf(&opt->env, "GIT_PUSH_CERT_KEY=%s",
782+
strvec_pushf(&proc->env, "GIT_PUSH_CERT_KEY=%s",
783783
sigcheck.key ? sigcheck.key : "");
784-
strvec_pushf(&opt->env, "GIT_PUSH_CERT_STATUS=%c",
784+
strvec_pushf(&proc->env, "GIT_PUSH_CERT_STATUS=%c",
785785
sigcheck.result);
786786
if (push_cert_nonce) {
787-
strvec_pushf(&opt->env,
787+
strvec_pushf(&proc->env,
788788
"GIT_PUSH_CERT_NONCE=%s",
789789
push_cert_nonce);
790-
strvec_pushf(&opt->env,
790+
strvec_pushf(&proc->env,
791791
"GIT_PUSH_CERT_NONCE_STATUS=%s",
792792
nonce_status);
793793
if (nonce_status == NONCE_SLOP)
794-
strvec_pushf(&opt->env,
794+
strvec_pushf(&proc->env,
795795
"GIT_PUSH_CERT_NONCE_SLOP=%ld",
796796
nonce_stamp_slop);
797797
}
@@ -803,140 +803,167 @@ struct receive_hook_feed_state {
803803
struct ref_push_report *report;
804804
int skip_broken;
805805
struct strbuf buf;
806+
const struct string_list *push_options;
806807
};
807808

808-
static int feed_receive_hook_cb(int hook_stdin_fd, void *pp_cb UNUSED, void *pp_task_cb)
809+
typedef int (*feed_fn)(void *, const char **, size_t *);
810+
static int run_and_feed_hook(const char *hook_name, feed_fn feed,
811+
struct receive_hook_feed_state *feed_state)
809812
{
810-
struct receive_hook_feed_state *state = pp_task_cb;
811-
struct command *cmd = state->cmd;
812-
unsigned int lines_batch_size = 500;
813-
814-
strbuf_reset(&state->buf);
815-
816-
/* batch lines to avoid going through run-command's poll loop for each line */
817-
for (unsigned int i = 0; i < lines_batch_size; i++) {
818-
while (cmd &&
819-
state->skip_broken && (cmd->error_string || cmd->did_not_exist))
820-
cmd = cmd->next;
813+
struct child_process proc = CHILD_PROCESS_INIT;
814+
struct async muxer;
815+
int code;
816+
const char *hook_path = find_hook(the_repository, hook_name);
821817

822-
if (!cmd)
823-
break; /* no more commands left */
818+
if (!hook_path)
819+
return 0;
824820

825-
if (!state->report)
826-
state->report = cmd->report;
821+
strvec_push(&proc.args, hook_path);
822+
proc.in = -1;
823+
proc.stdout_to_stderr = 1;
824+
proc.trace2_hook_name = hook_name;
825+
826+
if (feed_state->push_options) {
827+
size_t i;
828+
for (i = 0; i < feed_state->push_options->nr; i++)
829+
strvec_pushf(&proc.env,
830+
"GIT_PUSH_OPTION_%"PRIuMAX"=%s",
831+
(uintmax_t)i,
832+
feed_state->push_options->items[i].string);
833+
strvec_pushf(&proc.env, "GIT_PUSH_OPTION_COUNT=%"PRIuMAX"",
834+
(uintmax_t)feed_state->push_options->nr);
835+
} else
836+
strvec_pushf(&proc.env, "GIT_PUSH_OPTION_COUNT");
827837

828-
if (state->report) {
829-
struct object_id *old_oid;
830-
struct object_id *new_oid;
831-
const char *ref_name;
838+
if (tmp_objdir)
839+
strvec_pushv(&proc.env, tmp_objdir_env(tmp_objdir));
832840

833-
old_oid = state->report->old_oid ? state->report->old_oid : &cmd->old_oid;
834-
new_oid = state->report->new_oid ? state->report->new_oid : &cmd->new_oid;
835-
ref_name = state->report->ref_name ? state->report->ref_name : cmd->ref_name;
841+
if (use_sideband) {
842+
memset(&muxer, 0, sizeof(muxer));
843+
muxer.proc = copy_to_sideband;
844+
muxer.in = -1;
845+
code = start_async(&muxer);
846+
if (code)
847+
return code;
848+
proc.err = muxer.in;
849+
}
836850

837-
strbuf_addf(&state->buf, "%s %s %s\n",
838-
oid_to_hex(old_oid), oid_to_hex(new_oid),
839-
ref_name);
851+
prepare_push_cert_sha1(&proc);
840852

841-
state->report = state->report->next;
842-
if (!state->report)
843-
cmd = cmd->next;
844-
} else {
845-
strbuf_addf(&state->buf, "%s %s %s\n",
846-
oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid),
847-
cmd->ref_name);
848-
cmd = cmd->next;
849-
}
853+
code = start_command(&proc);
854+
if (code) {
855+
if (use_sideband)
856+
finish_async(&muxer);
857+
return code;
850858
}
851859

852-
state->cmd = cmd;
860+
sigchain_push(SIGPIPE, SIG_IGN);
853861

854-
if (state->buf.len > 0) {
855-
int ret = write_in_full(hook_stdin_fd, state->buf.buf, state->buf.len);
856-
if (ret < 0) {
857-
if (errno == EPIPE)
858-
return 1; /* child closed pipe */
859-
return ret;
860-
}
862+
while (1) {
863+
const char *buf;
864+
size_t n;
865+
if (feed(feed_state, &buf, &n))
866+
break;
867+
if (write_in_full(proc.in, buf, n) < 0)
868+
break;
861869
}
870+
close(proc.in);
871+
if (use_sideband)
872+
finish_async(&muxer);
862873

863-
return state->cmd ? 0 : 1; /* 0 = more to come, 1 = EOF */
874+
sigchain_pop(SIGPIPE);
875+
876+
return finish_command(&proc);
864877
}
865878

866-
static void hook_output_to_sideband(struct strbuf *output, void *cb_data UNUSED)
879+
static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
867880
{
868-
if (!output)
869-
BUG("output must be non-NULL");
881+
struct receive_hook_feed_state *state = state_;
882+
struct command *cmd = state->cmd;
870883

871-
/* buffer might be empty for keepalives */
872-
if (output->len)
873-
send_sideband(1, 2, output->buf, output->len, use_sideband);
884+
while (cmd &&
885+
state->skip_broken && (cmd->error_string || cmd->did_not_exist))
886+
cmd = cmd->next;
887+
if (!cmd)
888+
return -1; /* EOF */
889+
if (!bufp)
890+
return 0; /* OK, can feed something. */
891+
strbuf_reset(&state->buf);
892+
if (!state->report)
893+
state->report = cmd->report;
894+
if (state->report) {
895+
struct object_id *old_oid;
896+
struct object_id *new_oid;
897+
const char *ref_name;
898+
899+
old_oid = state->report->old_oid ? state->report->old_oid : &cmd->old_oid;
900+
new_oid = state->report->new_oid ? state->report->new_oid : &cmd->new_oid;
901+
ref_name = state->report->ref_name ? state->report->ref_name : cmd->ref_name;
902+
strbuf_addf(&state->buf, "%s %s %s\n",
903+
oid_to_hex(old_oid), oid_to_hex(new_oid),
904+
ref_name);
905+
state->report = state->report->next;
906+
if (!state->report)
907+
state->cmd = cmd->next;
908+
} else {
909+
strbuf_addf(&state->buf, "%s %s %s\n",
910+
oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid),
911+
cmd->ref_name);
912+
state->cmd = cmd->next;
913+
}
914+
if (bufp) {
915+
*bufp = state->buf.buf;
916+
*sizep = state->buf.len;
917+
}
918+
return 0;
874919
}
875920

876921
static int run_receive_hook(struct command *commands,
877922
const char *hook_name,
878923
int skip_broken,
879924
const struct string_list *push_options)
880925
{
881-
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
882-
struct command *iter = commands;
883-
struct receive_hook_feed_state feed_state;
884-
int ret;
885-
886-
/* if there are no valid commands, don't invoke the hook at all. */
887-
while (iter && skip_broken && (iter->error_string || iter->did_not_exist))
888-
iter = iter->next;
889-
if (!iter)
890-
return 0;
891-
892-
if (push_options) {
893-
for (int i = 0; i < push_options->nr; i++)
894-
strvec_pushf(&opt.env, "GIT_PUSH_OPTION_%d=%s", i,
895-
push_options->items[i].string);
896-
strvec_pushf(&opt.env, "GIT_PUSH_OPTION_COUNT=%"PRIuMAX"",
897-
(uintmax_t)push_options->nr);
898-
} else {
899-
strvec_push(&opt.env, "GIT_PUSH_OPTION_COUNT");
900-
}
901-
902-
if (tmp_objdir)
903-
strvec_pushv(&opt.env, tmp_objdir_env(tmp_objdir));
904-
905-
prepare_push_cert_sha1(&opt);
906-
907-
/* set up sideband printer */
908-
if (use_sideband)
909-
opt.consume_output = hook_output_to_sideband;
910-
911-
/* set up stdin callback */
912-
feed_state.cmd = commands;
913-
feed_state.skip_broken = skip_broken;
914-
feed_state.report = NULL;
915-
strbuf_init(&feed_state.buf, 0);
916-
opt.feed_pipe_cb_data = &feed_state;
917-
opt.feed_pipe = feed_receive_hook_cb;
918-
919-
ret = run_hooks_opt(the_repository, hook_name, &opt);
920-
921-
strbuf_release(&feed_state.buf);
926+
struct receive_hook_feed_state state;
927+
int status;
922928

923-
return ret;
929+
strbuf_init(&state.buf, 0);
930+
state.cmd = commands;
931+
state.skip_broken = skip_broken;
932+
state.report = NULL;
933+
if (feed_receive_hook(&state, NULL, NULL))
934+
return 0;
935+
state.cmd = commands;
936+
state.push_options = push_options;
937+
status = run_and_feed_hook(hook_name, feed_receive_hook, &state);
938+
strbuf_release(&state.buf);
939+
return status;
924940
}
925941

926942
static int run_update_hook(struct command *cmd)
927943
{
928-
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
944+
struct child_process proc = CHILD_PROCESS_INIT;
945+
int code;
946+
const char *hook_path = find_hook(the_repository, "update");
929947

930-
strvec_pushl(&opt.args,
931-
cmd->ref_name,
932-
oid_to_hex(&cmd->old_oid),
933-
oid_to_hex(&cmd->new_oid),
934-
NULL);
948+
if (!hook_path)
949+
return 0;
935950

936-
if (use_sideband)
937-
opt.consume_output = hook_output_to_sideband;
951+
strvec_push(&proc.args, hook_path);
952+
strvec_push(&proc.args, cmd->ref_name);
953+
strvec_push(&proc.args, oid_to_hex(&cmd->old_oid));
954+
strvec_push(&proc.args, oid_to_hex(&cmd->new_oid));
955+
956+
proc.no_stdin = 1;
957+
proc.stdout_to_stderr = 1;
958+
proc.err = use_sideband ? -1 : 0;
959+
proc.trace2_hook_name = "update";
938960

939-
return run_hooks_opt(the_repository, "update", &opt);
961+
code = start_command(&proc);
962+
if (code)
963+
return code;
964+
if (use_sideband)
965+
copy_to_sideband(proc.err, -1, NULL);
966+
return finish_command(&proc);
940967
}
941968

942969
static struct command *find_command_by_refname(struct command *list,
@@ -1613,20 +1640,33 @@ static const char *update(struct command *cmd, struct shallow_info *si)
16131640
static void run_update_post_hook(struct command *commands)
16141641
{
16151642
struct command *cmd;
1616-
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
1643+
struct child_process proc = CHILD_PROCESS_INIT;
1644+
const char *hook;
1645+
1646+
hook = find_hook(the_repository, "post-update");
1647+
if (!hook)
1648+
return;
16171649

16181650
for (cmd = commands; cmd; cmd = cmd->next) {
16191651
if (cmd->error_string || cmd->did_not_exist)
16201652
continue;
1621-
strvec_push(&opt.args, cmd->ref_name);
1653+
if (!proc.args.nr)
1654+
strvec_push(&proc.args, hook);
1655+
strvec_push(&proc.args, cmd->ref_name);
16221656
}
1623-
if (!opt.args.nr)
1657+
if (!proc.args.nr)
16241658
return;
16251659

1626-
if (use_sideband)
1627-
opt.consume_output = hook_output_to_sideband;
1660+
proc.no_stdin = 1;
1661+
proc.stdout_to_stderr = 1;
1662+
proc.err = use_sideband ? -1 : 0;
1663+
proc.trace2_hook_name = "post-update";
16281664

1629-
run_hooks_opt(the_repository, "post-update", &opt);
1665+
if (!start_command(&proc)) {
1666+
if (use_sideband)
1667+
copy_to_sideband(proc.err, -1, NULL);
1668+
finish_command(&proc);
1669+
}
16301670
}
16311671

16321672
static void check_aliased_update_internal(struct command *cmd,

commit.c

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,9 +1978,6 @@ int run_commit_hook(int editor_is_used, const char *index_file,
19781978
strvec_push(&opt.args, arg);
19791979
va_end(args);
19801980

1981-
/* All commit hook use-cases require ungrouping child output. */
1982-
opt.ungroup = 1;
1983-
19841981
opt.invoked_hook = invoked_hook;
19851982
return run_hooks_opt(the_repository, name, &opt);
19861983
}

0 commit comments

Comments
 (0)