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