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