promisor-remote: refactor how we parse advertised fields

In a follow up commit we are going to parse more fields, like a filter and a token, coming from the server when it advertises promisor remotes using the "promisor-remote" capability. To prepare for this, let's refactor the code that parses the advertised fields coming from the server into a new parse_one_advertised_remote() function that will populate a `struct promisor_info` with the content of the fields it parsed. While at it, let's also pass this `struct promisor_info` to the should_accept_remote() function, instead of passing it the parsed name and url. These changes will make it simpler to both parse more fields and access the content of these parsed fields in follow up commits. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Christian Couder committed Sep 8, 2025 at 07:30 UTC de1efeaf0cee5ca8947ead8b83235e84652c657f
1 file changed +57 -29
promisor-remote.c
+57 -29
@@ -405,16 +405,20 @@ struct promisor_info {
405 const char *token;
406 };
407
408 +static void promisor_info_free(struct promisor_info *p)
409 +{
410 + free((char *)p->name);
411 + free((char *)p->url);
412 + free((char *)p->filter);
413 + free((char *)p->token);
414 + free(p);
415 +}
416 +
417 static void promisor_info_list_clear(struct string_list *list)
418 {
410 - for (size_t i = 0; i < list->nr; i++) {
411 - struct promisor_info *p = list->items[i].util;
412 - free((char *)p->name);
413 - free((char *)p->url);
414 - free((char *)p->filter);
415 - free((char *)p->token);
416 - }
417 - string_list_clear(list, 1);
419 + for (size_t i = 0; i < list->nr; i++)
420 + promisor_info_free(list->items[i].util);
421 + string_list_clear(list, 0);
422 }
423
424 static void set_one_field(struct promisor_info *p,
@@ -531,11 +535,13 @@ enum accept_promisor {
535 };
536
537 static int should_accept_remote(enum accept_promisor accept,
534 - const char *remote_name, const char *remote_url,
538 + struct promisor_info *advertised,
539 struct string_list *config_info)
540 {
541 struct promisor_info *p;
542 struct string_list_item *item;
543 + const char *remote_name = advertised->name;
544 + const char *remote_url = advertised->url;
545
546 if (accept == ACCEPT_ALL)
547 return 1;
@@ -578,6 +584,41 @@ static int skip_field_name_prefix(const char *elem, const char *field_name, cons
584 return 1;
585 }
586
587 +static struct promisor_info *parse_one_advertised_remote(const char *remote_info)
588 +{
589 + struct promisor_info *info = xcalloc(1, sizeof(*info));
590 + struct string_list elem_list = STRING_LIST_INIT_DUP;
591 + struct string_list_item *item;
592 +
593 + string_list_split(&elem_list, remote_info, ",", -1);
594 +
595 + for_each_string_list_item(item, &elem_list) {
596 + const char *elem = item->string;
597 + const char *p = strchr(elem, '=');
598 +
599 + if (!p) {
600 + warning(_("invalid element '%s' from remote info"), elem);
601 + continue;
602 + }
603 +
604 + if (skip_field_name_prefix(elem, promisor_field_name, &p))
605 + info->name = url_percent_decode(p);
606 + else if (skip_field_name_prefix(elem, promisor_field_url, &p))
607 + info->url = url_percent_decode(p);
608 + }
609 +
610 + string_list_clear(&elem_list, 0);
611 +
612 + if (!info->name || !info->url) {
613 + warning(_("server advertised a promisor remote without a name or URL: %s"),
614 + remote_info);
615 + promisor_info_free(info);
616 + return NULL;
617 + }
618 +
619 + return info;
620 +}
621 +
622 static void filter_promisor_remote(struct repository *repo,
623 struct strvec *accepted,
624 const char *info)
@@ -614,32 +655,19 @@ static void filter_promisor_remote(struct repository *repo,
655 remotes = strbuf_split_str(info, ';', 0);
656
657 for (size_t i = 0; remotes[i]; i++) {
617 - struct strbuf **elems;
618 - const char *remote_name = NULL;
619 - const char *remote_url = NULL;
620 - char *decoded_name = NULL;
621 - char *decoded_url = NULL;
658 + struct promisor_info *advertised;
659
660 strbuf_strip_suffix(remotes[i], ";");
624 - elems = strbuf_split(remotes[i], ',');
661
626 - for (size_t j = 0; elems[j]; j++) {
627 - strbuf_strip_suffix(elems[j], ",");
628 - if (!skip_field_name_prefix(elems[j]->buf, promisor_field_name, &remote_name))
629 - skip_field_name_prefix(elems[j]->buf, promisor_field_url, &remote_url);
630 - }
662 + advertised = parse_one_advertised_remote(remotes[i]->buf);
663
632 - if (remote_name)
633 - decoded_name = url_percent_decode(remote_name);
634 - if (remote_url)
635 - decoded_url = url_percent_decode(remote_url);
664 + if (!advertised)
665 + continue;
666
637 - if (decoded_name && should_accept_remote(accept, decoded_name, decoded_url, &config_info))
638 - strvec_push(accepted, decoded_name);
667 + if (should_accept_remote(accept, advertised, &config_info))
668 + strvec_push(accepted, advertised->name);
669
640 - strbuf_list_free(elems);
641 - free(decoded_name);
642 - free(decoded_url);
670 + promisor_info_free(advertised);
671 }
672
673 promisor_info_list_clear(&config_info);