Browse Source

receive-pack: Send hook output over side band #2

If the client requests to enable side-band-64k capability we can
safely send any hook stdout or stderr data down side band #2,
so the client can present it to the user.

If side-band-64k isn't enabled, hooks continue to inherit stderr
from the parent receive-pack process.

When the side band channel is being used the push client will wind up
prefixing all server messages with "remote: ", just like fetch does,
so our test vector has to be updated with the new expected output.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Shawn O. Pearce 15 years ago committed by Junio C Hamano
parent
commit
6d525d389f
  1. 65
      builtin-receive-pack.c
  2. 22
      t/t5401-update-hooks.sh

65
builtin-receive-pack.c

@ -139,11 +139,25 @@ static struct command *commands;
static const char pre_receive_hook[] = "hooks/pre-receive"; static const char pre_receive_hook[] = "hooks/pre-receive";
static const char post_receive_hook[] = "hooks/post-receive"; static const char post_receive_hook[] = "hooks/post-receive";


static int copy_to_sideband(int in, int out, void *arg)
{
char data[128];
while (1) {
ssize_t sz = xread(in, data, sizeof(data));
if (sz <= 0)
break;
send_sideband(1, 2, data, sz, use_sideband);
}
close(in);
return 0;
}

static int run_receive_hook(const char *hook_name) static int run_receive_hook(const char *hook_name)
{ {
static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4]; static char buf[sizeof(commands->old_sha1) * 2 + PATH_MAX + 4];
struct command *cmd; struct command *cmd;
struct child_process proc; struct child_process proc;
struct async muxer;
const char *argv[2]; const char *argv[2];
int have_input = 0, code; int have_input = 0, code;


@ -163,9 +177,23 @@ static int run_receive_hook(const char *hook_name)
proc.in = -1; proc.in = -1;
proc.stdout_to_stderr = 1; proc.stdout_to_stderr = 1;


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;
}

code = start_command(&proc); code = start_command(&proc);
if (code) if (code) {
if (use_sideband)
finish_async(&muxer);
return code; return code;
}

for (cmd = commands; cmd; cmd = cmd->next) { for (cmd = commands; cmd; cmd = cmd->next) {
if (!cmd->error_string) { if (!cmd->error_string) {
size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n", size_t n = snprintf(buf, sizeof(buf), "%s %s %s\n",
@ -177,6 +205,8 @@ static int run_receive_hook(const char *hook_name)
} }
} }
close(proc.in); close(proc.in);
if (use_sideband)
finish_async(&muxer);
return finish_command(&proc); return finish_command(&proc);
} }


@ -184,6 +214,8 @@ static int run_update_hook(struct command *cmd)
{ {
static const char update_hook[] = "hooks/update"; static const char update_hook[] = "hooks/update";
const char *argv[5]; const char *argv[5];
struct child_process proc;
int code;


if (access(update_hook, X_OK) < 0) if (access(update_hook, X_OK) < 0)
return 0; return 0;
@ -194,8 +226,18 @@ static int run_update_hook(struct command *cmd)
argv[3] = sha1_to_hex(cmd->new_sha1); argv[3] = sha1_to_hex(cmd->new_sha1);
argv[4] = NULL; argv[4] = NULL;


return run_command_v_opt(argv, RUN_COMMAND_NO_STDIN | memset(&proc, 0, sizeof(proc));
RUN_COMMAND_STDOUT_TO_STDERR); proc.no_stdin = 1;
proc.stdout_to_stderr = 1;
proc.err = use_sideband ? -1 : 0;
proc.argv = argv;

code = start_command(&proc);
if (code)
return code;
if (use_sideband)
copy_to_sideband(proc.err, -1, NULL);
return finish_command(&proc);
} }


static int is_ref_checked_out(const char *ref) static int is_ref_checked_out(const char *ref)
@ -384,8 +426,9 @@ static char update_post_hook[] = "hooks/post-update";
static void run_update_post_hook(struct command *cmd) static void run_update_post_hook(struct command *cmd)
{ {
struct command *cmd_p; struct command *cmd_p;
int argc, status; int argc;
const char **argv; const char **argv;
struct child_process proc;


for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) { for (argc = 0, cmd_p = cmd; cmd_p; cmd_p = cmd_p->next) {
if (cmd_p->error_string) if (cmd_p->error_string)
@ -407,8 +450,18 @@ static void run_update_post_hook(struct command *cmd)
argc++; argc++;
} }
argv[argc] = NULL; argv[argc] = NULL;
status = run_command_v_opt(argv, RUN_COMMAND_NO_STDIN
| RUN_COMMAND_STDOUT_TO_STDERR); memset(&proc, 0, sizeof(proc));
proc.no_stdin = 1;
proc.stdout_to_stderr = 1;
proc.err = use_sideband ? -1 : 0;
proc.argv = argv;

if (!start_command(&proc)) {
if (use_sideband)
copy_to_sideband(proc.err, -1, NULL);
finish_command(&proc);
}
} }


static void execute_commands(const char *unpacker_error) static void execute_commands(const char *unpacker_error)

22
t/t5401-update-hooks.sh

@ -118,19 +118,19 @@ test_expect_success 'send-pack produced no output' '
' '


cat <<EOF >expect cat <<EOF >expect
STDOUT pre-receive remote: STDOUT pre-receive
STDERR pre-receive remote: STDERR pre-receive
STDOUT update refs/heads/master remote: STDOUT update refs/heads/master
STDERR update refs/heads/master remote: STDERR update refs/heads/master
STDOUT update refs/heads/tofail remote: STDOUT update refs/heads/tofail
STDERR update refs/heads/tofail remote: STDERR update refs/heads/tofail
STDOUT post-receive remote: STDOUT post-receive
STDERR post-receive remote: STDERR post-receive
STDOUT post-update remote: STDOUT post-update
STDERR post-update remote: STDERR post-update
EOF EOF
test_expect_success 'send-pack stderr contains hook messages' ' test_expect_success 'send-pack stderr contains hook messages' '
grep ^STD send.err >actual && grep ^remote: send.err | sed "s/ *\$//" >actual &&
test_cmp - actual <expect test_cmp - actual <expect
' '



Loading…
Cancel
Save