@@ -124,6 +124,37 @@ static long config_buf_ftell(struct config_source *conf)
124124 return conf -> u .buf .pos ;
125125}
126126
127+ struct remote_urls_entry {
128+ struct hashmap_entry ent ;
129+ char * name ;
130+ struct string_list urls ;
131+ };
132+
133+ static struct remote_urls_entry * remote_urls_find_entry (struct hashmap * remote_urls ,
134+ char * name )
135+ {
136+ struct remote_urls_entry k ;
137+ struct remote_urls_entry * found_entry ;
138+
139+ hashmap_entry_init (& k .ent , strhash (name ));
140+ k .name = name ;
141+ found_entry = hashmap_get_entry (remote_urls , & k , ent , NULL );
142+ return found_entry ;
143+ }
144+
145+ static int remote_urls_entry_cmp (const void * cmp_data UNUSED ,
146+ const struct hashmap_entry * eptr ,
147+ const struct hashmap_entry * entry_or_key ,
148+ const void * keydata UNUSED )
149+ {
150+ const struct remote_urls_entry * e1 , * e2 ;
151+
152+ e1 = container_of (eptr , const struct remote_urls_entry , ent );
153+ e2 = container_of (entry_or_key , const struct remote_urls_entry , ent );
154+
155+ return strcmp (e1 -> name , e2 -> name );
156+ }
157+
127158struct config_include_data {
128159 int depth ;
129160 config_fn_t fn ;
@@ -133,9 +164,10 @@ struct config_include_data {
133164 struct repository * repo ;
134165
135166 /*
136- * All remote URLs discovered when reading all config files.
167+ * All remote names & URLs discovered when reading all config files.
137168 */
138- struct string_list * remote_urls ;
169+ struct hashmap remote_urls ;
170+ int remote_urls_initialized ;
139171};
140172#define CONFIG_INCLUDE_INIT { 0 }
141173
@@ -329,16 +361,36 @@ static int include_by_branch(struct config_include_data *data,
329361static int add_remote_url (const char * var , const char * value ,
330362 const struct config_context * ctx UNUSED , void * data )
331363{
332- struct string_list * remote_urls = data ;
333- const char * remote_name ;
364+ struct hashmap * remote_urls = data ;
365+ const char * remote_section ;
334366 size_t remote_name_len ;
335367 const char * key ;
336368
337- if (!parse_config_key (var , "remote" , & remote_name , & remote_name_len ,
369+ if (!parse_config_key (var , "remote" , & remote_section , & remote_name_len ,
338370 & key ) &&
339- remote_name &&
340- !strcmp (key , "url" ))
341- string_list_append (remote_urls , value );
371+ remote_section &&
372+ !strcmp (key , "url" )) {
373+ const char * dot ;
374+ char * remote_name ;
375+ struct remote_urls_entry * e ;
376+
377+ dot = strchr (remote_section , '.' );
378+ if (!dot )
379+ return 0 ;
380+
381+ remote_name = xstrndup (remote_section , dot - remote_section );
382+ e = remote_urls_find_entry (remote_urls , remote_name );
383+ if (!e ) {
384+ e = xmalloc (sizeof (* e ));
385+ hashmap_entry_init (& e -> ent , strhash (remote_name ));
386+ e -> name = remote_name ;
387+ string_list_init_dup (& e -> urls );
388+ string_list_append (& e -> urls , value );
389+ hashmap_add (remote_urls , & e -> ent );
390+ } else {
391+ string_list_append (& e -> urls , value );
392+ }
393+ }
342394 return 0 ;
343395}
344396
@@ -349,9 +401,9 @@ static void populate_remote_urls(struct config_include_data *inc)
349401 opts = * inc -> opts ;
350402 opts .unconditional_remote_url = 1 ;
351403
352- inc -> remote_urls = xmalloc ( sizeof ( * inc -> remote_urls ) );
353- string_list_init_dup ( inc -> remote_urls ) ;
354- config_with_options (add_remote_url , inc -> remote_urls ,
404+ hashmap_init ( & inc -> remote_urls , remote_urls_entry_cmp , NULL , 0 );
405+ inc -> remote_urls_initialized = 1 ;
406+ config_with_options (add_remote_url , & inc -> remote_urls ,
355407 inc -> config_source , inc -> repo , & opts );
356408}
357409
@@ -392,12 +444,35 @@ static int at_least_one_url_matches_glob(const char *glob, int glob_len,
392444static int include_by_remote_url (struct config_include_data * inc ,
393445 const char * cond , size_t cond_len )
394446{
447+ struct hashmap_iter iter ;
448+ struct remote_urls_entry * remote ;
449+
450+ if (inc -> opts -> unconditional_remote_url )
451+ return 1 ;
452+ if (!inc -> remote_urls_initialized )
453+ populate_remote_urls (inc );
454+
455+ hashmap_for_each_entry (& inc -> remote_urls , & iter , remote , ent )
456+ if (at_least_one_url_matches_glob (cond , cond_len , & remote -> urls ))
457+ return 1 ;
458+ return 0 ;
459+ }
460+
461+ static int include_by_remote_name_and_url (struct config_include_data * inc ,
462+ const char * cond , size_t cond_len ,
463+ char * remote_name )
464+ {
465+ struct remote_urls_entry * e ;
466+
395467 if (inc -> opts -> unconditional_remote_url )
396468 return 1 ;
397- if (!inc -> remote_urls )
469+ if (!inc -> remote_urls_initialized )
398470 populate_remote_urls (inc );
399- return at_least_one_url_matches_glob (cond , cond_len ,
400- inc -> remote_urls );
471+
472+ e = remote_urls_find_entry (& inc -> remote_urls , remote_name );
473+ if (!e )
474+ return 0 ;
475+ return at_least_one_url_matches_glob (cond , cond_len , & e -> urls );
401476}
402477
403478static int include_condition_is_true (const struct key_value_info * kvi ,
@@ -415,6 +490,32 @@ static int include_condition_is_true(const struct key_value_info *kvi,
415490 else if (skip_prefix_mem (cond , cond_len , "hasconfig:remote.*.url:" , & cond ,
416491 & cond_len ))
417492 return include_by_remote_url (inc , cond , cond_len );
493+ else if (skip_prefix_mem (cond , cond_len , "hasconfig:remote." , & cond ,
494+ & cond_len )) {
495+ const char * dot ;
496+ char * remote_name ;
497+ char * cond_prefix ;
498+ int ret ;
499+
500+ dot = strchr (cond , '.' );
501+ if (!dot )
502+ return 0 ;
503+
504+ remote_name = xstrndup (cond , dot - cond );
505+ cond_prefix = xstrfmt ("%s.url:" , remote_name );
506+ if (!skip_prefix_mem (cond , cond_len , cond_prefix , & cond ,
507+ & cond_len )) {
508+ free (cond_prefix );
509+ free (remote_name );
510+ return 0 ;
511+ }
512+ free (cond_prefix );
513+
514+ ret = include_by_remote_name_and_url (inc , cond , cond_len ,
515+ remote_name );
516+ free (remote_name );
517+ return ret ;
518+ }
418519
419520 /* unknown conditionals are always false */
420521 return 0 ;
@@ -2130,9 +2231,15 @@ int config_with_options(config_fn_t fn, void *data,
21302231 ret = do_git_config_sequence (opts , repo , fn , data );
21312232 }
21322233
2133- if (inc .remote_urls ) {
2134- string_list_clear (inc .remote_urls , 0 );
2135- FREE_AND_NULL (inc .remote_urls );
2234+ if (inc .remote_urls_initialized ) {
2235+ struct hashmap_iter iter ;
2236+ struct remote_urls_entry * remote ;
2237+ hashmap_for_each_entry (& inc .remote_urls , & iter , remote , ent ) {
2238+ string_list_clear (& remote -> urls , 0 );
2239+ free (remote -> name );
2240+ }
2241+ hashmap_clear_and_free (& inc .remote_urls , struct remote_urls_entry , ent );
2242+ inc .remote_urls_initialized = 0 ;
21362243 }
21372244 return ret ;
21382245}
0 commit comments