fetch-pack: support shallow requests

Enable shallow clones and deepen requests using protocol version 2 if the server 'fetch' command supports the 'shallow' feature. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Brandon Williams committed Mar 15, 2018 at 10:31 UTC f7e205010542dc9b712473d260058e43ca2b26f7
4 files changed +105 -8
Documentation/technical/protocol-v2.txt
+11 -7
@@ -255,6 +255,10 @@ A `fetch` request can take the following arguments:
255 to its base by position in pack rather than by an oid. That is,
256 they can read OBJ_OFS_DELTA (ake type 6) in a packfile.
257
258 +If the 'shallow' feature is advertised the following arguments can be
259 +included in the clients request as well as the potential addition of the
260 +'shallow-info' section in the server's response as explained below.
261 +
262 shallow <oid>
263 A client must notify the server of all commits for which it only
264 has shallow copies (meaning that it doesn't have the parents of
@@ -338,13 +342,13 @@ header.
342 further negotiation is needed.
343
344 shallow-info section
341 - If the client has requested a shallow fetch/clone, a shallow
342 - client requests a fetch or the server is shallow then the
343 - server's response may include a shallow-info section. The
344 - shallow-info section will be included if (due to one of the
345 - above conditions) the server needs to inform the client of any
346 - shallow boundaries or adjustments to the clients already
347 - existing shallow boundaries.
345 + * If the client has requested a shallow fetch/clone, a shallow
346 + client requests a fetch or the server is shallow then the
347 + server's response may include a shallow-info section. The
348 + shallow-info section will be included if (due to one of the
349 + above conditions) the server needs to inform the client of any
350 + shallow boundaries or adjustments to the clients already
351 + existing shallow boundaries.
352
353 * Always begins with the section header "shallow-info"
354
connect.c
+22
@@ -82,6 +82,28 @@ int server_supports_v2(const char *c, int die_on_error)
82 return 0;
83 }
84
85 +int server_supports_feature(const char *c, const char *feature,
86 + int die_on_error)
87 +{
88 + int i;
89 +
90 + for (i = 0; i < server_capabilities_v2.argc; i++) {
91 + const char *out;
92 + if (skip_prefix(server_capabilities_v2.argv[i], c, &out) &&
93 + (!*out || *(out++) == '=')) {
94 + if (parse_feature_request(out, feature))
95 + return 1;
96 + else
97 + break;
98 + }
99 + }
100 +
101 + if (die_on_error)
102 + die("server doesn't support feature '%s'", feature);
103 +
104 + return 0;
105 +}
106 +
107 static void process_capabilities_v2(struct packet_reader *reader)
108 {
109 while (packet_reader_read(reader) == PACKET_READ_NORMAL)
connect.h
+2
@@ -17,5 +17,7 @@ struct packet_reader;
17 extern enum protocol_version discover_version(struct packet_reader *reader);
18
19 extern int server_supports_v2(const char *c, int die_on_error);
20 +extern int server_supports_feature(const char *c, const char *feature,
21 + int die_on_error);
22
23 #endif
fetch-pack.c
+70 -1
@@ -1008,6 +1008,26 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
1008 return ref;
1009 }
1010
1011 +static void add_shallow_requests(struct strbuf *req_buf,
1012 + const struct fetch_pack_args *args)
1013 +{
1014 + if (is_repository_shallow())
1015 + write_shallow_commits(req_buf, 1, NULL);
1016 + if (args->depth > 0)
1017 + packet_buf_write(req_buf, "deepen %d", args->depth);
1018 + if (args->deepen_since) {
1019 + timestamp_t max_age = approxidate(args->deepen_since);
1020 + packet_buf_write(req_buf, "deepen-since %"PRItime, max_age);
1021 + }
1022 + if (args->deepen_not) {
1023 + int i;
1024 + for (i = 0; i < args->deepen_not->nr; i++) {
1025 + struct string_list_item *s = args->deepen_not->items + i;
1026 + packet_buf_write(req_buf, "deepen-not %s", s->string);
1027 + }
1028 + }
1029 +}
1030 +
1031 static void add_wants(const struct ref *wants, struct strbuf *req_buf)
1032 {
1033 for ( ; wants ; wants = wants->next) {
@@ -1093,6 +1113,12 @@ static int send_fetch_request(int fd_out, const struct fetch_pack_args *args,
1113 if (prefer_ofs_delta)
1114 packet_buf_write(&req_buf, "ofs-delta");
1115
1116 + /* Add shallow-info and deepen request */
1117 + if (server_supports_feature("fetch", "shallow", 0))
1118 + add_shallow_requests(&req_buf, args);
1119 + else if (is_repository_shallow() || args->deepen)
1120 + die(_("Server does not support shallow requests"));
1121 +
1122 /* add wants */
1123 add_wants(wants, &req_buf);
1124
@@ -1122,7 +1148,7 @@ static int process_section_header(struct packet_reader *reader,
1148 int ret;
1149
1150 if (packet_reader_peek(reader) != PACKET_READ_NORMAL)
1125 - die("error reading packet");
1151 + die("error reading section header '%s'", section);
1152
1153 ret = !strcmp(reader->line, section);
1154
@@ -1177,6 +1203,43 @@ static int process_acks(struct packet_reader *reader, struct oidset *common)
1203 return received_ready ? 2 : (received_ack ? 1 : 0);
1204 }
1205
1206 +static void receive_shallow_info(struct fetch_pack_args *args,
1207 + struct packet_reader *reader)
1208 +{
1209 + process_section_header(reader, "shallow-info", 0);
1210 + while (packet_reader_read(reader) == PACKET_READ_NORMAL) {
1211 + const char *arg;
1212 + struct object_id oid;
1213 +
1214 + if (skip_prefix(reader->line, "shallow ", &arg)) {
1215 + if (get_oid_hex(arg, &oid))
1216 + die(_("invalid shallow line: %s"), reader->line);
1217 + register_shallow(&oid);
1218 + continue;
1219 + }
1220 + if (skip_prefix(reader->line, "unshallow ", &arg)) {
1221 + if (get_oid_hex(arg, &oid))
1222 + die(_("invalid unshallow line: %s"), reader->line);
1223 + if (!lookup_object(oid.hash))
1224 + die(_("object not found: %s"), reader->line);
1225 + /* make sure that it is parsed as shallow */
1226 + if (!parse_object(&oid))
1227 + die(_("error in object: %s"), reader->line);
1228 + if (unregister_shallow(&oid))
1229 + die(_("no shallow found: %s"), reader->line);
1230 + continue;
1231 + }
1232 + die(_("expected shallow/unshallow, got %s"), reader->line);
1233 + }
1234 +
1235 + if (reader->status != PACKET_READ_FLUSH &&
1236 + reader->status != PACKET_READ_DELIM)
1237 + die("error processing shallow info: %d", reader->status);
1238 +
1239 + setup_alternate_shallow(&shallow_lock, &alternate_shallow_file, NULL);
1240 + args->deepen = 1;
1241 +}
1242 +
1243 enum fetch_state {
1244 FETCH_CHECK_LOCAL = 0,
1245 FETCH_SEND_REQUEST,
@@ -1209,6 +1272,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1272 /* v2 supports these by default */
1273 allow_unadvertised_object_request |= ALLOW_REACHABLE_SHA1;
1274 use_sideband = 2;
1275 + if (args->depth > 0 || args->deepen_since || args->deepen_not)
1276 + args->deepen = 1;
1277
1278 if (marked)
1279 for_each_ref(clear_marks, NULL);
@@ -1245,6 +1310,10 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1310 }
1311 break;
1312 case FETCH_GET_PACK:
1313 + /* Check for shallow-info section */
1314 + if (process_section_header(&reader, "shallow-info", 1))
1315 + receive_shallow_info(args, &reader);
1316 +
1317 /* get the pack */
1318 process_section_header(&reader, "packfile", 0);
1319 if (get_pack(args, fd, pack_lockfile))