@@ -120,6 +120,22 @@ static long config_buf_ftell(struct config_source *conf)
120
120
return conf -> u .buf .pos ;
121
121
}
122
122
123
+ struct config_include_data {
124
+ int depth ;
125
+ config_fn_t fn ;
126
+ void * data ;
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 ;
134
+ };
135
+ #define CONFIG_INCLUDE_INIT { 0 }
136
+
137
+ static int git_config_include (const char * var , const char * value , void * data );
138
+
123
139
#define MAX_INCLUDE_DEPTH 10
124
140
static const char include_depth_advice [] = N_ (
125
141
"exceeded maximum include depth (%d) while including\n"
@@ -294,22 +310,108 @@ static int include_by_branch(const char *cond, size_t cond_len)
294
310
return ret ;
295
311
}
296
312
297
- 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 ,
298
396
const char * cond , size_t cond_len )
299
397
{
398
+ const struct config_options * opts = inc -> opts ;
300
399
301
400
if (skip_prefix_mem (cond , cond_len , "gitdir:" , & cond , & cond_len ))
302
401
return include_by_gitdir (opts , cond , cond_len , 0 );
303
402
else if (skip_prefix_mem (cond , cond_len , "gitdir/i:" , & cond , & cond_len ))
304
403
return include_by_gitdir (opts , cond , cond_len , 1 );
305
404
else if (skip_prefix_mem (cond , cond_len , "onbranch:" , & cond , & cond_len ))
306
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 );
307
409
308
410
/* unknown conditionals are always false */
309
411
return 0 ;
310
412
}
311
413
312
- int git_config_include (const char * var , const char * value , void * data )
414
+ static int git_config_include (const char * var , const char * value , void * data )
313
415
{
314
416
struct config_include_data * inc = data ;
315
417
const char * cond , * key ;
@@ -328,9 +430,15 @@ int git_config_include(const char *var, const char *value, void *data)
328
430
ret = handle_path_include (value , inc );
329
431
330
432
if (!parse_config_key (var , "includeif" , & cond , & cond_len , & key ) &&
331
- (cond && include_condition_is_true (inc -> opts , cond , cond_len )) &&
332
- !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 ;
333
439
ret = handle_path_include (value , inc );
440
+ inc -> fn = old_fn ;
441
+ }
334
442
335
443
return ret ;
336
444
}
@@ -1929,11 +2037,13 @@ int config_with_options(config_fn_t fn, void *data,
1929
2037
const struct config_options * opts )
1930
2038
{
1931
2039
struct config_include_data inc = CONFIG_INCLUDE_INIT ;
2040
+ int ret ;
1932
2041
1933
2042
if (opts -> respect_includes ) {
1934
2043
inc .fn = fn ;
1935
2044
inc .data = data ;
1936
2045
inc .opts = opts ;
2046
+ inc .config_source = config_source ;
1937
2047
fn = git_config_include ;
1938
2048
data = & inc ;
1939
2049
}
@@ -1946,17 +2056,23 @@ int config_with_options(config_fn_t fn, void *data,
1946
2056
* regular lookup sequence.
1947
2057
*/
1948
2058
if (config_source && config_source -> use_stdin ) {
1949
- return git_config_from_stdin (fn , data );
2059
+ ret = git_config_from_stdin (fn , data );
1950
2060
} else if (config_source && config_source -> file ) {
1951
- return git_config_from_file (fn , config_source -> file , data );
2061
+ ret = git_config_from_file (fn , config_source -> file , data );
1952
2062
} else if (config_source && config_source -> blob ) {
1953
2063
struct repository * repo = config_source -> repo ?
1954
2064
config_source -> repo : the_repository ;
1955
- return git_config_from_blob_ref (fn , repo , config_source -> blob ,
2065
+ ret = git_config_from_blob_ref (fn , repo , config_source -> blob ,
1956
2066
data );
2067
+ } else {
2068
+ ret = do_git_config_sequence (opts , fn , data );
1957
2069
}
1958
2070
1959
- return do_git_config_sequence (opts , fn , data );
2071
+ if (inc .remote_urls ) {
2072
+ string_list_clear (inc .remote_urls , 0 );
2073
+ FREE_AND_NULL (inc .remote_urls );
2074
+ }
2075
+ return ret ;
1960
2076
}
1961
2077
1962
2078
static void configset_iter (struct config_set * cs , config_fn_t fn , void * data )
0 commit comments