@@ -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