@@ -123,6 +123,37 @@ static long config_buf_ftell(struct config_source *conf)
123123 return conf -> u .buf .pos ;
124124}
125125
126+ struct remote_urls_entry {
127+ struct hashmap_entry ent ;
128+ char * name ;
129+ struct string_list urls ;
130+ };
131+
132+ static struct remote_urls_entry * remote_urls_find_entry (struct hashmap * remote_urls ,
133+ char * name )
134+ {
135+ struct remote_urls_entry k ;
136+ struct remote_urls_entry * found_entry ;
137+
138+ hashmap_entry_init (& k .ent , strhash (name ));
139+ k .name = name ;
140+ found_entry = hashmap_get_entry (remote_urls , & k , ent , NULL );
141+ return found_entry ;
142+ }
143+
144+ static int remote_urls_entry_cmp (const void * cmp_data UNUSED ,
145+ const struct hashmap_entry * eptr ,
146+ const struct hashmap_entry * entry_or_key ,
147+ const void * keydata UNUSED )
148+ {
149+ const struct remote_urls_entry * e1 , * e2 ;
150+
151+ e1 = container_of (eptr , const struct remote_urls_entry , ent );
152+ e2 = container_of (entry_or_key , const struct remote_urls_entry , ent );
153+
154+ return strcmp (e1 -> name , e2 -> name );
155+ }
156+
126157struct config_include_data {
127158 int depth ;
128159 config_fn_t fn ;
@@ -132,9 +163,10 @@ struct config_include_data {
132163 struct repository * repo ;
133164
134165 /*
135- * All remote URLs discovered when reading all config files.
166+ * All remote names & URLs discovered when reading all config files.
136167 */
137- struct string_list * remote_urls ;
168+ struct hashmap remote_urls ;
169+ int remote_urls_initialized ;
138170};
139171#define CONFIG_INCLUDE_INIT { 0 }
140172
@@ -328,16 +360,36 @@ static int include_by_branch(struct config_include_data *data,
328360static int add_remote_url (const char * var , const char * value ,
329361 const struct config_context * ctx UNUSED , void * data )
330362{
331- struct string_list * remote_urls = data ;
332- const char * remote_name ;
363+ struct hashmap * remote_urls = data ;
364+ const char * remote_section ;
333365 size_t remote_name_len ;
334366 const char * key ;
335367
336- if (!parse_config_key (var , "remote" , & remote_name , & remote_name_len ,
368+ if (!parse_config_key (var , "remote" , & remote_section , & remote_name_len ,
337369 & key ) &&
338- remote_name &&
339- !strcmp (key , "url" ))
340- string_list_append (remote_urls , value );
370+ remote_section &&
371+ !strcmp (key , "url" )) {
372+ const char * dot ;
373+ char * remote_name ;
374+ struct remote_urls_entry * e ;
375+
376+ dot = strchr (remote_section , '.' );
377+ if (!dot )
378+ return 0 ;
379+
380+ remote_name = xstrndup (remote_section , dot - remote_section );
381+ e = remote_urls_find_entry (remote_urls , remote_name );
382+ if (!e ) {
383+ e = xmalloc (sizeof (* e ));
384+ hashmap_entry_init (& e -> ent , strhash (remote_name ));
385+ e -> name = remote_name ;
386+ string_list_init_dup (& e -> urls );
387+ string_list_append (& e -> urls , value );
388+ hashmap_add (remote_urls , & e -> ent );
389+ } else {
390+ string_list_append (& e -> urls , value );
391+ }
392+ }
341393 return 0 ;
342394}
343395
@@ -348,9 +400,9 @@ static void populate_remote_urls(struct config_include_data *inc)
348400 opts = * inc -> opts ;
349401 opts .unconditional_remote_url = 1 ;
350402
351- inc -> remote_urls = xmalloc ( sizeof ( * inc -> remote_urls ) );
352- string_list_init_dup ( inc -> remote_urls ) ;
353- config_with_options (add_remote_url , inc -> remote_urls ,
403+ hashmap_init ( & inc -> remote_urls , remote_urls_entry_cmp , NULL , 0 );
404+ inc -> remote_urls_initialized = 1 ;
405+ config_with_options (add_remote_url , & inc -> remote_urls ,
354406 inc -> config_source , inc -> repo , & opts );
355407}
356408
@@ -391,12 +443,35 @@ static int at_least_one_url_matches_glob(const char *glob, int glob_len,
391443static int include_by_remote_url (struct config_include_data * inc ,
392444 const char * cond , size_t cond_len )
393445{
446+ struct hashmap_iter iter ;
447+ struct remote_urls_entry * remote ;
448+
449+ if (inc -> opts -> unconditional_remote_url )
450+ return 1 ;
451+ if (!inc -> remote_urls_initialized )
452+ populate_remote_urls (inc );
453+
454+ hashmap_for_each_entry (& inc -> remote_urls , & iter , remote , ent )
455+ if (at_least_one_url_matches_glob (cond , cond_len , & remote -> urls ))
456+ return 1 ;
457+ return 0 ;
458+ }
459+
460+ static int include_by_remote_name_and_url (struct config_include_data * inc ,
461+ const char * cond , size_t cond_len ,
462+ char * remote_name )
463+ {
464+ struct remote_urls_entry * e ;
465+
394466 if (inc -> opts -> unconditional_remote_url )
395467 return 1 ;
396- if (!inc -> remote_urls )
468+ if (!inc -> remote_urls_initialized )
397469 populate_remote_urls (inc );
398- return at_least_one_url_matches_glob (cond , cond_len ,
399- inc -> remote_urls );
470+
471+ e = remote_urls_find_entry (& inc -> remote_urls , remote_name );
472+ if (!e )
473+ return 0 ;
474+ return at_least_one_url_matches_glob (cond , cond_len , & e -> urls );
400475}
401476
402477static int include_condition_is_true (const struct key_value_info * kvi ,
@@ -414,6 +489,32 @@ static int include_condition_is_true(const struct key_value_info *kvi,
414489 else if (skip_prefix_mem (cond , cond_len , "hasconfig:remote.*.url:" , & cond ,
415490 & cond_len ))
416491 return include_by_remote_url (inc , cond , cond_len );
492+ else if (skip_prefix_mem (cond , cond_len , "hasconfig:remote." , & cond ,
493+ & cond_len )) {
494+ const char * dot ;
495+ char * remote_name ;
496+ char * cond_prefix ;
497+ int ret ;
498+
499+ dot = strchr (cond , '.' );
500+ if (!dot )
501+ return 0 ;
502+
503+ remote_name = xstrndup (cond , dot - cond );
504+ cond_prefix = xstrfmt ("%s.url:" , remote_name );
505+ if (!skip_prefix_mem (cond , cond_len , cond_prefix , & cond ,
506+ & cond_len )) {
507+ free (cond_prefix );
508+ free (remote_name );
509+ return 0 ;
510+ }
511+ free (cond_prefix );
512+
513+ ret = include_by_remote_name_and_url (inc , cond , cond_len ,
514+ remote_name );
515+ free (remote_name );
516+ return ret ;
517+ }
417518
418519 /* unknown conditionals are always false */
419520 return 0 ;
@@ -2163,9 +2264,15 @@ int config_with_options(config_fn_t fn, void *data,
21632264 ret = do_git_config_sequence (opts , repo , fn , data );
21642265 }
21652266
2166- if (inc .remote_urls ) {
2167- string_list_clear (inc .remote_urls , 0 );
2168- FREE_AND_NULL (inc .remote_urls );
2267+ if (inc .remote_urls_initialized ) {
2268+ struct hashmap_iter iter ;
2269+ struct remote_urls_entry * remote ;
2270+ hashmap_for_each_entry (& inc .remote_urls , & iter , remote , ent ) {
2271+ string_list_clear (& remote -> urls , 0 );
2272+ free (remote -> name );
2273+ }
2274+ hashmap_clear_and_free (& inc .remote_urls , struct remote_urls_entry , ent );
2275+ inc .remote_urls_initialized = 0 ;
21692276 }
21702277 return ret ;
21712278}
0 commit comments