1 #define USE_THE_REPOSITORY_VARIABLE
3 #include "git-compat-util.h"
7 #include "promisor-remote.h"
10 #include "transport.h"
13 #include "environment.h"
17 struct promisor_remote_config
{
18 struct promisor_remote
*promisors
;
19 struct promisor_remote
**promisors_tail
;
22 static int fetch_objects(struct repository
*repo
,
23 const char *remote_name
,
24 const struct object_id
*oids
,
27 struct child_process child
= CHILD_PROCESS_INIT
;
32 if (git_env_bool(NO_LAZY_FETCH_ENVIRONMENT
, 0)) {
33 static int warning_shown
;
36 warning(_("lazy fetching disabled; some objects may not be available"));
43 if (repo
!= the_repository
)
44 prepare_other_repo_env(&child
.env
, repo
->gitdir
);
45 strvec_pushl(&child
.args
, "-c", "fetch.negotiationAlgorithm=noop",
46 "fetch", remote_name
, "--no-tags",
47 "--no-write-fetch-head", "--recurse-submodules=no",
48 "--filter=blob:none", "--stdin", NULL
);
49 if (!git_config_get_bool("promisor.quiet", &quiet
) && quiet
)
50 strvec_push(&child
.args
, "--quiet");
51 if (start_command(&child
))
52 die(_("promisor-remote: unable to fork off fetch subprocess"));
53 child_in
= xfdopen(child
.in
, "w");
55 trace2_data_intmax("promisor", repo
, "fetch_count", oid_nr
);
57 for (i
= 0; i
< oid_nr
; i
++) {
58 if (fputs(oid_to_hex(&oids
[i
]), child_in
) < 0)
59 die_errno(_("promisor-remote: could not write to fetch subprocess"));
60 if (fputc('\n', child_in
) < 0)
61 die_errno(_("promisor-remote: could not write to fetch subprocess"));
64 if (fclose(child_in
) < 0)
65 die_errno(_("promisor-remote: could not close stdin to fetch subprocess"));
66 return finish_command(&child
) ? -1 : 0;
69 static struct promisor_remote
*promisor_remote_new(struct promisor_remote_config
*config
,
70 const char *remote_name
)
72 struct promisor_remote
*r
;
74 if (*remote_name
== '/') {
75 warning(_("promisor remote name cannot begin with '/': %s"),
80 FLEX_ALLOC_STR(r
, name
, remote_name
);
82 *config
->promisors_tail
= r
;
83 config
->promisors_tail
= &r
->next
;
88 static struct promisor_remote
*promisor_remote_lookup(struct promisor_remote_config
*config
,
89 const char *remote_name
,
90 struct promisor_remote
**previous
)
92 struct promisor_remote
*r
, *p
;
94 for (p
= NULL
, r
= config
->promisors
; r
; p
= r
, r
= r
->next
)
95 if (!strcmp(r
->name
, remote_name
)) {
104 static void promisor_remote_move_to_tail(struct promisor_remote_config
*config
,
105 struct promisor_remote
*r
,
106 struct promisor_remote
*previous
)
112 previous
->next
= r
->next
;
114 config
->promisors
= r
->next
? r
->next
: r
;
116 *config
->promisors_tail
= r
;
117 config
->promisors_tail
= &r
->next
;
120 static int promisor_remote_config(const char *var
, const char *value
,
121 const struct config_context
*ctx UNUSED
,
124 struct promisor_remote_config
*config
= data
;
129 if (parse_config_key(var
, "remote", &name
, &namelen
, &subkey
) < 0)
132 if (!strcmp(subkey
, "promisor")) {
135 if (!git_config_bool(var
, value
))
138 remote_name
= xmemdupz(name
, namelen
);
140 if (!promisor_remote_lookup(config
, remote_name
, NULL
))
141 promisor_remote_new(config
, remote_name
);
146 if (!strcmp(subkey
, "partialclonefilter")) {
147 struct promisor_remote
*r
;
148 char *remote_name
= xmemdupz(name
, namelen
);
150 r
= promisor_remote_lookup(config
, remote_name
, NULL
);
152 r
= promisor_remote_new(config
, remote_name
);
159 FREE_AND_NULL(r
->partial_clone_filter
);
160 return git_config_string(&r
->partial_clone_filter
, var
, value
);
166 static void promisor_remote_init(struct repository
*r
)
168 struct promisor_remote_config
*config
;
170 if (r
->promisor_remote_config
)
172 config
= r
->promisor_remote_config
=
173 xcalloc(1, sizeof(*r
->promisor_remote_config
));
174 config
->promisors_tail
= &config
->promisors
;
176 repo_config(r
, promisor_remote_config
, config
);
178 if (r
->repository_format_partial_clone
) {
179 struct promisor_remote
*o
, *previous
;
181 o
= promisor_remote_lookup(config
,
182 r
->repository_format_partial_clone
,
185 promisor_remote_move_to_tail(config
, o
, previous
);
187 promisor_remote_new(config
, r
->repository_format_partial_clone
);
191 void promisor_remote_clear(struct promisor_remote_config
*config
)
193 while (config
->promisors
) {
194 struct promisor_remote
*r
= config
->promisors
;
195 free(r
->partial_clone_filter
);
196 config
->promisors
= config
->promisors
->next
;
200 config
->promisors_tail
= &config
->promisors
;
203 void repo_promisor_remote_reinit(struct repository
*r
)
205 promisor_remote_clear(r
->promisor_remote_config
);
206 FREE_AND_NULL(r
->promisor_remote_config
);
207 promisor_remote_init(r
);
210 struct promisor_remote
*repo_promisor_remote_find(struct repository
*r
,
211 const char *remote_name
)
213 promisor_remote_init(r
);
216 return r
->promisor_remote_config
->promisors
;
218 return promisor_remote_lookup(r
->promisor_remote_config
, remote_name
, NULL
);
221 int repo_has_promisor_remote(struct repository
*r
)
223 return !!repo_promisor_remote_find(r
, NULL
);
226 int repo_has_accepted_promisor_remote(struct repository
*r
)
228 struct promisor_remote
*p
;
230 promisor_remote_init(r
);
232 for (p
= r
->promisor_remote_config
->promisors
; p
; p
= p
->next
)
238 static int remove_fetched_oids(struct repository
*repo
,
239 struct object_id
**oids
,
240 int oid_nr
, int to_free
)
242 int i
, remaining_nr
= 0;
243 int *remaining
= xcalloc(oid_nr
, sizeof(*remaining
));
244 struct object_id
*old_oids
= *oids
;
245 struct object_id
*new_oids
;
247 for (i
= 0; i
< oid_nr
; i
++)
248 if (odb_read_object_info_extended(repo
->objects
, &old_oids
[i
], NULL
,
249 OBJECT_INFO_SKIP_FETCH_OBJECT
)) {
256 CALLOC_ARRAY(new_oids
, remaining_nr
);
257 for (i
= 0; i
< oid_nr
; i
++)
259 oidcpy(&new_oids
[j
++], &old_oids
[i
]);
270 void promisor_remote_get_direct(struct repository
*repo
,
271 const struct object_id
*oids
,
274 struct promisor_remote
*r
;
275 struct object_id
*remaining_oids
= (struct object_id
*)oids
;
276 int remaining_nr
= oid_nr
;
283 promisor_remote_init(repo
);
285 for (r
= repo
->promisor_remote_config
->promisors
; r
; r
= r
->next
) {
286 if (fetch_objects(repo
, r
->name
, remaining_oids
, remaining_nr
) < 0) {
287 if (remaining_nr
== 1)
289 remaining_nr
= remove_fetched_oids(repo
, &remaining_oids
,
290 remaining_nr
, to_free
);
299 for (i
= 0; i
< remaining_nr
; i
++) {
300 if (is_promisor_object(repo
, &remaining_oids
[i
]))
301 die(_("could not fetch %s from promisor remote"),
302 oid_to_hex(&remaining_oids
[i
]));
307 free(remaining_oids
);
310 static int allow_unsanitized(char ch
)
312 if (ch
== ',' || ch
== ';' || ch
== '%')
314 return ch
> 32 && ch
< 127;
317 static void promisor_info_vecs(struct repository
*repo
,
318 struct strvec
*names
,
321 struct promisor_remote
*r
;
323 promisor_remote_init(repo
);
325 for (r
= repo
->promisor_remote_config
->promisors
; r
; r
= r
->next
) {
327 char *url_key
= xstrfmt("remote.%s.url", r
->name
);
329 /* Only add remotes with a non empty URL */
330 if (!git_config_get_string_tmp(url_key
, &url
) && *url
) {
331 strvec_push(names
, r
->name
);
332 strvec_push(urls
, url
);
339 char *promisor_remote_info(struct repository
*repo
)
341 struct strbuf sb
= STRBUF_INIT
;
342 int advertise_promisors
= 0;
343 struct strvec names
= STRVEC_INIT
;
344 struct strvec urls
= STRVEC_INIT
;
346 git_config_get_bool("promisor.advertise", &advertise_promisors
);
348 if (!advertise_promisors
)
351 promisor_info_vecs(repo
, &names
, &urls
);
356 for (size_t i
= 0; i
< names
.nr
; i
++) {
358 strbuf_addch(&sb
, ';');
359 strbuf_addstr(&sb
, "name=");
360 strbuf_addstr_urlencode(&sb
, names
.v
[i
], allow_unsanitized
);
361 strbuf_addstr(&sb
, ",url=");
362 strbuf_addstr_urlencode(&sb
, urls
.v
[i
], allow_unsanitized
);
365 strvec_clear(&names
);
368 return strbuf_detach(&sb
, NULL
);
372 * Find first index of 'nicks' where there is 'nick'. 'nick' is
373 * compared case sensitively to the strings in 'nicks'. If not found
374 * 'nicks->nr' is returned.
376 static size_t remote_nick_find(struct strvec
*nicks
, const char *nick
)
378 for (size_t i
= 0; i
< nicks
->nr
; i
++)
379 if (!strcmp(nicks
->v
[i
], nick
))
384 enum accept_promisor
{
391 static int should_accept_remote(enum accept_promisor accept
,
392 const char *remote_name
, const char *remote_url
,
393 struct strvec
*names
, struct strvec
*urls
)
397 if (accept
== ACCEPT_ALL
)
400 i
= remote_nick_find(names
, remote_name
);
403 /* We don't know about that remote */
406 if (accept
== ACCEPT_KNOWN_NAME
)
409 if (accept
!= ACCEPT_KNOWN_URL
)
410 BUG("Unhandled 'enum accept_promisor' value '%d'", accept
);
412 if (!remote_url
|| !*remote_url
) {
413 warning(_("no or empty URL advertised for remote '%s'"), remote_name
);
417 if (!strcmp(urls
->v
[i
], remote_url
))
420 warning(_("known remote named '%s' but with URL '%s' instead of '%s'"),
421 remote_name
, urls
->v
[i
], remote_url
);
426 static void filter_promisor_remote(struct repository
*repo
,
427 struct strvec
*accepted
,
430 struct strbuf
**remotes
;
431 const char *accept_str
;
432 enum accept_promisor accept
= ACCEPT_NONE
;
433 struct strvec names
= STRVEC_INIT
;
434 struct strvec urls
= STRVEC_INIT
;
436 if (!git_config_get_string_tmp("promisor.acceptfromserver", &accept_str
)) {
437 if (!*accept_str
|| !strcasecmp("None", accept_str
))
438 accept
= ACCEPT_NONE
;
439 else if (!strcasecmp("KnownUrl", accept_str
))
440 accept
= ACCEPT_KNOWN_URL
;
441 else if (!strcasecmp("KnownName", accept_str
))
442 accept
= ACCEPT_KNOWN_NAME
;
443 else if (!strcasecmp("All", accept_str
))
446 warning(_("unknown '%s' value for '%s' config option"),
447 accept_str
, "promisor.acceptfromserver");
450 if (accept
== ACCEPT_NONE
)
453 if (accept
!= ACCEPT_ALL
)
454 promisor_info_vecs(repo
, &names
, &urls
);
456 /* Parse remote info received */
458 remotes
= strbuf_split_str(info
, ';', 0);
460 for (size_t i
= 0; remotes
[i
]; i
++) {
461 struct strbuf
**elems
;
462 const char *remote_name
= NULL
;
463 const char *remote_url
= NULL
;
464 char *decoded_name
= NULL
;
465 char *decoded_url
= NULL
;
467 strbuf_strip_suffix(remotes
[i
], ";");
468 elems
= strbuf_split(remotes
[i
], ',');
470 for (size_t j
= 0; elems
[j
]; j
++) {
472 strbuf_strip_suffix(elems
[j
], ",");
473 res
= skip_prefix(elems
[j
]->buf
, "name=", &remote_name
) ||
474 skip_prefix(elems
[j
]->buf
, "url=", &remote_url
);
476 warning(_("unknown element '%s' from remote info"),
481 decoded_name
= url_percent_decode(remote_name
);
483 decoded_url
= url_percent_decode(remote_url
);
485 if (decoded_name
&& should_accept_remote(accept
, decoded_name
, decoded_url
, &names
, &urls
))
486 strvec_push(accepted
, decoded_name
);
488 strbuf_list_free(elems
);
493 strvec_clear(&names
);
495 strbuf_list_free(remotes
);
498 char *promisor_remote_reply(const char *info
)
500 struct strvec accepted
= STRVEC_INIT
;
501 struct strbuf reply
= STRBUF_INIT
;
503 filter_promisor_remote(the_repository
, &accepted
, info
);
508 for (size_t i
= 0; i
< accepted
.nr
; i
++) {
510 strbuf_addch(&reply
, ';');
511 strbuf_addstr_urlencode(&reply
, accepted
.v
[i
], allow_unsanitized
);
514 strvec_clear(&accepted
);
516 return strbuf_detach(&reply
, NULL
);
519 void mark_promisor_remotes_as_accepted(struct repository
*r
, const char *remotes
)
521 struct strbuf
**accepted_remotes
= strbuf_split_str(remotes
, ';', 0);
523 for (size_t i
= 0; accepted_remotes
[i
]; i
++) {
524 struct promisor_remote
*p
;
525 char *decoded_remote
;
527 strbuf_strip_suffix(accepted_remotes
[i
], ";");
528 decoded_remote
= url_percent_decode(accepted_remotes
[i
]->buf
);
530 p
= repo_promisor_remote_find(r
, decoded_remote
);
534 warning(_("accepted promisor remote '%s' not found"),
537 free(decoded_remote
);
540 strbuf_list_free(accepted_remotes
);