]>
Commit | Line | Data |
---|---|---|
5579f44d | 1 | #include "git-compat-util.h" |
f394e093 | 2 | #include "gettext.h" |
41771fa4 | 3 | #include "hex.h" |
a034e910 | 4 | #include "object-store-ll.h" |
48de3158 CC |
5 | #include "promisor-remote.h" |
6 | #include "config.h" | |
74ea5c95 | 7 | #include "trace2.h" |
db27dca5 | 8 | #include "transport.h" |
7ca3c0ac | 9 | #include "strvec.h" |
301f1e3a | 10 | #include "packfile.h" |
db27dca5 | 11 | |
ef7dc2e9 JT |
12 | struct promisor_remote_config { |
13 | struct promisor_remote *promisors; | |
14 | struct promisor_remote **promisors_tail; | |
15 | }; | |
60b7a92d | 16 | |
78cfdd0c EN |
17 | static int fetch_objects(struct repository *repo, |
18 | const char *remote_name, | |
db27dca5 CC |
19 | const struct object_id *oids, |
20 | int oid_nr) | |
21 | { | |
7ca3c0ac | 22 | struct child_process child = CHILD_PROCESS_INIT; |
db27dca5 | 23 | int i; |
7ca3c0ac JT |
24 | FILE *child_in; |
25 | ||
26 | child.git_cmd = 1; | |
27 | child.in = -1; | |
ef830cc4 | 28 | if (repo != the_repository) |
29fda24d | 29 | prepare_other_repo_env(&child.env, repo->gitdir); |
7ca3c0ac JT |
30 | strvec_pushl(&child.args, "-c", "fetch.negotiationAlgorithm=noop", |
31 | "fetch", remote_name, "--no-tags", | |
32 | "--no-write-fetch-head", "--recurse-submodules=no", | |
33 | "--filter=blob:none", "--stdin", NULL); | |
34 | if (start_command(&child)) | |
35 | die(_("promisor-remote: unable to fork off fetch subprocess")); | |
36 | child_in = xfdopen(child.in, "w"); | |
db27dca5 | 37 | |
78cfdd0c EN |
38 | trace2_data_intmax("promisor", repo, "fetch_count", oid_nr); |
39 | ||
db27dca5 | 40 | for (i = 0; i < oid_nr; i++) { |
7ca3c0ac JT |
41 | if (fputs(oid_to_hex(&oids[i]), child_in) < 0) |
42 | die_errno(_("promisor-remote: could not write to fetch subprocess")); | |
43 | if (fputc('\n', child_in) < 0) | |
44 | die_errno(_("promisor-remote: could not write to fetch subprocess")); | |
db27dca5 | 45 | } |
7ca3c0ac JT |
46 | |
47 | if (fclose(child_in) < 0) | |
48 | die_errno(_("promisor-remote: could not close stdin to fetch subprocess")); | |
49 | return finish_command(&child) ? -1 : 0; | |
db27dca5 | 50 | } |
48de3158 | 51 | |
ef7dc2e9 JT |
52 | static struct promisor_remote *promisor_remote_new(struct promisor_remote_config *config, |
53 | const char *remote_name) | |
48de3158 CC |
54 | { |
55 | struct promisor_remote *r; | |
56 | ||
57 | if (*remote_name == '/') { | |
58 | warning(_("promisor remote name cannot begin with '/': %s"), | |
59 | remote_name); | |
60 | return NULL; | |
61 | } | |
62 | ||
63 | FLEX_ALLOC_STR(r, name, remote_name); | |
64 | ||
ef7dc2e9 JT |
65 | *config->promisors_tail = r; |
66 | config->promisors_tail = &r->next; | |
48de3158 CC |
67 | |
68 | return r; | |
69 | } | |
70 | ||
ef7dc2e9 JT |
71 | static struct promisor_remote *promisor_remote_lookup(struct promisor_remote_config *config, |
72 | const char *remote_name, | |
48de3158 CC |
73 | struct promisor_remote **previous) |
74 | { | |
75 | struct promisor_remote *r, *p; | |
76 | ||
ef7dc2e9 | 77 | for (p = NULL, r = config->promisors; r; p = r, r = r->next) |
48de3158 CC |
78 | if (!strcmp(r->name, remote_name)) { |
79 | if (previous) | |
80 | *previous = p; | |
81 | return r; | |
82 | } | |
83 | ||
84 | return NULL; | |
85 | } | |
86 | ||
ef7dc2e9 JT |
87 | static void promisor_remote_move_to_tail(struct promisor_remote_config *config, |
88 | struct promisor_remote *r, | |
faf2abf4 CC |
89 | struct promisor_remote *previous) |
90 | { | |
afe8a907 | 91 | if (!r->next) |
65904b8b ES |
92 | return; |
93 | ||
faf2abf4 CC |
94 | if (previous) |
95 | previous->next = r->next; | |
96 | else | |
ef7dc2e9 | 97 | config->promisors = r->next ? r->next : r; |
faf2abf4 | 98 | r->next = NULL; |
ef7dc2e9 JT |
99 | *config->promisors_tail = r; |
100 | config->promisors_tail = &r->next; | |
faf2abf4 CC |
101 | } |
102 | ||
a4e7e317 GC |
103 | static int promisor_remote_config(const char *var, const char *value, |
104 | const struct config_context *ctx UNUSED, | |
105 | void *data) | |
48de3158 | 106 | { |
ef7dc2e9 | 107 | struct promisor_remote_config *config = data; |
48de3158 | 108 | const char *name; |
f5914f4b | 109 | size_t namelen; |
48de3158 CC |
110 | const char *subkey; |
111 | ||
112 | if (parse_config_key(var, "remote", &name, &namelen, &subkey) < 0) | |
113 | return 0; | |
114 | ||
115 | if (!strcmp(subkey, "promisor")) { | |
116 | char *remote_name; | |
117 | ||
118 | if (!git_config_bool(var, value)) | |
119 | return 0; | |
120 | ||
121 | remote_name = xmemdupz(name, namelen); | |
122 | ||
ef7dc2e9 JT |
123 | if (!promisor_remote_lookup(config, remote_name, NULL)) |
124 | promisor_remote_new(config, remote_name); | |
48de3158 CC |
125 | |
126 | free(remote_name); | |
127 | return 0; | |
128 | } | |
fa3d1b63 CC |
129 | if (!strcmp(subkey, "partialclonefilter")) { |
130 | struct promisor_remote *r; | |
131 | char *remote_name = xmemdupz(name, namelen); | |
132 | ||
ef7dc2e9 | 133 | r = promisor_remote_lookup(config, remote_name, NULL); |
fa3d1b63 | 134 | if (!r) |
ef7dc2e9 | 135 | r = promisor_remote_new(config, remote_name); |
fa3d1b63 CC |
136 | |
137 | free(remote_name); | |
138 | ||
139 | if (!r) | |
140 | return 0; | |
141 | ||
142 | return git_config_string(&r->partial_clone_filter, var, value); | |
143 | } | |
48de3158 CC |
144 | |
145 | return 0; | |
146 | } | |
147 | ||
ef7dc2e9 | 148 | static void promisor_remote_init(struct repository *r) |
48de3158 | 149 | { |
ef7dc2e9 JT |
150 | struct promisor_remote_config *config; |
151 | ||
152 | if (r->promisor_remote_config) | |
48de3158 | 153 | return; |
ef7dc2e9 | 154 | config = r->promisor_remote_config = |
c4bbd9bb | 155 | xcalloc(1, sizeof(*r->promisor_remote_config)); |
ef7dc2e9 | 156 | config->promisors_tail = &config->promisors; |
48de3158 | 157 | |
ef7dc2e9 | 158 | repo_config(r, promisor_remote_config, config); |
faf2abf4 | 159 | |
ef7dc2e9 | 160 | if (r->repository_format_partial_clone) { |
faf2abf4 CC |
161 | struct promisor_remote *o, *previous; |
162 | ||
ef7dc2e9 JT |
163 | o = promisor_remote_lookup(config, |
164 | r->repository_format_partial_clone, | |
faf2abf4 CC |
165 | &previous); |
166 | if (o) | |
ef7dc2e9 | 167 | promisor_remote_move_to_tail(config, o, previous); |
faf2abf4 | 168 | else |
ef7dc2e9 | 169 | promisor_remote_new(config, r->repository_format_partial_clone); |
faf2abf4 | 170 | } |
48de3158 CC |
171 | } |
172 | ||
ef7dc2e9 | 173 | void promisor_remote_clear(struct promisor_remote_config *config) |
9cfebc1f | 174 | { |
ef7dc2e9 JT |
175 | while (config->promisors) { |
176 | struct promisor_remote *r = config->promisors; | |
177 | config->promisors = config->promisors->next; | |
9cfebc1f CC |
178 | free(r); |
179 | } | |
180 | ||
ef7dc2e9 | 181 | config->promisors_tail = &config->promisors; |
9cfebc1f CC |
182 | } |
183 | ||
ef7dc2e9 | 184 | void repo_promisor_remote_reinit(struct repository *r) |
9cfebc1f | 185 | { |
ef7dc2e9 JT |
186 | promisor_remote_clear(r->promisor_remote_config); |
187 | FREE_AND_NULL(r->promisor_remote_config); | |
188 | promisor_remote_init(r); | |
9cfebc1f CC |
189 | } |
190 | ||
ef7dc2e9 JT |
191 | struct promisor_remote *repo_promisor_remote_find(struct repository *r, |
192 | const char *remote_name) | |
48de3158 | 193 | { |
ef7dc2e9 | 194 | promisor_remote_init(r); |
48de3158 CC |
195 | |
196 | if (!remote_name) | |
ef7dc2e9 | 197 | return r->promisor_remote_config->promisors; |
48de3158 | 198 | |
ef7dc2e9 | 199 | return promisor_remote_lookup(r->promisor_remote_config, remote_name, NULL); |
48de3158 CC |
200 | } |
201 | ||
ef7dc2e9 | 202 | int repo_has_promisor_remote(struct repository *r) |
48de3158 | 203 | { |
ef7dc2e9 | 204 | return !!repo_promisor_remote_find(r, NULL); |
48de3158 | 205 | } |
9e27beaa CC |
206 | |
207 | static int remove_fetched_oids(struct repository *repo, | |
208 | struct object_id **oids, | |
209 | int oid_nr, int to_free) | |
210 | { | |
211 | int i, remaining_nr = 0; | |
212 | int *remaining = xcalloc(oid_nr, sizeof(*remaining)); | |
213 | struct object_id *old_oids = *oids; | |
214 | struct object_id *new_oids; | |
215 | ||
216 | for (i = 0; i < oid_nr; i++) | |
217 | if (oid_object_info_extended(repo, &old_oids[i], NULL, | |
218 | OBJECT_INFO_SKIP_FETCH_OBJECT)) { | |
219 | remaining[i] = 1; | |
220 | remaining_nr++; | |
221 | } | |
222 | ||
223 | if (remaining_nr) { | |
224 | int j = 0; | |
ca56dadb | 225 | CALLOC_ARRAY(new_oids, remaining_nr); |
9e27beaa CC |
226 | for (i = 0; i < oid_nr; i++) |
227 | if (remaining[i]) | |
228 | oidcpy(&new_oids[j++], &old_oids[i]); | |
229 | *oids = new_oids; | |
230 | if (to_free) | |
231 | free(old_oids); | |
232 | } | |
233 | ||
234 | free(remaining); | |
235 | ||
236 | return remaining_nr; | |
237 | } | |
238 | ||
00057bf1 JT |
239 | void promisor_remote_get_direct(struct repository *repo, |
240 | const struct object_id *oids, | |
241 | int oid_nr) | |
9e27beaa CC |
242 | { |
243 | struct promisor_remote *r; | |
244 | struct object_id *remaining_oids = (struct object_id *)oids; | |
245 | int remaining_nr = oid_nr; | |
246 | int to_free = 0; | |
301f1e3a | 247 | int i; |
9e27beaa | 248 | |
db7ed741 | 249 | if (oid_nr == 0) |
00057bf1 | 250 | return; |
db7ed741 | 251 | |
ef7dc2e9 | 252 | promisor_remote_init(repo); |
9e27beaa | 253 | |
ef7dc2e9 | 254 | for (r = repo->promisor_remote_config->promisors; r; r = r->next) { |
78cfdd0c | 255 | if (fetch_objects(repo, r->name, remaining_oids, remaining_nr) < 0) { |
9e27beaa CC |
256 | if (remaining_nr == 1) |
257 | continue; | |
258 | remaining_nr = remove_fetched_oids(repo, &remaining_oids, | |
259 | remaining_nr, to_free); | |
260 | if (remaining_nr) { | |
261 | to_free = 1; | |
262 | continue; | |
263 | } | |
264 | } | |
301f1e3a JT |
265 | goto all_fetched; |
266 | } | |
267 | ||
268 | for (i = 0; i < remaining_nr; i++) { | |
269 | if (is_promisor_object(&remaining_oids[i])) | |
270 | die(_("could not fetch %s from promisor remote"), | |
271 | oid_to_hex(&remaining_oids[i])); | |
9e27beaa CC |
272 | } |
273 | ||
301f1e3a | 274 | all_fetched: |
9e27beaa CC |
275 | if (to_free) |
276 | free(remaining_oids); | |
9e27beaa | 277 | } |