send-pack: demultiplex a sideband stream with status data

If the server advertises side-band-64k capability, we request
it and pull the status report data out of side band #1, and let
side band #2 go to our stderr.  The latter channel be used by the
remote side to send our user messages.  This basically mirrors the
side-band-64k capability in upload-pack.

Servers may choose to use side band #2 to send error messages from
hook scripts that are meant for the push end user.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Shawn O. Pearce 2010-02-05 12:57:39 -08:00 committed by Junio C Hamano
parent ae6a5609c0
commit 0c499ea60f

View File

@ -372,6 +372,14 @@ static void print_helper_status(struct ref *ref)
strbuf_release(&buf); strbuf_release(&buf);
} }
static int sideband_demux(int in, int out, void *data)
{
int *fd = data;
int ret = recv_sideband("send-pack", fd[0], out);
close(out);
return ret;
}
int send_pack(struct send_pack_args *args, int send_pack(struct send_pack_args *args,
int fd[], struct child_process *conn, int fd[], struct child_process *conn,
struct ref *remote_refs, struct ref *remote_refs,
@ -382,18 +390,22 @@ int send_pack(struct send_pack_args *args,
struct strbuf req_buf = STRBUF_INIT; struct strbuf req_buf = STRBUF_INIT;
struct ref *ref; struct ref *ref;
int new_refs; int new_refs;
int ask_for_status_report = 0;
int allow_deleting_refs = 0; int allow_deleting_refs = 0;
int expect_status_report = 0; int status_report = 0;
int use_sideband = 0;
unsigned cmds_sent = 0;
int ret; int ret;
struct async demux;
/* Does the other end support the reporting? */ /* Does the other end support the reporting? */
if (server_supports("report-status")) if (server_supports("report-status"))
ask_for_status_report = 1; status_report = 1;
if (server_supports("delete-refs")) if (server_supports("delete-refs"))
allow_deleting_refs = 1; allow_deleting_refs = 1;
if (server_supports("ofs-delta")) if (server_supports("ofs-delta"))
args->use_ofs_delta = 1; args->use_ofs_delta = 1;
if (server_supports("side-band-64k"))
use_sideband = 1;
if (!remote_refs) { if (!remote_refs) {
fprintf(stderr, "No refs in common and none specified; doing nothing.\n" fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
@ -456,28 +468,30 @@ int send_pack(struct send_pack_args *args,
if (!ref->deletion) if (!ref->deletion)
new_refs++; new_refs++;
if (!args->dry_run) { if (args->dry_run) {
ref->status = REF_STATUS_OK;
} else {
char *old_hex = sha1_to_hex(ref->old_sha1); char *old_hex = sha1_to_hex(ref->old_sha1);
char *new_hex = sha1_to_hex(ref->new_sha1); char *new_hex = sha1_to_hex(ref->new_sha1);
if (ask_for_status_report) { if (!cmds_sent && (status_report || use_sideband)) {
packet_buf_write(&req_buf, "%s %s %s%c%s", packet_buf_write(&req_buf, "%s %s %s%c%s%s",
old_hex, new_hex, ref->name, 0, old_hex, new_hex, ref->name, 0,
"report-status"); status_report ? " report-status" : "",
ask_for_status_report = 0; use_sideband ? " side-band-64k" : "");
expect_status_report = 1;
} }
else else
packet_buf_write(&req_buf, "%s %s %s", packet_buf_write(&req_buf, "%s %s %s",
old_hex, new_hex, ref->name); old_hex, new_hex, ref->name);
ref->status = status_report ?
REF_STATUS_EXPECTING_REPORT :
REF_STATUS_OK;
cmds_sent++;
} }
ref->status = expect_status_report ?
REF_STATUS_EXPECTING_REPORT :
REF_STATUS_OK;
} }
if (args->stateless_rpc) { if (args->stateless_rpc) {
if (!args->dry_run) { if (!args->dry_run && cmds_sent) {
packet_buf_flush(&req_buf); packet_buf_flush(&req_buf);
send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX); send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
} }
@ -487,23 +501,43 @@ int send_pack(struct send_pack_args *args,
} }
strbuf_release(&req_buf); strbuf_release(&req_buf);
if (new_refs && !args->dry_run) { if (use_sideband && cmds_sent) {
memset(&demux, 0, sizeof(demux));
demux.proc = sideband_demux;
demux.data = fd;
demux.out = -1;
if (start_async(&demux))
die("receive-pack: unable to fork off sideband demultiplexer");
in = demux.out;
}
if (new_refs && cmds_sent) {
if (pack_objects(out, remote_refs, extra_have, args) < 0) { if (pack_objects(out, remote_refs, extra_have, args) < 0) {
for (ref = remote_refs; ref; ref = ref->next) for (ref = remote_refs; ref; ref = ref->next)
ref->status = REF_STATUS_NONE; ref->status = REF_STATUS_NONE;
if (use_sideband)
finish_async(&demux);
return -1; return -1;
} }
} }
if (args->stateless_rpc && !args->dry_run) if (args->stateless_rpc && cmds_sent)
packet_flush(out); packet_flush(out);
if (expect_status_report) if (status_report && cmds_sent)
ret = receive_status(in, remote_refs); ret = receive_status(in, remote_refs);
else else
ret = 0; ret = 0;
if (args->stateless_rpc) if (args->stateless_rpc)
packet_flush(out); packet_flush(out);
if (use_sideband && cmds_sent) {
if (finish_async(&demux)) {
error("error in sideband demultiplexer");
ret = -1;
}
close(demux.out);
}
if (ret < 0) if (ret < 0)
return ret; return ret;
for (ref = remote_refs; ref; ref = ref->next) { for (ref = remote_refs; ref; ref = ref->next) {