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>
Shawn O. Pearce committed
Feb 5, 2010 at 12:57 UTC
0c499ea60fda716198c76f2d5febe3998d302afb
1 file changed
+50
-16
builtin-send-pack.c
+50
-16
@@ -372,6 +372,14 @@ static void print_helper_status(struct ref *ref)
372
strbuf_release(&buf);
373
}
374
375
+static int sideband_demux(int in, int out, void *data)
376
+{
377
+ int *fd = data;
378
+ int ret = recv_sideband("send-pack", fd[0], out);
379
+ close(out);
380
+ return ret;
381
+}
382
+
383
int send_pack(struct send_pack_args *args,
384
int fd[], struct child_process *conn,
385
struct ref *remote_refs,
@@ -382,18 +390,22 @@ int send_pack(struct send_pack_args *args,
390
struct strbuf req_buf = STRBUF_INIT;
391
struct ref *ref;
392
int new_refs;
385
- int ask_for_status_report = 0;
393
int allow_deleting_refs = 0;
387
- int expect_status_report = 0;
394
+ int status_report = 0;
395
+ int use_sideband = 0;
396
+ unsigned cmds_sent = 0;
397
int ret;
398
+ struct async demux;
399
400
/* Does the other end support the reporting? */
401
if (server_supports("report-status"))
392
- ask_for_status_report = 1;
402
+ status_report = 1;
403
if (server_supports("delete-refs"))
404
allow_deleting_refs = 1;
405
if (server_supports("ofs-delta"))
406
args->use_ofs_delta = 1;
407
+ if (server_supports("side-band-64k"))
408
+ use_sideband = 1;
409
410
if (!remote_refs) {
411
fprintf(stderr, "No refs in common and none specified; doing nothing.\n"
@@ -456,28 +468,30 @@ int send_pack(struct send_pack_args *args,
468
if (!ref->deletion)
469
new_refs++;
470
459
- if (!args->dry_run) {
471
+ if (args->dry_run) {
472
+ ref->status = REF_STATUS_OK;
473
+ } else {
474
char *old_hex = sha1_to_hex(ref->old_sha1);
475
char *new_hex = sha1_to_hex(ref->new_sha1);
476
463
- if (ask_for_status_report) {
464
- packet_buf_write(&req_buf, "%s %s %s%c%s",
477
+ if (!cmds_sent && (status_report || use_sideband)) {
478
+ packet_buf_write(&req_buf, "%s %s %s%c%s%s",
479
old_hex, new_hex, ref->name, 0,
466
- "report-status");
467
- ask_for_status_report = 0;
468
- expect_status_report = 1;
480
+ status_report ? " report-status" : "",
481
+ use_sideband ? " side-band-64k" : "");
482
}
483
else
484
packet_buf_write(&req_buf, "%s %s %s",
485
old_hex, new_hex, ref->name);
486
+ ref->status = status_report ?
487
+ REF_STATUS_EXPECTING_REPORT :
488
+ REF_STATUS_OK;
489
+ cmds_sent++;
490
}
474
- ref->status = expect_status_report ?
475
- REF_STATUS_EXPECTING_REPORT :
476
- REF_STATUS_OK;
491
}
492
493
if (args->stateless_rpc) {
480
- if (!args->dry_run) {
494
+ if (!args->dry_run && cmds_sent) {
495
packet_buf_flush(&req_buf);
496
send_sideband(out, -1, req_buf.buf, req_buf.len, LARGE_PACKET_MAX);
497
}
@@ -487,23 +501,43 @@ int send_pack(struct send_pack_args *args,
501
}
502
strbuf_release(&req_buf);
503
490
- if (new_refs && !args->dry_run) {
504
+ if (use_sideband && cmds_sent) {
505
+ memset(&demux, 0, sizeof(demux));
506
+ demux.proc = sideband_demux;
507
+ demux.data = fd;
508
+ demux.out = -1;
509
+ if (start_async(&demux))
510
+ die("receive-pack: unable to fork off sideband demultiplexer");
511
+ in = demux.out;
512
+ }
513
+
514
+ if (new_refs && cmds_sent) {
515
if (pack_objects(out, remote_refs, extra_have, args) < 0) {
516
for (ref = remote_refs; ref; ref = ref->next)
517
ref->status = REF_STATUS_NONE;
518
+ if (use_sideband)
519
+ finish_async(&demux);
520
return -1;
521
}
522
}
497
- if (args->stateless_rpc && !args->dry_run)
523
+ if (args->stateless_rpc && cmds_sent)
524
packet_flush(out);
525
500
- if (expect_status_report)
526
+ if (status_report && cmds_sent)
527
ret = receive_status(in, remote_refs);
528
else
529
ret = 0;
530
if (args->stateless_rpc)
531
packet_flush(out);
532
533
+ if (use_sideband && cmds_sent) {
534
+ if (finish_async(&demux)) {
535
+ error("error in sideband demultiplexer");
536
+ ret = -1;
537
+ }
538
+ close(demux.out);
539
+ }
540
+
541
if (ret < 0)
542
return ret;
543
for (ref = remote_refs; ref; ref = ref->next) {