git/builtin/archive.c
Elijah Newren d1cbe1e6d8 hash-ll.h: split out of hash.h to remove dependency on repository.h
hash.h depends upon and includes repository.h, due to the definition and
use of the_hash_algo (defined as the_repository->hash_algo).  However,
most headers trying to include hash.h are only interested in the layout
of the structs like object_id.  Move the parts of hash.h that do not
depend upon repository.h into a new file hash-ll.h (the "low level"
parts of hash.h), and adjust other files to use this new header where
the convenience inline functions aren't needed.

This allows hash.h and object.h to be fairly small, minimal headers.  It
also exposes a lot of hidden dependencies on both path.h (which was
brought in by repository.h) and repository.h (which was previously
implicitly brought in by object.h), so also adjust other files to be
more explicit about what they depend upon.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2023-04-24 12:47:32 -07:00

113 lines
3.1 KiB
C

/*
* Copyright (c) 2006 Franck Bui-Huu
* Copyright (c) 2006 Rene Scharfe
*/
#include "cache.h"
#include "builtin.h"
#include "archive.h"
#include "gettext.h"
#include "transport.h"
#include "parse-options.h"
#include "pkt-line.h"
#include "repository.h"
#include "sideband.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);
if (!_remote->url[0])
die(_("git archive: Remote with no URL"));
transport = transport_get(_remote, _remote->url[0]);
transport_connect(transport, "git-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)
{
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()
};
argc = parse_options(argc, argv, prefix, local_opts, NULL,
PARSE_OPT_KEEP_ALL);
init_archivers();
if (output)
create_output_file(output);
if (remote)
return run_remote_archiver(argc, argv, remote, exec, output);
setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
UNLEAK(output);
return write_archive(argc, argv, prefix, the_repository, output, 0);
}