Skip to content

Commit b5e9ad5

Browse files
nasamuffingitster
authored andcommitted
receive-pack: convert receive hooks to hook API
This converts the last remaining hooks to the new hook API, for the same benefits as the previous conversions (no need to toggle signals, manage custom struct child_process, call find_hook(), prepares for specifying hooks via configs, etc.). See the previous three commits for a more in-depth explanation of how this all works. Signed-off-by: Emily Shaffer <emilyshaffer@google.com> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent fc148b1 commit b5e9ad5

1 file changed

Lines changed: 75 additions & 103 deletions

File tree

builtin/receive-pack.c

Lines changed: 75 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -791,7 +791,7 @@ static int check_cert_push_options(const struct string_list *push_options)
791791
return retval;
792792
}
793793

794-
static void prepare_push_cert_sha1(struct child_process *proc)
794+
static void prepare_push_cert_sha1(struct run_hooks_opt *opt)
795795
{
796796
static int already_done;
797797

@@ -817,23 +817,23 @@ static void prepare_push_cert_sha1(struct child_process *proc)
817817
nonce_status = check_nonce(sigcheck.payload);
818818
}
819819
if (!is_null_oid(&push_cert_oid)) {
820-
strvec_pushf(&proc->env, "GIT_PUSH_CERT=%s",
820+
strvec_pushf(&opt->env, "GIT_PUSH_CERT=%s",
821821
oid_to_hex(&push_cert_oid));
822-
strvec_pushf(&proc->env, "GIT_PUSH_CERT_SIGNER=%s",
822+
strvec_pushf(&opt->env, "GIT_PUSH_CERT_SIGNER=%s",
823823
sigcheck.signer ? sigcheck.signer : "");
824-
strvec_pushf(&proc->env, "GIT_PUSH_CERT_KEY=%s",
824+
strvec_pushf(&opt->env, "GIT_PUSH_CERT_KEY=%s",
825825
sigcheck.key ? sigcheck.key : "");
826-
strvec_pushf(&proc->env, "GIT_PUSH_CERT_STATUS=%c",
826+
strvec_pushf(&opt->env, "GIT_PUSH_CERT_STATUS=%c",
827827
sigcheck.result);
828828
if (push_cert_nonce) {
829-
strvec_pushf(&proc->env,
829+
strvec_pushf(&opt->env,
830830
"GIT_PUSH_CERT_NONCE=%s",
831831
push_cert_nonce);
832-
strvec_pushf(&proc->env,
832+
strvec_pushf(&opt->env,
833833
"GIT_PUSH_CERT_NONCE_STATUS=%s",
834834
nonce_status);
835835
if (nonce_status == NONCE_SLOP)
836-
strvec_pushf(&proc->env,
836+
strvec_pushf(&opt->env,
837837
"GIT_PUSH_CERT_NONCE_SLOP=%ld",
838838
nonce_stamp_slop);
839839
}
@@ -845,94 +845,25 @@ struct receive_hook_feed_state {
845845
struct ref_push_report *report;
846846
int skip_broken;
847847
struct strbuf buf;
848-
const struct string_list *push_options;
849848
};
850849

851-
typedef int (*feed_fn)(void *, const char **, size_t *);
852-
static int run_and_feed_hook(const char *hook_name, feed_fn feed,
853-
struct receive_hook_feed_state *feed_state)
850+
static int feed_receive_hook_cb(int hook_stdin_fd, void *pp_cb UNUSED, void *pp_task_cb)
854851
{
855-
struct child_process proc = CHILD_PROCESS_INIT;
856-
struct async muxer;
857-
int code;
858-
const char *hook_path = find_hook(the_repository, hook_name);
859-
860-
if (!hook_path)
861-
return 0;
862-
863-
strvec_push(&proc.args, hook_path);
864-
proc.in = -1;
865-
proc.stdout_to_stderr = 1;
866-
proc.trace2_hook_name = hook_name;
867-
868-
if (feed_state->push_options) {
869-
size_t i;
870-
for (i = 0; i < feed_state->push_options->nr; i++)
871-
strvec_pushf(&proc.env,
872-
"GIT_PUSH_OPTION_%"PRIuMAX"=%s",
873-
(uintmax_t)i,
874-
feed_state->push_options->items[i].string);
875-
strvec_pushf(&proc.env, "GIT_PUSH_OPTION_COUNT=%"PRIuMAX"",
876-
(uintmax_t)feed_state->push_options->nr);
877-
} else
878-
strvec_pushf(&proc.env, "GIT_PUSH_OPTION_COUNT");
879-
880-
if (tmp_objdir)
881-
strvec_pushv(&proc.env, tmp_objdir_env(tmp_objdir));
882-
883-
if (use_sideband) {
884-
memset(&muxer, 0, sizeof(muxer));
885-
muxer.proc = copy_to_sideband;
886-
muxer.in = -1;
887-
code = start_async(&muxer);
888-
if (code)
889-
return code;
890-
proc.err = muxer.in;
891-
}
892-
893-
prepare_push_cert_sha1(&proc);
894-
895-
code = start_command(&proc);
896-
if (code) {
897-
if (use_sideband)
898-
finish_async(&muxer);
899-
return code;
900-
}
901-
902-
sigchain_push(SIGPIPE, SIG_IGN);
903-
904-
while (1) {
905-
const char *buf;
906-
size_t n;
907-
if (feed(feed_state, &buf, &n))
908-
break;
909-
if (write_in_full(proc.in, buf, n) < 0)
910-
break;
911-
}
912-
close(proc.in);
913-
if (use_sideband)
914-
finish_async(&muxer);
915-
916-
sigchain_pop(SIGPIPE);
917-
918-
return finish_command(&proc);
919-
}
920-
921-
static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
922-
{
923-
struct receive_hook_feed_state *state = state_;
852+
struct receive_hook_feed_state *state = pp_task_cb;
924853
struct command *cmd = state->cmd;
925854

855+
strbuf_reset(&state->buf);
856+
926857
while (cmd &&
927858
state->skip_broken && (cmd->error_string || cmd->did_not_exist))
928859
cmd = cmd->next;
860+
929861
if (!cmd)
930-
return -1; /* EOF */
931-
if (!bufp)
932-
return 0; /* OK, can feed something. */
933-
strbuf_reset(&state->buf);
862+
return 1; /* no more commands left */
863+
934864
if (!state->report)
935865
state->report = cmd->report;
866+
936867
if (state->report) {
937868
struct object_id *old_oid;
938869
struct object_id *new_oid;
@@ -941,44 +872,85 @@ static int feed_receive_hook(void *state_, const char **bufp, size_t *sizep)
941872
old_oid = state->report->old_oid ? state->report->old_oid : &cmd->old_oid;
942873
new_oid = state->report->new_oid ? state->report->new_oid : &cmd->new_oid;
943874
ref_name = state->report->ref_name ? state->report->ref_name : cmd->ref_name;
875+
944876
strbuf_addf(&state->buf, "%s %s %s\n",
945877
oid_to_hex(old_oid), oid_to_hex(new_oid),
946878
ref_name);
879+
947880
state->report = state->report->next;
948881
if (!state->report)
949-
state->cmd = cmd->next;
882+
cmd = cmd->next;
950883
} else {
951884
strbuf_addf(&state->buf, "%s %s %s\n",
952885
oid_to_hex(&cmd->old_oid), oid_to_hex(&cmd->new_oid),
953886
cmd->ref_name);
954-
state->cmd = cmd->next;
887+
cmd = cmd->next;
955888
}
956-
if (bufp) {
957-
*bufp = state->buf.buf;
958-
*sizep = state->buf.len;
889+
890+
state->cmd = cmd;
891+
892+
if (state->buf.len > 0) {
893+
int ret = write_in_full(hook_stdin_fd, state->buf.buf, state->buf.len);
894+
if (ret < 0) {
895+
if (errno == EPIPE)
896+
return 1; /* child closed pipe */
897+
return ret;
898+
}
959899
}
960-
return 0;
900+
901+
return state->cmd ? 0 : 1; /* 0 = more to come, 1 = EOF */
961902
}
962903

963904
static int run_receive_hook(struct command *commands,
964905
const char *hook_name,
965906
int skip_broken,
966907
const struct string_list *push_options)
967908
{
968-
struct receive_hook_feed_state state;
969-
int status;
909+
struct run_hooks_opt opt = RUN_HOOKS_OPT_INIT;
910+
struct command *iter = commands;
911+
struct receive_hook_feed_state feed_state;
912+
struct async sideband_async;
913+
int sideband_async_started = 0;
914+
int saved_stderr = -1;
915+
int ret;
970916

971-
strbuf_init(&state.buf, 0);
972-
state.cmd = commands;
973-
state.skip_broken = skip_broken;
974-
state.report = NULL;
975-
if (feed_receive_hook(&state, NULL, NULL))
917+
/* if there are no valid commands, don't invoke the hook at all. */
918+
while (iter && skip_broken && (iter->error_string || iter->did_not_exist))
919+
iter = iter->next;
920+
if (!iter)
976921
return 0;
977-
state.cmd = commands;
978-
state.push_options = push_options;
979-
status = run_and_feed_hook(hook_name, feed_receive_hook, &state);
980-
strbuf_release(&state.buf);
981-
return status;
922+
923+
if (push_options) {
924+
for (int i = 0; i < push_options->nr; i++)
925+
strvec_pushf(&opt.env, "GIT_PUSH_OPTION_%d=%s", i,
926+
push_options->items[i].string);
927+
strvec_pushf(&opt.env, "GIT_PUSH_OPTION_COUNT=%"PRIuMAX"",
928+
(uintmax_t)push_options->nr);
929+
} else {
930+
strvec_push(&opt.env, "GIT_PUSH_OPTION_COUNT");
931+
}
932+
933+
if (tmp_objdir)
934+
strvec_pushv(&opt.env, tmp_objdir_env(tmp_objdir));
935+
936+
prepare_push_cert_sha1(&opt);
937+
938+
prepare_sideband_async(&sideband_async, &saved_stderr, &sideband_async_started);
939+
940+
/* set up stdin callback */
941+
feed_state.cmd = commands;
942+
feed_state.skip_broken = skip_broken;
943+
feed_state.report = NULL;
944+
strbuf_init(&feed_state.buf, 0);
945+
opt.feed_pipe_cb_data = &feed_state;
946+
opt.feed_pipe = feed_receive_hook_cb;
947+
948+
ret = run_hooks_opt(the_repository, hook_name, &opt);
949+
950+
strbuf_release(&feed_state.buf);
951+
finish_sideband_async(&sideband_async, saved_stderr, sideband_async_started);
952+
953+
return ret;
982954
}
983955

984956
static int run_update_hook(struct command *cmd)

0 commit comments

Comments
 (0)