doc: use 'object database' not ODB or abbreviation
[alt-git.git] / bundle-uri.c
blob4a8cc74ed0531eaf3fcfb0023d198cea4aa2188d
1 #include "cache.h"
2 #include "bundle-uri.h"
3 #include "bundle.h"
4 #include "object-store.h"
5 #include "refs.h"
6 #include "run-command.h"
8 static int find_temp_filename(struct strbuf *name)
10 int fd;
12 * Find a temporary filename that is available. This is briefly
13 * racy, but unlikely to collide.
15 fd = odb_mkstemp(name, "bundles/tmp_uri_XXXXXX");
16 if (fd < 0) {
17 warning(_("failed to create temporary file"));
18 return -1;
21 close(fd);
22 unlink(name->buf);
23 return 0;
26 static int download_https_uri_to_file(const char *file, const char *uri)
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;
34 strvec_pushl(&cp.args, "git-remote-https", uri, NULL);
35 cp.in = -1;
36 cp.out = -1;
38 if (start_command(&cp))
39 return 1;
41 child_in = fdopen(cp.in, "w");
42 if (!child_in) {
43 result = 1;
44 goto cleanup;
47 child_out = fdopen(cp.out, "r");
48 if (!child_out) {
49 result = 1;
50 goto cleanup;
53 fprintf(child_in, "capabilities\n");
54 fflush(child_in);
56 while (!strbuf_getline(&line, child_out)) {
57 if (!line.len)
58 break;
59 if (!strcmp(line.buf, "get"))
60 found_get = 1;
62 strbuf_release(&line);
64 if (!found_get) {
65 result = error(_("insufficient capabilities"));
66 goto cleanup;
69 fprintf(child_in, "get %s %s\n\n", uri, file);
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;
81 static int copy_uri_to_file(const char *filename, const char *uri)
83 const char *out;
85 if (starts_with(uri, "https:") ||
86 starts_with(uri, "http:"))
87 return download_https_uri_to_file(filename, uri);
89 if (skip_prefix(uri, "file://", &out))
90 uri = out;
92 /* Copy as a file */
93 return copy_file(filename, uri, 0);
96 static int unbundle_from_file(struct repository *r, const char *file)
98 int result = 0;
99 int bundle_fd;
100 struct bundle_header header = BUNDLE_HEADER_INIT;
101 struct string_list_item *refname;
102 struct strbuf bundle_ref = STRBUF_INIT;
103 size_t bundle_prefix_len;
105 if ((bundle_fd = read_bundle_header(file, &header)) < 0)
106 return 1;
108 if ((result = unbundle(r, &header, bundle_fd, NULL)))
109 return 1;
112 * Convert all refs/heads/ from the bundle into refs/bundles/
113 * in the local repository.
115 strbuf_addstr(&bundle_ref, "refs/bundles/");
116 bundle_prefix_len = bundle_ref.len;
118 for_each_string_list_item(refname, &header.references) {
119 struct object_id *oid = refname->util;
120 struct object_id old_oid;
121 const char *branch_name;
122 int has_old;
124 if (!skip_prefix(refname->string, "refs/heads/", &branch_name))
125 continue;
127 strbuf_setlen(&bundle_ref, bundle_prefix_len);
128 strbuf_addstr(&bundle_ref, branch_name);
130 has_old = !read_ref(bundle_ref.buf, &old_oid);
131 update_ref("fetched bundle", bundle_ref.buf, oid,
132 has_old ? &old_oid : NULL,
133 REF_SKIP_OID_VERIFICATION,
134 UPDATE_REFS_MSG_ON_ERR);
137 bundle_header_release(&header);
138 return result;
141 int fetch_bundle_uri(struct repository *r, const char *uri)
143 int result = 0;
144 struct strbuf filename = STRBUF_INIT;
146 if ((result = find_temp_filename(&filename)))
147 goto cleanup;
149 if ((result = copy_uri_to_file(filename.buf, uri))) {
150 warning(_("failed to download bundle from URI '%s'"), uri);
151 goto cleanup;
154 if ((result = !is_bundle(filename.buf, 0))) {
155 warning(_("file at URI '%s' is not a bundle"), uri);
156 goto cleanup;
159 if ((result = unbundle_from_file(r, filename.buf))) {
160 warning(_("failed to unbundle bundle from URI '%s'"), uri);
161 goto cleanup;
164 cleanup:
165 unlink(filename.buf);
166 strbuf_release(&filename);
167 return result;