@@ -268,11 +268,35 @@ static int remove_fetched_oids(struct repository *repo,
268268 return remaining_nr ;
269269}
270270
271+ static int try_promisor_remotes (struct repository * repo ,
272+ struct object_id * * remaining_oids ,
273+ int * remaining_nr , int * to_free ,
274+ bool accepted_only )
275+ {
276+ struct promisor_remote * r = repo -> promisor_remote_config -> promisors ;
277+
278+ for (; r ; r = r -> next ) {
279+ if (accepted_only != r -> accepted )
280+ continue ;
281+ if (fetch_objects (repo , r -> name , * remaining_oids , * remaining_nr ) < 0 ) {
282+ if (* remaining_nr == 1 )
283+ continue ;
284+ * remaining_nr = remove_fetched_oids (repo , remaining_oids ,
285+ * remaining_nr , * to_free );
286+ if (* remaining_nr ) {
287+ * to_free = 1 ;
288+ continue ;
289+ }
290+ }
291+ return 1 ; /* all fetched */
292+ }
293+ return 0 ;
294+ }
295+
271296void promisor_remote_get_direct (struct repository * repo ,
272297 const struct object_id * oids ,
273298 int oid_nr )
274299{
275- struct promisor_remote * r ;
276300 struct object_id * remaining_oids = (struct object_id * )oids ;
277301 int remaining_nr = oid_nr ;
278302 int to_free = 0 ;
@@ -283,19 +307,13 @@ void promisor_remote_get_direct(struct repository *repo,
283307
284308 promisor_remote_init (repo );
285309
286- for (r = repo -> promisor_remote_config -> promisors ; r ; r = r -> next ) {
287- if (fetch_objects (repo , r -> name , remaining_oids , remaining_nr ) < 0 ) {
288- if (remaining_nr == 1 )
289- continue ;
290- remaining_nr = remove_fetched_oids (repo , & remaining_oids ,
291- remaining_nr , to_free );
292- if (remaining_nr ) {
293- to_free = 1 ;
294- continue ;
295- }
296- }
310+ /* Try accepted remotes first (those the server told us to use) */
311+ if (try_promisor_remotes (repo , & remaining_oids , & remaining_nr ,
312+ & to_free , true))
313+ goto all_fetched ;
314+ if (try_promisor_remotes (repo , & remaining_oids , & remaining_nr ,
315+ & to_free , false))
297316 goto all_fetched ;
298- }
299317
300318 for (i = 0 ; i < remaining_nr ; i ++ ) {
301319 if (is_promisor_object (repo , & remaining_oids [i ]))
@@ -557,6 +575,12 @@ enum accept_promisor {
557575 ACCEPT_ALL
558576};
559577
578+ /*
579+ * Check if a specific field and its advertised value match the local
580+ * configuration of a given promisor remote.
581+ *
582+ * Returns 1 if they match, 0 otherwise.
583+ */
560584static int match_field_against_config (const char * field , const char * value ,
561585 struct promisor_info * config_info )
562586{
@@ -568,9 +592,18 @@ static int match_field_against_config(const char *field, const char *value,
568592 return 0 ;
569593}
570594
595+ /*
596+ * Check that the advertised fields match the local configuration.
597+ *
598+ * When 'config_entry' is NULL (ACCEPT_ALL mode), every checked field
599+ * must match at least one remote in 'config_info'.
600+ *
601+ * When 'config_entry' points to a specific remote's config, the
602+ * checked fields are compared against that single remote only.
603+ */
571604static int all_fields_match (struct promisor_info * advertised ,
572605 struct string_list * config_info ,
573- int in_list )
606+ struct promisor_info * config_entry )
574607{
575608 struct string_list * fields = fields_checked ();
576609 struct string_list_item * item_checked ;
@@ -579,7 +612,6 @@ static int all_fields_match(struct promisor_info *advertised,
579612 int match = 0 ;
580613 const char * field = item_checked -> string ;
581614 const char * value = NULL ;
582- struct string_list_item * item ;
583615
584616 if (!strcasecmp (field , promisor_field_filter ))
585617 value = advertised -> filter ;
@@ -589,20 +621,18 @@ static int all_fields_match(struct promisor_info *advertised,
589621 if (!value )
590622 return 0 ;
591623
592- if (in_list ) {
624+ if (config_entry ) {
625+ match = match_field_against_config (field , value ,
626+ config_entry );
627+ } else {
628+ struct string_list_item * item ;
593629 for_each_string_list_item (item , config_info ) {
594630 struct promisor_info * p = item -> util ;
595631 if (match_field_against_config (field , value , p )) {
596632 match = 1 ;
597633 break ;
598634 }
599635 }
600- } else {
601- item = string_list_lookup (config_info , advertised -> name );
602- if (item ) {
603- struct promisor_info * p = item -> util ;
604- match = match_field_against_config (field , value , p );
605- }
606636 }
607637
608638 if (!match )
@@ -612,6 +642,14 @@ static int all_fields_match(struct promisor_info *advertised,
612642 return 1 ;
613643}
614644
645+ static bool has_control_char (const char * s )
646+ {
647+ for (const char * c = s ; * c ; c ++ )
648+ if (iscntrl (* c ))
649+ return true;
650+ return false;
651+ }
652+
615653static int should_accept_remote (enum accept_promisor accept ,
616654 struct promisor_info * advertised ,
617655 struct string_list * config_info )
@@ -621,8 +659,13 @@ static int should_accept_remote(enum accept_promisor accept,
621659 const char * remote_name = advertised -> name ;
622660 const char * remote_url = advertised -> url ;
623661
662+ if (!remote_url || !* remote_url )
663+ BUG ("no or empty URL advertised for remote '%s'; "
664+ "this remote should have been rejected earlier" ,
665+ remote_name );
666+
624667 if (accept == ACCEPT_ALL )
625- return all_fields_match (advertised , config_info , 1 );
668+ return all_fields_match (advertised , config_info , NULL );
626669
627670 /* Get config info for that promisor remote */
628671 item = string_list_lookup (config_info , remote_name );
@@ -634,23 +677,19 @@ static int should_accept_remote(enum accept_promisor accept,
634677 p = item -> util ;
635678
636679 if (accept == ACCEPT_KNOWN_NAME )
637- return all_fields_match (advertised , config_info , 0 );
680+ return all_fields_match (advertised , config_info , p );
638681
639682 if (accept != ACCEPT_KNOWN_URL )
640683 BUG ("Unhandled 'enum accept_promisor' value '%d'" , accept );
641684
642- if (!remote_url || !* remote_url ) {
643- warning (_ ("no or empty URL advertised for remote '%s'" ), remote_name );
685+ if (strcmp (p -> url , remote_url )) {
686+ warning (_ ("known remote named '%s' but with URL '%s' instead of '%s', "
687+ "ignoring this remote" ),
688+ remote_name , p -> url , remote_url );
644689 return 0 ;
645690 }
646691
647- if (!strcmp (p -> url , remote_url ))
648- return all_fields_match (advertised , config_info , 0 );
649-
650- warning (_ ("known remote named '%s' but with URL '%s' instead of '%s'" ),
651- remote_name , p -> url , remote_url );
652-
653- return 0 ;
692+ return all_fields_match (advertised , config_info , p );
654693}
655694
656695static int skip_field_name_prefix (const char * elem , const char * field_name , const char * * value )
@@ -691,9 +730,9 @@ static struct promisor_info *parse_one_advertised_remote(const char *remote_info
691730
692731 string_list_clear (& elem_list , 0 );
693732
694- if (!info -> name || !info -> url ) {
695- warning (_ ("server advertised a promisor remote without a name or URL: %s" ),
696- remote_info );
733+ if (!info -> name || !* info -> name || ! info -> url || ! * info -> url ) {
734+ warning (_ ("server advertised a promisor remote without a name or URL: '%s', "
735+ "ignoring this remote" ), remote_info );
697736 promisor_info_free (info );
698737 return NULL ;
699738 }
@@ -741,18 +780,14 @@ static bool valid_filter(const char *filter, const char *remote_name)
741780 return !res ;
742781}
743782
744- /* Check that a token doesn't contain any control character */
745783static bool valid_token (const char * token , const char * remote_name )
746784{
747- const char * c = token ;
748-
749- for (; * c ; c ++ )
750- if (iscntrl (* c )) {
751- warning (_ ("invalid token '%s' for remote '%s' "
752- "will not be stored" ),
753- token , remote_name );
754- return false;
755- }
785+ if (has_control_char (token )) {
786+ warning (_ ("invalid token '%s' for remote '%s' "
787+ "will not be stored" ),
788+ token , remote_name );
789+ return false;
790+ }
756791
757792 return true;
758793}
@@ -827,20 +862,12 @@ static bool promisor_store_advertised_fields(struct promisor_info *advertised,
827862 return reload_config ;
828863}
829864
830- static void filter_promisor_remote (struct repository * repo ,
831- struct strvec * accepted ,
832- const char * info )
865+ static enum accept_promisor accept_from_server (struct repository * repo )
833866{
834867 const char * accept_str ;
835868 enum accept_promisor accept = ACCEPT_NONE ;
836- struct string_list config_info = STRING_LIST_INIT_NODUP ;
837- struct string_list remote_info = STRING_LIST_INIT_DUP ;
838- struct store_info * store_info = NULL ;
839- struct string_list_item * item ;
840- bool reload_config = false;
841- struct string_list accepted_filters = STRING_LIST_INIT_DUP ;
842869
843- if (!repo_config_get_string_tmp (the_repository , "promisor.acceptfromserver" , & accept_str )) {
870+ if (!repo_config_get_string_tmp (repo , "promisor.acceptfromserver" , & accept_str )) {
844871 if (!* accept_str || !strcasecmp ("None" , accept_str ))
845872 accept = ACCEPT_NONE ;
846873 else if (!strcasecmp ("KnownUrl" , accept_str ))
@@ -854,6 +881,20 @@ static void filter_promisor_remote(struct repository *repo,
854881 accept_str , "promisor.acceptfromserver" );
855882 }
856883
884+ return accept ;
885+ }
886+
887+ static void filter_promisor_remote (struct repository * repo ,
888+ struct string_list * accepted_remotes ,
889+ const char * info )
890+ {
891+ struct string_list config_info = STRING_LIST_INIT_NODUP ;
892+ struct string_list remote_info = STRING_LIST_INIT_DUP ;
893+ struct store_info * store_info = NULL ;
894+ struct string_list_item * item ;
895+ bool reload_config = false;
896+ enum accept_promisor accept = accept_from_server (repo );
897+
857898 if (accept == ACCEPT_NONE )
858899 return ;
859900
@@ -880,17 +921,10 @@ static void filter_promisor_remote(struct repository *repo,
880921 if (promisor_store_advertised_fields (advertised , store_info ))
881922 reload_config = true;
882923
883- strvec_push (accepted , advertised -> name );
884-
885- /* Capture advertised filters for accepted remotes */
886- if (advertised -> filter ) {
887- struct string_list_item * i ;
888- i = string_list_append (& accepted_filters , advertised -> name );
889- i -> util = xstrdup (advertised -> filter );
890- }
924+ string_list_append (accepted_remotes , advertised -> name )-> util = advertised ;
925+ } else {
926+ promisor_info_free (advertised );
891927 }
892-
893- promisor_info_free (advertised );
894928 }
895929
896930 promisor_info_list_clear (& config_info );
@@ -900,47 +934,44 @@ static void filter_promisor_remote(struct repository *repo,
900934 if (reload_config )
901935 repo_promisor_remote_reinit (repo );
902936
903- /* Apply accepted remote filters to the stable repo state */
904- for_each_string_list_item (item , & accepted_filters ) {
905- struct promisor_remote * r = repo_promisor_remote_find (repo , item -> string );
906- if (r ) {
907- free (r -> advertised_filter );
908- r -> advertised_filter = item -> util ;
909- item -> util = NULL ;
910- }
911- }
937+ /* Apply accepted remotes to the stable repo state */
938+ for_each_string_list_item (item , accepted_remotes ) {
939+ struct promisor_info * info = item -> util ;
940+ struct promisor_remote * r = repo_promisor_remote_find (repo , info -> name );
912941
913- string_list_clear (& accepted_filters , 1 );
914-
915- /* Mark the remotes as accepted in the repository state */
916- for (size_t i = 0 ; i < accepted -> nr ; i ++ ) {
917- struct promisor_remote * r = repo_promisor_remote_find (repo , accepted -> v [i ]);
918- if (r )
942+ if (r ) {
919943 r -> accepted = 1 ;
944+ if (info -> filter ) {
945+ free (r -> advertised_filter );
946+ r -> advertised_filter = xstrdup (info -> filter );
947+ }
948+ }
920949 }
921950}
922951
923952void promisor_remote_reply (const char * info , char * * accepted_out )
924953{
925- struct strvec accepted = STRVEC_INIT ;
954+ struct string_list accepted_remotes = STRING_LIST_INIT_NODUP ;
926955
927- filter_promisor_remote (the_repository , & accepted , info );
956+ filter_promisor_remote (the_repository , & accepted_remotes , info );
928957
929958 if (accepted_out ) {
930- if (accepted .nr ) {
959+ if (accepted_remotes .nr ) {
931960 struct strbuf reply = STRBUF_INIT ;
932- for (size_t i = 0 ; i < accepted .nr ; i ++ ) {
933- if (i )
961+ struct string_list_item * item ;
962+
963+ for_each_string_list_item (item , & accepted_remotes ) {
964+ if (reply .len )
934965 strbuf_addch (& reply , ';' );
935- strbuf_addstr_urlencode (& reply , accepted . v [ i ] , allow_unsanitized );
966+ strbuf_addstr_urlencode (& reply , item -> string , allow_unsanitized );
936967 }
937968 * accepted_out = strbuf_detach (& reply , NULL );
938969 } else {
939970 * accepted_out = NULL ;
940971 }
941972 }
942973
943- strvec_clear ( & accepted );
974+ promisor_info_list_clear ( & accepted_remotes );
944975}
945976
946977void mark_promisor_remotes_as_accepted (struct repository * r , const char * remotes )
0 commit comments