mirror of
https://github.com/git-for-windows/git.git
synced 2026-06-14 15:01:15 -05:00
The git_connect() function takes a "name" argument which is a bit confusing. It is _not_ the program to run on the remote repo, which is specified by the "prog" argument. It should instead be one of a few well-known strings specifying the type of operation (e.g., "git-upload-pack"). But to add to the confusion, unless otherwise configured, those well-known strings will also be the same as the programs we run, making it easy to mistake which variable is which. This confusion comes fromeaa0fd6584(git_connect(): fix corner cases in downgrading v2 to v0, 2023-03-17), though in its defense, the term "name" and the use of a string are found in other connect code, going all the way back tob236752a87(Support remote archive from all smart transports, 2009-12-09). But let's see if we can clean things up a bit. The term "name" is overly vague. We use "service" in other places, including in the smart-http protocol, so let's use it here, too. Using a string invites the notion that it can be anything, not one of a defined set. Let's instead introduce an enum, which has the added bonus that the compiler can catch typos for us, rather than quietly choosing the wrong service from an unexpected strcmp() result. We do still have to turn our enum into those well-known strings to pass along in the remote-helper protocol (e.g., for a stateless-connect directive). But now we do so explicitly and in a way that I think is much more obvious to follow. This is a pure cleanup; there should be no behavior change. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
118 lines
3.0 KiB
C
118 lines
3.0 KiB
C
/*
|
|
* Copyright (c) 2006 Franck Bui-Huu
|
|
* Copyright (c) 2006 Rene Scharfe
|
|
*/
|
|
#include "builtin.h"
|
|
#include "archive.h"
|
|
#include "gettext.h"
|
|
#include "transport.h"
|
|
#include "parse-options.h"
|
|
#include "pkt-line.h"
|
|
|
|
static void create_output_file(const char *output_file)
|
|
{
|
|
int output_fd = xopen(output_file, O_CREAT | O_WRONLY | O_TRUNC, 0666);
|
|
if (output_fd != 1) {
|
|
if (dup2(output_fd, 1) < 0)
|
|
die_errno(_("could not redirect output"));
|
|
else
|
|
close(output_fd);
|
|
}
|
|
}
|
|
|
|
static int run_remote_archiver(int argc, const char **argv,
|
|
const char *remote, const char *exec,
|
|
const char *name_hint)
|
|
{
|
|
int fd[2], i, rv;
|
|
struct transport *transport;
|
|
struct remote *_remote;
|
|
struct packet_reader reader;
|
|
|
|
_remote = remote_get(remote);
|
|
transport = transport_get(_remote, _remote->url.v[0]);
|
|
transport_connect(transport, GIT_CONNECT_UPLOAD_ARCHIVE, exec, fd);
|
|
|
|
/*
|
|
* Inject a fake --format field at the beginning of the
|
|
* arguments, with the format inferred from our output
|
|
* filename. This way explicit --format options can override
|
|
* it.
|
|
*/
|
|
if (name_hint) {
|
|
const char *format = archive_format_from_filename(name_hint);
|
|
if (format)
|
|
packet_write_fmt(fd[1], "argument --format=%s\n", format);
|
|
}
|
|
for (i = 1; i < argc; i++)
|
|
packet_write_fmt(fd[1], "argument %s\n", argv[i]);
|
|
packet_flush(fd[1]);
|
|
|
|
packet_reader_init(&reader, fd[0], NULL, 0,
|
|
PACKET_READ_CHOMP_NEWLINE |
|
|
PACKET_READ_DIE_ON_ERR_PACKET);
|
|
|
|
if (packet_reader_read(&reader) != PACKET_READ_NORMAL)
|
|
die(_("git archive: expected ACK/NAK, got a flush packet"));
|
|
if (strcmp(reader.line, "ACK")) {
|
|
if (starts_with(reader.line, "NACK "))
|
|
die(_("git archive: NACK %s"), reader.line + 5);
|
|
die(_("git archive: protocol error"));
|
|
}
|
|
|
|
if (packet_reader_read(&reader) != PACKET_READ_FLUSH)
|
|
die(_("git archive: expected a flush"));
|
|
|
|
/* Now, start reading from fd[0] and spit it out to stdout */
|
|
rv = recv_sideband("archive", fd[0], 1);
|
|
rv |= transport_disconnect(transport);
|
|
|
|
return !!rv;
|
|
}
|
|
|
|
#define PARSE_OPT_KEEP_ALL ( PARSE_OPT_KEEP_DASHDASH | \
|
|
PARSE_OPT_KEEP_ARGV0 | \
|
|
PARSE_OPT_KEEP_UNKNOWN_OPT | \
|
|
PARSE_OPT_NO_INTERNAL_HELP )
|
|
|
|
int cmd_archive(int argc,
|
|
const char **argv,
|
|
const char *prefix,
|
|
struct repository *repo)
|
|
{
|
|
const char *exec = "git-upload-archive";
|
|
char *output = NULL;
|
|
const char *remote = NULL;
|
|
struct option local_opts[] = {
|
|
OPT_FILENAME('o', "output", &output,
|
|
N_("write the archive to this file")),
|
|
OPT_STRING(0, "remote", &remote, N_("repo"),
|
|
N_("retrieve the archive from remote repository <repo>")),
|
|
OPT_STRING(0, "exec", &exec, N_("command"),
|
|
N_("path to the remote git-upload-archive command")),
|
|
OPT_END()
|
|
};
|
|
int ret;
|
|
|
|
argc = parse_options(argc, argv, prefix, local_opts, NULL,
|
|
PARSE_OPT_KEEP_ALL);
|
|
|
|
init_archivers();
|
|
|
|
if (output)
|
|
create_output_file(output);
|
|
|
|
if (remote) {
|
|
ret = run_remote_archiver(argc, argv, remote, exec, output);
|
|
goto out;
|
|
}
|
|
|
|
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
|
|
|
|
ret = write_archive(argc, argv, prefix, repo, output, 0);
|
|
|
|
out:
|
|
free(output);
|
|
return ret;
|
|
}
|