
Using the show_usage_and_exit_if_asked() helper we introduced earlier, fix callers of usage() that want to show the help text when explicitly asked by the end-user. The help text now goes to the standard output stream for them. These are the bog standard "if we got only '-h', then that is a request for help" callers. Their if (argc == 2 && !strcmp(argv[1], "-h")) usage(message); are simply replaced with show_usage_and_exit_if_asked(argc, argv, message); With this, the built-ins tested by t0012 all send their help text to their standard output stream, so the check in t0012 that was half tightened earlier is now fully tightened to insist on standard error stream being empty. Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
148 lines
3.4 KiB
C
148 lines
3.4 KiB
C
/*
|
|
* Copyright (c) 2006 Franck Bui-Huu
|
|
*/
|
|
#define USE_THE_REPOSITORY_VARIABLE
|
|
#include "builtin.h"
|
|
#include "archive.h"
|
|
#include "path.h"
|
|
#include "pkt-line.h"
|
|
#include "sideband.h"
|
|
#include "run-command.h"
|
|
#include "strvec.h"
|
|
|
|
static const char upload_archive_usage[] =
|
|
"git upload-archive <repository>";
|
|
|
|
static const char deadchild[] =
|
|
"git upload-archive: archiver died with error";
|
|
|
|
#define MAX_ARGS (64)
|
|
|
|
int cmd_upload_archive_writer(int argc,
|
|
const char **argv,
|
|
const char *prefix,
|
|
struct repository *repo UNUSED)
|
|
{
|
|
struct strvec sent_argv = STRVEC_INIT;
|
|
const char *arg_cmd = "argument ";
|
|
int ret;
|
|
|
|
show_usage_if_asked(argc, argv, upload_archive_usage);
|
|
if (argc != 2)
|
|
usage(upload_archive_usage);
|
|
|
|
if (!enter_repo(argv[1], 0))
|
|
die("'%s' does not appear to be a git repository", argv[1]);
|
|
|
|
init_archivers();
|
|
|
|
/* put received options in sent_argv[] */
|
|
strvec_push(&sent_argv, "git-upload-archive");
|
|
for (;;) {
|
|
char *buf = packet_read_line(0, NULL);
|
|
if (!buf)
|
|
break; /* got a flush */
|
|
if (sent_argv.nr > MAX_ARGS)
|
|
die("Too many options (>%d)", MAX_ARGS - 1);
|
|
|
|
if (!starts_with(buf, arg_cmd))
|
|
die("'argument' token or flush expected");
|
|
strvec_push(&sent_argv, buf + strlen(arg_cmd));
|
|
}
|
|
|
|
/* parse all options sent by the client */
|
|
ret = write_archive(sent_argv.nr, sent_argv.v, prefix,
|
|
the_repository, NULL, 1);
|
|
|
|
strvec_clear(&sent_argv);
|
|
return ret;
|
|
}
|
|
|
|
__attribute__((format (printf, 1, 2)))
|
|
static void error_clnt(const char *fmt, ...)
|
|
{
|
|
struct strbuf buf = STRBUF_INIT;
|
|
va_list params;
|
|
|
|
va_start(params, fmt);
|
|
strbuf_vaddf(&buf, fmt, params);
|
|
va_end(params);
|
|
send_sideband(1, 3, buf.buf, buf.len, LARGE_PACKET_MAX);
|
|
die("sent error to the client: %s", buf.buf);
|
|
}
|
|
|
|
static ssize_t process_input(int child_fd, int band)
|
|
{
|
|
char buf[16384];
|
|
ssize_t sz = read(child_fd, buf, sizeof(buf));
|
|
if (sz < 0) {
|
|
if (errno != EAGAIN && errno != EINTR)
|
|
error_clnt("read error: %s\n", strerror(errno));
|
|
return sz;
|
|
}
|
|
send_sideband(1, band, buf, sz, LARGE_PACKET_MAX);
|
|
return sz;
|
|
}
|
|
|
|
int cmd_upload_archive(int argc,
|
|
const char **argv,
|
|
const char *prefix,
|
|
struct repository *repo UNUSED)
|
|
{
|
|
struct child_process writer = CHILD_PROCESS_INIT;
|
|
|
|
BUG_ON_NON_EMPTY_PREFIX(prefix);
|
|
|
|
show_usage_if_asked(argc, argv, upload_archive_usage);
|
|
|
|
/*
|
|
* Set up sideband subprocess.
|
|
*
|
|
* We (parent) monitor and read from child, sending its fd#1 and fd#2
|
|
* multiplexed out to our fd#1. If the child dies, we tell the other
|
|
* end over channel #3.
|
|
*/
|
|
writer.out = writer.err = -1;
|
|
writer.git_cmd = 1;
|
|
strvec_push(&writer.args, "upload-archive--writer");
|
|
strvec_pushv(&writer.args, argv + 1);
|
|
if (start_command(&writer)) {
|
|
int err = errno;
|
|
packet_write_fmt(1, "NACK unable to spawn subprocess\n");
|
|
die("upload-archive: %s", strerror(err));
|
|
}
|
|
|
|
packet_write_fmt(1, "ACK\n");
|
|
packet_flush(1);
|
|
|
|
while (1) {
|
|
struct pollfd pfd[2];
|
|
|
|
pfd[0].fd = writer.out;
|
|
pfd[0].events = POLLIN;
|
|
pfd[1].fd = writer.err;
|
|
pfd[1].events = POLLIN;
|
|
if (poll(pfd, 2, -1) < 0) {
|
|
if (errno != EINTR) {
|
|
error_errno("poll failed resuming");
|
|
sleep(1);
|
|
}
|
|
continue;
|
|
}
|
|
if (pfd[1].revents & POLLIN)
|
|
/* Status stream ready */
|
|
if (process_input(pfd[1].fd, 2))
|
|
continue;
|
|
if (pfd[0].revents & POLLIN)
|
|
/* Data stream ready */
|
|
if (process_input(pfd[0].fd, 1))
|
|
continue;
|
|
|
|
if (finish_command(&writer))
|
|
error_clnt("%s", deadchild);
|
|
packet_flush(1);
|
|
break;
|
|
}
|
|
return 0;
|
|
}
|