@@ -125,6 +125,12 @@ struct config_include_data {
125
125
config_fn_t fn ;
126
126
void * data ;
127
127
const struct config_options * opts ;
128
+ struct git_config_source * config_source ;
129
+
130
+ /*
131
+ * All remote URLs discovered when reading all config files.
132
+ */
133
+ struct string_list * remote_urls ;
128
134
};
129
135
#define CONFIG_INCLUDE_INIT { 0 }
130
136
@@ -304,16 +310,102 @@ static int include_by_branch(const char *cond, size_t cond_len)
304
310
return ret ;
305
311
}
306
312
307
- static int include_condition_is_true (const struct config_options * opts ,
313
+ static int add_remote_url (const char * var , const char * value , void * data )
314
+ {
315
+ struct string_list * remote_urls = data ;
316
+ const char * remote_name ;
317
+ size_t remote_name_len ;
318
+ const char * key ;
319
+
320
+ if (!parse_config_key (var , "remote" , & remote_name , & remote_name_len ,
321
+ & key ) &&
322
+ remote_name &&
323
+ !strcmp (key , "url" ))
324
+ string_list_append (remote_urls , value );
325
+ return 0 ;
326
+ }
327
+
328
+ static void populate_remote_urls (struct config_include_data * inc )
329
+ {
330
+ struct config_options opts ;
331
+
332
+ struct config_source * store_cf = cf ;
333
+ struct key_value_info * store_kvi = current_config_kvi ;
334
+ enum config_scope store_scope = current_parsing_scope ;
335
+
336
+ opts = * inc -> opts ;
337
+ opts .unconditional_remote_url = 1 ;
338
+
339
+ cf = NULL ;
340
+ current_config_kvi = NULL ;
341
+ current_parsing_scope = 0 ;
342
+
343
+ inc -> remote_urls = xmalloc (sizeof (* inc -> remote_urls ));
344
+ string_list_init_dup (inc -> remote_urls );
345
+ config_with_options (add_remote_url , inc -> remote_urls , inc -> config_source , & opts );
346
+
347
+ cf = store_cf ;
348
+ current_config_kvi = store_kvi ;
349
+ current_parsing_scope = store_scope ;
350
+ }
351
+
352
+ static int forbid_remote_url (const char * var , const char * value , void * data )
353
+ {
354
+ const char * remote_name ;
355
+ size_t remote_name_len ;
356
+ const char * key ;
357
+
358
+ if (!parse_config_key (var , "remote" , & remote_name , & remote_name_len ,
359
+ & key ) &&
360
+ remote_name &&
361
+ !strcmp (key , "url" ))
362
+ die (_ ("remote URLs cannot be configured in file directly or indirectly included by includeIf.hasconfig:remote.*.url" ));
363
+ return 0 ;
364
+ }
365
+
366
+ static int at_least_one_url_matches_glob (const char * glob , int glob_len ,
367
+ struct string_list * remote_urls )
368
+ {
369
+ struct strbuf pattern = STRBUF_INIT ;
370
+ struct string_list_item * url_item ;
371
+ int found = 0 ;
372
+
373
+ strbuf_add (& pattern , glob , glob_len );
374
+ for_each_string_list_item (url_item , remote_urls ) {
375
+ if (!wildmatch (pattern .buf , url_item -> string , WM_PATHNAME )) {
376
+ found = 1 ;
377
+ break ;
378
+ }
379
+ }
380
+ strbuf_release (& pattern );
381
+ return found ;
382
+ }
383
+
384
+ static int include_by_remote_url (struct config_include_data * inc ,
385
+ const char * cond , size_t cond_len )
386
+ {
387
+ if (inc -> opts -> unconditional_remote_url )
388
+ return 1 ;
389
+ if (!inc -> remote_urls )
390
+ populate_remote_urls (inc );
391
+ return at_least_one_url_matches_glob (cond , cond_len ,
392
+ inc -> remote_urls );
393
+ }
394
+
395
+ static int include_condition_is_true (struct config_include_data * inc ,
308
396
const char * cond , size_t cond_len )
309
397
{
398
+ const struct config_options * opts = inc -> opts ;
310
399
311
400
if (skip_prefix_mem (cond , cond_len , "gitdir:" , & cond , & cond_len ))
312
401
return include_by_gitdir (opts , cond , cond_len , 0 );
313
402
else if (skip_prefix_mem (cond , cond_len , "gitdir/i:" , & cond , & cond_len ))
314
403
return include_by_gitdir (opts , cond , cond_len , 1 );
315
404
else if (skip_prefix_mem (cond , cond_len , "onbranch:" , & cond , & cond_len ))
316
405
return include_by_branch (cond , cond_len );
406
+ else if (skip_prefix_mem (cond , cond_len , "hasconfig:remote.*.url:" , & cond ,
407
+ & cond_len ))
408
+ return include_by_remote_url (inc , cond , cond_len );
317
409
318
410
/* unknown conditionals are always false */
319
411
return 0 ;
@@ -338,9 +430,15 @@ static int git_config_include(const char *var, const char *value, void *data)
338
430
ret = handle_path_include (value , inc );
339
431
340
432
if (!parse_config_key (var , "includeif" , & cond , & cond_len , & key ) &&
341
- (cond && include_condition_is_true (inc -> opts , cond , cond_len )) &&
342
- !strcmp (key , "path" ))
433
+ cond && include_condition_is_true (inc , cond , cond_len ) &&
434
+ !strcmp (key , "path" )) {
435
+ config_fn_t old_fn = inc -> fn ;
436
+
437
+ if (inc -> opts -> unconditional_remote_url )
438
+ inc -> fn = forbid_remote_url ;
343
439
ret = handle_path_include (value , inc );
440
+ inc -> fn = old_fn ;
441
+ }
344
442
345
443
return ret ;
346
444
}
@@ -1936,11 +2034,13 @@ int config_with_options(config_fn_t fn, void *data,
1936
2034
const struct config_options * opts )
1937
2035
{
1938
2036
struct config_include_data inc = CONFIG_INCLUDE_INIT ;
2037
+ int ret ;
1939
2038
1940
2039
if (opts -> respect_includes ) {
1941
2040
inc .fn = fn ;
1942
2041
inc .data = data ;
1943
2042
inc .opts = opts ;
2043
+ inc .config_source = config_source ;
1944
2044
fn = git_config_include ;
1945
2045
data = & inc ;
1946
2046
}
@@ -1953,17 +2053,23 @@ int config_with_options(config_fn_t fn, void *data,
1953
2053
* regular lookup sequence.
1954
2054
*/
1955
2055
if (config_source && config_source -> use_stdin ) {
1956
- return git_config_from_stdin (fn , data );
2056
+ ret = git_config_from_stdin (fn , data );
1957
2057
} else if (config_source && config_source -> file ) {
1958
- return git_config_from_file (fn , config_source -> file , data );
2058
+ ret = git_config_from_file (fn , config_source -> file , data );
1959
2059
} else if (config_source && config_source -> blob ) {
1960
2060
struct repository * repo = config_source -> repo ?
1961
2061
config_source -> repo : the_repository ;
1962
- return git_config_from_blob_ref (fn , repo , config_source -> blob ,
2062
+ ret = git_config_from_blob_ref (fn , repo , config_source -> blob ,
1963
2063
data );
2064
+ } else {
2065
+ ret = do_git_config_sequence (opts , fn , data );
1964
2066
}
1965
2067
1966
- return do_git_config_sequence (opts , fn , data );
2068
+ if (inc .remote_urls ) {
2069
+ string_list_clear (inc .remote_urls , 0 );
2070
+ FREE_AND_NULL (inc .remote_urls );
2071
+ }
2072
+ return ret ;
1967
2073
}
1968
2074
1969
2075
static void configset_iter (struct config_set * cs , config_fn_t fn , void * data )
0 commit comments