summaryrefslogtreecommitdiff
path: root/fetch-pack.c
diff options
context:
space:
mode:
authorJonathan Tan <jonathantanmy@google.com>2020-06-10 20:57:23 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-06-11 01:06:34 (GMT)
commitdd4b732df73b06878b81fce050e7dcac4366a38e (patch)
tree7bfe19e33dc531f2eb0ef6fba249bcc819f772ed /fetch-pack.c
parent9da69a6539e98da1b7ed8832cb54b494961463cb (diff)
downloadgit-dd4b732df73b06878b81fce050e7dcac4366a38e.zip
git-dd4b732df73b06878b81fce050e7dcac4366a38e.tar.gz
git-dd4b732df73b06878b81fce050e7dcac4366a38e.tar.bz2
upload-pack: send part of packfile response as uri
Teach upload-pack to send part of its packfile response as URIs. An administrator may configure a repository with one or more "uploadpack.blobpackfileuri" lines, each line containing an OID, a pack hash, and a URI. A client may configure fetch.uriprotocols to be a comma-separated list of protocols that it is willing to use to fetch additional packfiles - this list will be sent to the server. Whenever an object with one of those OIDs would appear in the packfile transmitted by upload-pack, the server may exclude that object, and instead send the URI. The client will then download the packs referred to by those URIs before performing the connectivity check. Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'fetch-pack.c')
-rw-r--r--fetch-pack.c112
1 files changed, 108 insertions, 4 deletions
diff --git a/fetch-pack.c b/fetch-pack.c
index bc3af3c..ca2b101 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -38,6 +38,7 @@ static int server_supports_filtering;
static struct shallow_lock shallow_lock;
static const char *alternate_shallow_file;
static struct strbuf fsck_msg_types = STRBUF_INIT;
+static struct string_list uri_protocols = STRING_LIST_INIT_DUP;
/* Remember to update object flag allocation in object.h */
#define COMPLETE (1U << 0)
@@ -795,6 +796,7 @@ static void write_promisor_file(const char *keep_name,
static int get_pack(struct fetch_pack_args *args,
int xd[2], struct string_list *pack_lockfiles,
+ int only_packfile,
struct ref **sought, int nr_sought)
{
struct async demux;
@@ -855,8 +857,15 @@ static int get_pack(struct fetch_pack_args *args,
"--keep=fetch-pack %"PRIuMAX " on %s",
(uintmax_t)getpid(), hostname);
}
- if (args->check_self_contained_and_connected)
+ if (only_packfile && args->check_self_contained_and_connected)
argv_array_push(&cmd.args, "--check-self-contained-and-connected");
+ else
+ /*
+ * We cannot perform any connectivity checks because
+ * not all packs have been downloaded; let the caller
+ * have this responsibility.
+ */
+ args->check_self_contained_and_connected = 0;
/*
* If we're obtaining the filename of a lockfile, we'll use
* that filename to write a .promisor file with more
@@ -1068,7 +1077,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
alternate_shallow_file = setup_temporary_shallow(si->shallow);
else
alternate_shallow_file = NULL;
- if (get_pack(args, fd, pack_lockfiles, sought, nr_sought))
+ if (get_pack(args, fd, pack_lockfiles, 1, sought, nr_sought))
die(_("git fetch-pack: fetch failed."));
all_done:
@@ -1222,6 +1231,26 @@ static int send_fetch_request(struct fetch_negotiator *negotiator, int fd_out,
warning("filtering not recognized by server, ignoring");
}
+ if (server_supports_feature("fetch", "packfile-uris", 0)) {
+ int i;
+ struct strbuf to_send = STRBUF_INIT;
+
+ for (i = 0; i < uri_protocols.nr; i++) {
+ const char *s = uri_protocols.items[i].string;
+
+ if (!strcmp(s, "https") || !strcmp(s, "http")) {
+ if (to_send.len)
+ strbuf_addch(&to_send, ',');
+ strbuf_addstr(&to_send, s);
+ }
+ }
+ if (to_send.len) {
+ packet_buf_write(&req_buf, "packfile-uris %s",
+ to_send.buf);
+ strbuf_release(&to_send);
+ }
+ }
+
/* add wants */
add_wants(args->no_dependents, wants, &req_buf);
@@ -1444,6 +1473,21 @@ static void receive_wanted_refs(struct packet_reader *reader,
die(_("error processing wanted refs: %d"), reader->status);
}
+static void receive_packfile_uris(struct packet_reader *reader,
+ struct string_list *uris)
+{
+ process_section_header(reader, "packfile-uris", 0);
+ while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
+ if (reader->pktlen < the_hash_algo->hexsz ||
+ reader->line[the_hash_algo->hexsz] != ' ')
+ die("expected '<hash> <uri>', got: %s\n", reader->line);
+
+ string_list_append(uris, reader->line);
+ }
+ if (reader->status != PACKET_READ_DELIM)
+ die("expected DELIM");
+}
+
enum fetch_state {
FETCH_CHECK_LOCAL = 0,
FETCH_SEND_REQUEST,
@@ -1470,6 +1514,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
struct fetch_negotiator negotiator_alloc;
struct fetch_negotiator *negotiator;
int seen_ack = 0;
+ struct string_list packfile_uris = STRING_LIST_INIT_DUP;
+ int i;
if (args->no_dependents) {
negotiator = NULL;
@@ -1558,9 +1604,12 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
if (process_section_header(&reader, "wanted-refs", 1))
receive_wanted_refs(&reader, sought, nr_sought);
- /* get the pack */
+ /* get the pack(s) */
+ if (process_section_header(&reader, "packfile-uris", 1))
+ receive_packfile_uris(&reader, &packfile_uris);
process_section_header(&reader, "packfile", 0);
- if (get_pack(args, fd, pack_lockfiles, sought, nr_sought))
+ if (get_pack(args, fd, pack_lockfiles,
+ !packfile_uris.nr, sought, nr_sought))
die(_("git fetch-pack: fetch failed."));
state = FETCH_DONE;
@@ -1570,8 +1619,55 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
}
}
+ for (i = 0; i < packfile_uris.nr; i++) {
+ struct child_process cmd = CHILD_PROCESS_INIT;
+ char packname[GIT_MAX_HEXSZ + 1];
+ const char *uri = packfile_uris.items[i].string +
+ the_hash_algo->hexsz + 1;
+
+ argv_array_push(&cmd.args, "http-fetch");
+ argv_array_pushf(&cmd.args, "--packfile=%.*s",
+ (int) the_hash_algo->hexsz,
+ packfile_uris.items[i].string);
+ argv_array_push(&cmd.args, uri);
+ cmd.git_cmd = 1;
+ cmd.no_stdin = 1;
+ cmd.out = -1;
+ if (start_command(&cmd))
+ die("fetch-pack: unable to spawn http-fetch");
+
+ if (read_in_full(cmd.out, packname, 5) < 0 ||
+ memcmp(packname, "keep\t", 5))
+ die("fetch-pack: expected keep then TAB at start of http-fetch output");
+
+ if (read_in_full(cmd.out, packname,
+ the_hash_algo->hexsz + 1) < 0 ||
+ packname[the_hash_algo->hexsz] != '\n')
+ die("fetch-pack: expected hash then LF at end of http-fetch output");
+
+ packname[the_hash_algo->hexsz] = '\0';
+
+ close(cmd.out);
+
+ if (finish_command(&cmd))
+ die("fetch-pack: unable to finish http-fetch");
+
+ if (memcmp(packfile_uris.items[i].string, packname,
+ the_hash_algo->hexsz))
+ die("fetch-pack: pack downloaded from %s does not match expected hash %.*s",
+ uri, (int) the_hash_algo->hexsz,
+ packfile_uris.items[i].string);
+
+ string_list_append_nodup(pack_lockfiles,
+ xstrfmt("%s/pack/pack-%s.keep",
+ get_object_directory(),
+ packname));
+ }
+ string_list_clear(&packfile_uris, 0);
+
if (negotiator)
negotiator->release(negotiator);
+
oidset_clear(&common);
return ref;
}
@@ -1608,6 +1704,14 @@ static void fetch_pack_config(void)
git_config_get_bool("repack.usedeltabaseoffset", &prefer_ofs_delta);
git_config_get_bool("fetch.fsckobjects", &fetch_fsck_objects);
git_config_get_bool("transfer.fsckobjects", &transfer_fsck_objects);
+ if (!uri_protocols.nr) {
+ char *str;
+
+ if (!git_config_get_string("fetch.uriprotocols", &str) && str) {
+ string_list_split(&uri_protocols, str, ',', -1);
+ free(str);
+ }
+ }
git_config(fetch_pack_config_cb, NULL);
}