Merge branch 'ab/remove-implicit-use-of-the-repository' into en/header-split-cache-h
[alt-git.git] / promisor-remote.c
bloba8dbb788e8f1a0a4cb3c77ba16fda20bb8b9f41a
1 #include "cache.h"
2 #include "gettext.h"
3 #include "hex.h"
4 #include "object-store.h"
5 #include "promisor-remote.h"
6 #include "config.h"
7 #include "transport.h"
8 #include "strvec.h"
9 #include "packfile.h"
11 struct promisor_remote_config {
12 struct promisor_remote *promisors;
13 struct promisor_remote **promisors_tail;
16 static int fetch_objects(struct repository *repo,
17 const char *remote_name,
18 const struct object_id *oids,
19 int oid_nr)
21 struct child_process child = CHILD_PROCESS_INIT;
22 int i;
23 FILE *child_in;
25 child.git_cmd = 1;
26 child.in = -1;
27 if (repo != the_repository)
28 prepare_other_repo_env(&child.env, repo->gitdir);
29 strvec_pushl(&child.args, "-c", "fetch.negotiationAlgorithm=noop",
30 "fetch", remote_name, "--no-tags",
31 "--no-write-fetch-head", "--recurse-submodules=no",
32 "--filter=blob:none", "--stdin", NULL);
33 if (start_command(&child))
34 die(_("promisor-remote: unable to fork off fetch subprocess"));
35 child_in = xfdopen(child.in, "w");
37 trace2_data_intmax("promisor", repo, "fetch_count", oid_nr);
39 for (i = 0; i < oid_nr; i++) {
40 if (fputs(oid_to_hex(&oids[i]), child_in) < 0)
41 die_errno(_("promisor-remote: could not write to fetch subprocess"));
42 if (fputc('\n', child_in) < 0)
43 die_errno(_("promisor-remote: could not write to fetch subprocess"));
46 if (fclose(child_in) < 0)
47 die_errno(_("promisor-remote: could not close stdin to fetch subprocess"));
48 return finish_command(&child) ? -1 : 0;
51 static struct promisor_remote *promisor_remote_new(struct promisor_remote_config *config,
52 const char *remote_name)
54 struct promisor_remote *r;
56 if (*remote_name == '/') {
57 warning(_("promisor remote name cannot begin with '/': %s"),
58 remote_name);
59 return NULL;
62 FLEX_ALLOC_STR(r, name, remote_name);
64 *config->promisors_tail = r;
65 config->promisors_tail = &r->next;
67 return r;
70 static struct promisor_remote *promisor_remote_lookup(struct promisor_remote_config *config,
71 const char *remote_name,
72 struct promisor_remote **previous)
74 struct promisor_remote *r, *p;
76 for (p = NULL, r = config->promisors; r; p = r, r = r->next)
77 if (!strcmp(r->name, remote_name)) {
78 if (previous)
79 *previous = p;
80 return r;
83 return NULL;
86 static void promisor_remote_move_to_tail(struct promisor_remote_config *config,
87 struct promisor_remote *r,
88 struct promisor_remote *previous)
90 if (!r->next)
91 return;
93 if (previous)
94 previous->next = r->next;
95 else
96 config->promisors = r->next ? r->next : r;
97 r->next = NULL;
98 *config->promisors_tail = r;
99 config->promisors_tail = &r->next;
102 static int promisor_remote_config(const char *var, const char *value, void *data)
104 struct promisor_remote_config *config = data;
105 const char *name;
106 size_t namelen;
107 const char *subkey;
109 if (parse_config_key(var, "remote", &name, &namelen, &subkey) < 0)
110 return 0;
112 if (!strcmp(subkey, "promisor")) {
113 char *remote_name;
115 if (!git_config_bool(var, value))
116 return 0;
118 remote_name = xmemdupz(name, namelen);
120 if (!promisor_remote_lookup(config, remote_name, NULL))
121 promisor_remote_new(config, remote_name);
123 free(remote_name);
124 return 0;
126 if (!strcmp(subkey, "partialclonefilter")) {
127 struct promisor_remote *r;
128 char *remote_name = xmemdupz(name, namelen);
130 r = promisor_remote_lookup(config, remote_name, NULL);
131 if (!r)
132 r = promisor_remote_new(config, remote_name);
134 free(remote_name);
136 if (!r)
137 return 0;
139 return git_config_string(&r->partial_clone_filter, var, value);
142 return 0;
145 static void promisor_remote_init(struct repository *r)
147 struct promisor_remote_config *config;
149 if (r->promisor_remote_config)
150 return;
151 config = r->promisor_remote_config =
152 xcalloc(1, sizeof(*r->promisor_remote_config));
153 config->promisors_tail = &config->promisors;
155 repo_config(r, promisor_remote_config, config);
157 if (r->repository_format_partial_clone) {
158 struct promisor_remote *o, *previous;
160 o = promisor_remote_lookup(config,
161 r->repository_format_partial_clone,
162 &previous);
163 if (o)
164 promisor_remote_move_to_tail(config, o, previous);
165 else
166 promisor_remote_new(config, r->repository_format_partial_clone);
170 void promisor_remote_clear(struct promisor_remote_config *config)
172 while (config->promisors) {
173 struct promisor_remote *r = config->promisors;
174 config->promisors = config->promisors->next;
175 free(r);
178 config->promisors_tail = &config->promisors;
181 void repo_promisor_remote_reinit(struct repository *r)
183 promisor_remote_clear(r->promisor_remote_config);
184 FREE_AND_NULL(r->promisor_remote_config);
185 promisor_remote_init(r);
188 struct promisor_remote *repo_promisor_remote_find(struct repository *r,
189 const char *remote_name)
191 promisor_remote_init(r);
193 if (!remote_name)
194 return r->promisor_remote_config->promisors;
196 return promisor_remote_lookup(r->promisor_remote_config, remote_name, NULL);
199 int repo_has_promisor_remote(struct repository *r)
201 return !!repo_promisor_remote_find(r, NULL);
204 static int remove_fetched_oids(struct repository *repo,
205 struct object_id **oids,
206 int oid_nr, int to_free)
208 int i, remaining_nr = 0;
209 int *remaining = xcalloc(oid_nr, sizeof(*remaining));
210 struct object_id *old_oids = *oids;
211 struct object_id *new_oids;
213 for (i = 0; i < oid_nr; i++)
214 if (oid_object_info_extended(repo, &old_oids[i], NULL,
215 OBJECT_INFO_SKIP_FETCH_OBJECT)) {
216 remaining[i] = 1;
217 remaining_nr++;
220 if (remaining_nr) {
221 int j = 0;
222 CALLOC_ARRAY(new_oids, remaining_nr);
223 for (i = 0; i < oid_nr; i++)
224 if (remaining[i])
225 oidcpy(&new_oids[j++], &old_oids[i]);
226 *oids = new_oids;
227 if (to_free)
228 free(old_oids);
231 free(remaining);
233 return remaining_nr;
236 void promisor_remote_get_direct(struct repository *repo,
237 const struct object_id *oids,
238 int oid_nr)
240 struct promisor_remote *r;
241 struct object_id *remaining_oids = (struct object_id *)oids;
242 int remaining_nr = oid_nr;
243 int to_free = 0;
244 int i;
246 if (oid_nr == 0)
247 return;
249 promisor_remote_init(repo);
251 for (r = repo->promisor_remote_config->promisors; r; r = r->next) {
252 if (fetch_objects(repo, r->name, remaining_oids, remaining_nr) < 0) {
253 if (remaining_nr == 1)
254 continue;
255 remaining_nr = remove_fetched_oids(repo, &remaining_oids,
256 remaining_nr, to_free);
257 if (remaining_nr) {
258 to_free = 1;
259 continue;
262 goto all_fetched;
265 for (i = 0; i < remaining_nr; i++) {
266 if (is_promisor_object(&remaining_oids[i]))
267 die(_("could not fetch %s from promisor remote"),
268 oid_to_hex(&remaining_oids[i]));
271 all_fetched:
272 if (to_free)
273 free(remaining_oids);