@@ -87,6 +87,7 @@ static const char *nonce_status;
static long nonce_stamp_slop;
static timestamp_t nonce_stamp_slop_limit;
static struct ref_transaction *transaction;
+struct argv_array post_receive_env_array;
static enum {
KEEPALIVE_NEVER = 0,
@@ -694,7 +695,9 @@ struct receive_hook_feed_state {
};
typedef int (*feed_fn)(void *, const char **, size_t *);
+typedef void (*stdout_handler_fn)(int out);
static int run_and_feed_hook(const char *hook_name, feed_fn feed,
+ stdout_handler_fn stdout_handler,
struct receive_hook_feed_state *feed_state)
{
struct child_process proc = CHILD_PROCESS_INIT;
@@ -716,9 +719,15 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
proc.argv = argv;
proc.in = -1;
- proc.stdout_to_stderr = 1;
+ if (stdout_handler)
+ proc.out = -1;
+ else
+ proc.stdout_to_stderr = 1;
proc.trace2_hook_name = hook_name;
+ if (!strcmp(hook_name, "post-receive") && post_receive_env_array.argc > 0)
+ argv_array_pushv(&proc.env_array, post_receive_env_array.argv);
+
if (feed_state->push_options) {
int i;
for (i = 0; i < feed_state->push_options->nr; i++)
@@ -763,6 +772,10 @@ static int run_and_feed_hook(const char *hook_name, feed_fn feed,
break;
}
close(proc.in);
+
+ if (stdout_handler)
+ stdout_handler(proc.out);
+
if (use_sideband)
finish_async(&muxer);
@@ -819,7 +832,7 @@ static int run_receive_hook(struct command *commands,
return 0;
state.cmd = commands;
state.push_options = push_options;
- status = run_and_feed_hook(hook_name, feed_receive_hook, &state);
+ status = run_and_feed_hook(hook_name, feed_receive_hook, NULL, &state);
strbuf_release(&state.buf);
return status;
}
@@ -853,6 +866,23 @@ static int run_update_hook(struct command *cmd)
return finish_command(&proc);
}
+static void prepare_post_receive_env(int in)
+{
+ struct strbuf stdout_buf = STRBUF_INIT;
+
+ while (strbuf_getwholeline_fd(&stdout_buf, in, '\n') != EOF) {
+ char *p = stdout_buf.buf + stdout_buf.len -1;
+ if (*p =='\n')
+ *p = '\0';
+ p = strchr(stdout_buf.buf, '=');
+ if (p == NULL)
+ continue;
+ argv_array_push(&post_receive_env_array, stdout_buf.buf);
+ strbuf_reset(&stdout_buf);
+ }
+ strbuf_release(&stdout_buf);
+}
+
static int run_proc_receive_hook(struct command *commands,
const struct string_list *push_options)
{
@@ -869,7 +899,8 @@ static int run_proc_receive_hook(struct command *commands,
return 0;
state.cmd = commands;
state.push_options = push_options;
- status = run_and_feed_hook("proc-receive", feed_receive_hook, &state);
+ status = run_and_feed_hook("proc-receive",
+ feed_receive_hook, prepare_post_receive_env, &state);
strbuf_release(&state.buf);
return status;
}
@@ -2040,6 +2071,7 @@ int cmd_receive_pack(int argc, const char **argv, const char *prefix)
};
string_list_init(&proc_receive_refs, 0);
+ argv_array_init(&post_receive_env_array);
packet_trace_identity("receive-pack");
@@ -687,4 +687,74 @@ test_expect_success "(6) push both a normal and a special refs (declined)" '
test_cmp expect actual
'
+test_expect_success "(7) restore pre-receive hook" '
+ mv $bare/hooks/pre-receive $bare/hooks/pre-receive.fail &&
+ mv $bare/hooks/pre-receive.ok $bare/hooks/pre-receive
+'
+
+test_expect_success "(7) new proc-receive and post-receive hooks (pass environment variables)" '
+ ## proc-receive hook
+ mv $bare/hooks/proc-receive $bare/hooks/proc-receive.ok &&
+ cat >$bare/hooks/proc-receive <<-EOF &&
+ #!/bin/sh
+
+ printf >&2 "execute: proc-receive hook\n"
+
+ while read old new ref
+ do
+ printf >&2 ">> old: \$old, new: \$new, ref: \$ref.\n"
+ done
+
+ printf "GIT_VAR1=var1\n"
+ printf "GIT_VAR2=var2\n"
+ printf "AGIT_VAR1=foo\n"
+ printf "AGIT_VAR2=bar\n"
+ EOF
+ chmod a+x $bare/hooks/proc-receive &&
+
+ ## post-receive hook
+ mv $bare/hooks/post-receive $bare/hooks/post-receive.ok &&
+ cat >$bare/hooks/post-receive <<-EOF &&
+ #!/bin/sh
+
+ printf >&2 "execute: post-receive hook\n"
+
+ while read old new ref
+ do
+ printf >&2 ">> old: \$old, new: \$new, ref: \$ref.\n"
+ done
+
+ for k in GIT_VAR1 GIT_VAR2 AGIT_VAR1 AGIT_VAR2
+ do
+ if test -n "\$(eval echo \\"\\\$\$k\")"
+ then
+ printf >&2 ">> has env: \$k=\$(eval echo \\"\\\$\$k\").\n"
+ fi
+ done
+ EOF
+ chmod a+x $bare/hooks/post-receive
+'
+
+test_expect_success "(7) push one special ref (show environments)" '
+ (
+ cd work &&
+ git push origin \
+ HEAD:refs/for/master/my/topic
+ ) >out 2>&1 &&
+ grep "^remote:" out | sed -e "s/ *\$//g" >actual &&
+ cat >expect <<-EOF &&
+ remote: execute: pre-receive hook
+ remote: >> old: $ZERO_OID, new: $B, ref: refs/for/master/my/topic.
+ remote: execute: proc-receive hook
+ remote: >> old: $ZERO_OID, new: $B, ref: refs/for/master/my/topic.
+ remote: execute: post-receive hook
+ remote: >> old: $ZERO_OID, new: $B, ref: refs/for/master/my/topic.
+ remote: >> has env: GIT_VAR1=var1.
+ remote: >> has env: GIT_VAR2=var2.
+ remote: >> has env: AGIT_VAR1=foo.
+ remote: >> has env: AGIT_VAR2=bar.
+ EOF
+ test_cmp expect actual
+'
+
test_done