e013bdab0f
Clean up pkt-line API, implementation and its callers to make them more robust. * jk/pkt-line-cleanup: do not use GIT_TRACE_PACKET=3 in tests remote-curl: always parse incoming refs remote-curl: move ref-parsing code up in file remote-curl: pass buffer straight to get_remote_heads teach get_remote_heads to read from a memory buffer pkt-line: share buffer/descriptor reading implementation pkt-line: provide a LARGE_PACKET_MAX static buffer pkt-line: move LARGE_PACKET_MAX definition from sideband pkt-line: teach packet_read_line to chomp newlines pkt-line: provide a generic reading function with options pkt-line: drop safe_write function pkt-line: move a misplaced comment write_or_die: raise SIGPIPE when we get EPIPE upload-archive: use argv_array to store client arguments upload-archive: do not copy repo name send-pack: prefer prefixcmp over memcmp in receive_status fetch-pack: fix out-of-bounds buffer offset in get_ack upload-pack: remove packet debugging harness upload-pack: do not add duplicate objects to shallow list upload-pack: use get_sha1_hex to parse "shallow" lines
183 lines
4.2 KiB
C
183 lines
4.2 KiB
C
#include "builtin.h"
|
|
#include "pkt-line.h"
|
|
#include "fetch-pack.h"
|
|
|
|
static const char fetch_pack_usage[] =
|
|
"git fetch-pack [--all] [--stdin] [--quiet|-q] [--keep|-k] [--thin] "
|
|
"[--include-tag] [--upload-pack=<git-upload-pack>] [--depth=<n>] "
|
|
"[--no-progress] [-v] [<host>:]<directory> [<refs>...]";
|
|
|
|
static void add_sought_entry_mem(struct ref ***sought, int *nr, int *alloc,
|
|
const char *name, int namelen)
|
|
{
|
|
struct ref *ref = xcalloc(1, sizeof(*ref) + namelen + 1);
|
|
|
|
memcpy(ref->name, name, namelen);
|
|
ref->name[namelen] = '\0';
|
|
(*nr)++;
|
|
ALLOC_GROW(*sought, *nr, *alloc);
|
|
(*sought)[*nr - 1] = ref;
|
|
}
|
|
|
|
static void add_sought_entry(struct ref ***sought, int *nr, int *alloc,
|
|
const char *string)
|
|
{
|
|
add_sought_entry_mem(sought, nr, alloc, string, strlen(string));
|
|
}
|
|
|
|
int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
|
|
{
|
|
int i, ret;
|
|
struct ref *ref = NULL;
|
|
const char *dest = NULL;
|
|
struct ref **sought = NULL;
|
|
int nr_sought = 0, alloc_sought = 0;
|
|
int fd[2];
|
|
char *pack_lockfile = NULL;
|
|
char **pack_lockfile_ptr = NULL;
|
|
struct child_process *conn;
|
|
struct fetch_pack_args args;
|
|
|
|
packet_trace_identity("fetch-pack");
|
|
|
|
memset(&args, 0, sizeof(args));
|
|
args.uploadpack = "git-upload-pack";
|
|
|
|
for (i = 1; i < argc && *argv[i] == '-'; i++) {
|
|
const char *arg = argv[i];
|
|
|
|
if (!prefixcmp(arg, "--upload-pack=")) {
|
|
args.uploadpack = arg + 14;
|
|
continue;
|
|
}
|
|
if (!prefixcmp(arg, "--exec=")) {
|
|
args.uploadpack = arg + 7;
|
|
continue;
|
|
}
|
|
if (!strcmp("--quiet", arg) || !strcmp("-q", arg)) {
|
|
args.quiet = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp("--keep", arg) || !strcmp("-k", arg)) {
|
|
args.lock_pack = args.keep_pack;
|
|
args.keep_pack = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp("--thin", arg)) {
|
|
args.use_thin_pack = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp("--include-tag", arg)) {
|
|
args.include_tag = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp("--all", arg)) {
|
|
args.fetch_all = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp("--stdin", arg)) {
|
|
args.stdin_refs = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp("-v", arg)) {
|
|
args.verbose = 1;
|
|
continue;
|
|
}
|
|
if (!prefixcmp(arg, "--depth=")) {
|
|
args.depth = strtol(arg + 8, NULL, 0);
|
|
continue;
|
|
}
|
|
if (!strcmp("--no-progress", arg)) {
|
|
args.no_progress = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp("--stateless-rpc", arg)) {
|
|
args.stateless_rpc = 1;
|
|
continue;
|
|
}
|
|
if (!strcmp("--lock-pack", arg)) {
|
|
args.lock_pack = 1;
|
|
pack_lockfile_ptr = &pack_lockfile;
|
|
continue;
|
|
}
|
|
usage(fetch_pack_usage);
|
|
}
|
|
|
|
if (i < argc)
|
|
dest = argv[i++];
|
|
else
|
|
usage(fetch_pack_usage);
|
|
|
|
/*
|
|
* Copy refs from cmdline to growable list, then append any
|
|
* refs from the standard input:
|
|
*/
|
|
for (; i < argc; i++)
|
|
add_sought_entry(&sought, &nr_sought, &alloc_sought, argv[i]);
|
|
if (args.stdin_refs) {
|
|
if (args.stateless_rpc) {
|
|
/* in stateless RPC mode we use pkt-line to read
|
|
* from stdin, until we get a flush packet
|
|
*/
|
|
for (;;) {
|
|
char *line = packet_read_line(0, NULL);
|
|
if (!line)
|
|
break;
|
|
add_sought_entry(&sought, &nr_sought, &alloc_sought, line);
|
|
}
|
|
}
|
|
else {
|
|
/* read from stdin one ref per line, until EOF */
|
|
struct strbuf line = STRBUF_INIT;
|
|
while (strbuf_getline(&line, stdin, '\n') != EOF)
|
|
add_sought_entry(&sought, &nr_sought, &alloc_sought, line.buf);
|
|
strbuf_release(&line);
|
|
}
|
|
}
|
|
|
|
if (args.stateless_rpc) {
|
|
conn = NULL;
|
|
fd[0] = 0;
|
|
fd[1] = 1;
|
|
} else {
|
|
conn = git_connect(fd, dest, args.uploadpack,
|
|
args.verbose ? CONNECT_VERBOSE : 0);
|
|
}
|
|
|
|
get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL);
|
|
|
|
ref = fetch_pack(&args, fd, conn, ref, dest,
|
|
sought, nr_sought, pack_lockfile_ptr);
|
|
if (pack_lockfile) {
|
|
printf("lock %s\n", pack_lockfile);
|
|
fflush(stdout);
|
|
}
|
|
close(fd[0]);
|
|
close(fd[1]);
|
|
if (finish_connect(conn))
|
|
return 1;
|
|
|
|
ret = !ref;
|
|
|
|
/*
|
|
* If the heads to pull were given, we should have consumed
|
|
* all of them by matching the remote. Otherwise, 'git fetch
|
|
* remote no-such-ref' would silently succeed without issuing
|
|
* an error.
|
|
*/
|
|
for (i = 0; i < nr_sought; i++) {
|
|
if (!sought[i] || sought[i]->matched)
|
|
continue;
|
|
error("no such remote ref %s", sought[i]->name);
|
|
ret = 1;
|
|
}
|
|
|
|
while (ref) {
|
|
printf("%s %s\n",
|
|
sha1_to_hex(ref->old_sha1), ref->name);
|
|
ref = ref->next;
|
|
}
|
|
|
|
return ret;
|
|
}
|