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
parent
38a81b4e82
commit
6d525d389f
|
@ -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)
|
||||||
|
|
|
@ -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…
Reference in New Issue