bundle-uri: add support for http(s):// and file://

The previous change created the 'git clone --bundle-uri=<uri>' option. Currently, <uri> must be a filename. Update copy_uri_to_file() to first inspect the URI for an HTTP(S) prefix and use git-remote-https as the way to download the data at that URI. Otherwise, check to see if file:// is present and modify the prefix accordingly. Reviewed-by: Josh Steadmon <steadmon@google.com> Signed-off-by: Derrick Stolee <derrickstolee@github.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Aug 9, 2022 at 13:11 UTC 59c1752ab6768cb9c380f0a7c9d06af79d183f67
2 files changed +112 -3
bundle-uri.c
+67 -3
@@ -23,10 +23,74 @@ static int find_temp_filename(struct strbuf *name)
23 return 0;
24 }
25
26 -static int copy_uri_to_file(const char *file, const char *uri)
26 +static int download_https_uri_to_file(const char *file, const char *uri)
27 {
28 - /* File-based URIs only for now. */
29 - return copy_file(file, uri, 0);
28 + int result = 0;
29 + struct child_process cp = CHILD_PROCESS_INIT;
30 + FILE *child_in = NULL, *child_out = NULL;
31 + struct strbuf line = STRBUF_INIT;
32 + int found_get = 0;
33 +
34 + strvec_pushl(&cp.args, "git-remote-https", uri, NULL);
35 + cp.in = -1;
36 + cp.out = -1;
37 +
38 + if (start_command(&cp))
39 + return 1;
40 +
41 + child_in = fdopen(cp.in, "w");
42 + if (!child_in) {
43 + result = 1;
44 + goto cleanup;
45 + }
46 +
47 + child_out = fdopen(cp.out, "r");
48 + if (!child_out) {
49 + result = 1;
50 + goto cleanup;
51 + }
52 +
53 + fprintf(child_in, "capabilities\n");
54 + fflush(child_in);
55 +
56 + while (!strbuf_getline(&line, child_out)) {
57 + if (!line.len)
58 + break;
59 + if (!strcmp(line.buf, "get"))
60 + found_get = 1;
61 + }
62 + strbuf_release(&line);
63 +
64 + if (!found_get) {
65 + result = error(_("insufficient capabilities"));
66 + goto cleanup;
67 + }
68 +
69 + fprintf(child_in, "get %s %s\n\n", uri, file);
70 +
71 +cleanup:
72 + if (child_in)
73 + fclose(child_in);
74 + if (finish_command(&cp))
75 + return 1;
76 + if (child_out)
77 + fclose(child_out);
78 + return result;
79 +}
80 +
81 +static int copy_uri_to_file(const char *filename, const char *uri)
82 +{
83 + const char *out;
84 +
85 + if (starts_with(uri, "https:") ||
86 + starts_with(uri, "http:"))
87 + return download_https_uri_to_file(filename, uri);
88 +
89 + if (skip_prefix(uri, "file://", &out))
90 + uri = out;
91 +
92 + /* Copy as a file */
93 + return copy_file(filename, uri, 0);
94 }
95
96 static int unbundle_from_file(struct repository *r, const char *file)
t/t5558-clone-bundle-uri.sh
+45
@@ -33,4 +33,49 @@ test_expect_success 'clone with path bundle' '
33 test_cmp expect actual
34 '
35
36 +test_expect_success 'clone with file:// bundle' '
37 + git clone --bundle-uri="file://$(pwd)/clone-from/B.bundle" \
38 + clone-from clone-file &&
39 + git -C clone-file rev-parse refs/bundles/topic >actual &&
40 + git -C clone-from rev-parse topic >expect &&
41 + test_cmp expect actual
42 +'
43 +
44 +#########################################################################
45 +# HTTP tests begin here
46 +
47 +. "$TEST_DIRECTORY"/lib-httpd.sh
48 +start_httpd
49 +
50 +test_expect_success 'fail to fetch from non-existent HTTP URL' '
51 + test_when_finished rm -rf test &&
52 + git clone --bundle-uri="$HTTPD_URL/does-not-exist" . test 2>err &&
53 + grep "failed to download bundle from URI" err
54 +'
55 +
56 +test_expect_success 'fail to fetch from non-bundle HTTP URL' '
57 + test_when_finished rm -rf test &&
58 + echo bogus >"$HTTPD_DOCUMENT_ROOT_PATH/bogus" &&
59 + git clone --bundle-uri="$HTTPD_URL/bogus" . test 2>err &&
60 + grep "is not a bundle" err
61 +'
62 +
63 +test_expect_success 'clone HTTP bundle' '
64 + cp clone-from/B.bundle "$HTTPD_DOCUMENT_ROOT_PATH/B.bundle" &&
65 +
66 + git clone --no-local --mirror clone-from \
67 + "$HTTPD_DOCUMENT_ROOT_PATH/fetch.git" &&
68 +
69 + git clone --bundle-uri="$HTTPD_URL/B.bundle" \
70 + "$HTTPD_URL/smart/fetch.git" clone-http &&
71 + git -C clone-http rev-parse refs/bundles/topic >actual &&
72 + git -C clone-from rev-parse topic >expect &&
73 + test_cmp expect actual &&
74 +
75 + test_config -C clone-http log.excludedecoration refs/bundle/
76 +'
77 +
78 +# Do not add tests here unless they use the HTTP server, as they will
79 +# not run unless the HTTP dependencies exist.
80 +
81 test_done