8
8
#include "cache.h"
9
9
#include "branch.h"
10
10
#include "config.h"
11
+ #include "environment.h"
11
12
#include "repository.h"
12
13
#include "lockfile.h"
13
14
#include "exec-cmd.h"
@@ -332,19 +333,82 @@ int git_config_include(const char *var, const char *value, void *data)
332
333
return ret ;
333
334
}
334
335
335
- void git_config_push_parameter (const char * text )
336
+ static void git_config_push_split_parameter (const char * key , const char * value )
336
337
{
337
338
struct strbuf env = STRBUF_INIT ;
338
339
const char * old = getenv (CONFIG_DATA_ENVIRONMENT );
339
340
if (old && * old ) {
340
341
strbuf_addstr (& env , old );
341
342
strbuf_addch (& env , ' ' );
342
343
}
343
- sq_quote_buf (& env , text );
344
+ sq_quote_buf (& env , key );
345
+ strbuf_addch (& env , '=' );
346
+ if (value )
347
+ sq_quote_buf (& env , value );
344
348
setenv (CONFIG_DATA_ENVIRONMENT , env .buf , 1 );
345
349
strbuf_release (& env );
346
350
}
347
351
352
+ void git_config_push_parameter (const char * text )
353
+ {
354
+ const char * value ;
355
+
356
+ /*
357
+ * When we see:
358
+ *
359
+ * section.subsection=with=equals.key=value
360
+ *
361
+ * we cannot tell if it means:
362
+ *
363
+ * [section "subsection=with=equals"]
364
+ * key = value
365
+ *
366
+ * or:
367
+ *
368
+ * [section]
369
+ * subsection = with=equals.key=value
370
+ *
371
+ * We parse left-to-right for the first "=", meaning we'll prefer to
372
+ * keep the value intact over the subsection. This is historical, but
373
+ * also sensible since values are more likely to contain odd or
374
+ * untrusted input than a section name.
375
+ *
376
+ * A missing equals is explicitly allowed (as a bool-only entry).
377
+ */
378
+ value = strchr (text , '=' );
379
+ if (value ) {
380
+ char * key = xmemdupz (text , value - text );
381
+ git_config_push_split_parameter (key , value + 1 );
382
+ free (key );
383
+ } else {
384
+ git_config_push_split_parameter (text , NULL );
385
+ }
386
+ }
387
+
388
+ void git_config_push_env (const char * spec )
389
+ {
390
+ char * key ;
391
+ const char * env_name ;
392
+ const char * env_value ;
393
+
394
+ env_name = strrchr (spec , '=' );
395
+ if (!env_name )
396
+ die (_ ("invalid config format: %s" ), spec );
397
+ key = xmemdupz (spec , env_name - spec );
398
+ env_name ++ ;
399
+ if (!* env_name )
400
+ die (_ ("missing environment variable name for configuration '%.*s'" ),
401
+ (int )(env_name - spec - 1 ), spec );
402
+
403
+ env_value = getenv (env_name );
404
+ if (!env_value )
405
+ die (_ ("missing environment variable '%s' for configuration '%.*s'" ),
406
+ env_name , (int )(env_name - spec - 1 ), spec );
407
+
408
+ git_config_push_split_parameter (key , env_value );
409
+ free (key );
410
+ }
411
+
348
412
static inline int iskeychar (int c )
349
413
{
350
414
return isalnum (c ) || c == '-' ;
@@ -437,11 +501,26 @@ int git_config_key_is_valid(const char *key)
437
501
return !git_config_parse_key_1 (key , NULL , NULL , 1 );
438
502
}
439
503
504
+ static int config_parse_pair (const char * key , const char * value ,
505
+ config_fn_t fn , void * data )
506
+ {
507
+ char * canonical_name ;
508
+ int ret ;
509
+
510
+ if (!strlen (key ))
511
+ return error (_ ("empty config key" ));
512
+ if (git_config_parse_key (key , & canonical_name , NULL ))
513
+ return -1 ;
514
+
515
+ ret = (fn (canonical_name , value , data ) < 0 ) ? -1 : 0 ;
516
+ free (canonical_name );
517
+ return ret ;
518
+ }
519
+
440
520
int git_config_parse_parameter (const char * text ,
441
521
config_fn_t fn , void * data )
442
522
{
443
523
const char * value ;
444
- char * canonical_name ;
445
524
struct strbuf * * pair ;
446
525
int ret ;
447
526
@@ -462,51 +541,131 @@ int git_config_parse_parameter(const char *text,
462
541
return error (_ ("bogus config parameter: %s" ), text );
463
542
}
464
543
465
- if (git_config_parse_key (pair [0 ]-> buf , & canonical_name , NULL )) {
466
- ret = -1 ;
467
- } else {
468
- ret = (fn (canonical_name , value , data ) < 0 ) ? -1 : 0 ;
469
- free (canonical_name );
470
- }
544
+ ret = config_parse_pair (pair [0 ]-> buf , value , fn , data );
471
545
strbuf_list_free (pair );
472
546
return ret ;
473
547
}
474
548
549
+ static int parse_config_env_list (char * env , config_fn_t fn , void * data )
550
+ {
551
+ char * cur = env ;
552
+ while (cur && * cur ) {
553
+ const char * key = sq_dequote_step (cur , & cur );
554
+ if (!key )
555
+ return error (_ ("bogus format in %s" ),
556
+ CONFIG_DATA_ENVIRONMENT );
557
+
558
+ if (!cur || isspace (* cur )) {
559
+ /* old-style 'key=value' */
560
+ if (git_config_parse_parameter (key , fn , data ) < 0 )
561
+ return -1 ;
562
+ }
563
+ else if (* cur == '=' ) {
564
+ /* new-style 'key'='value' */
565
+ const char * value ;
566
+
567
+ cur ++ ;
568
+ if (* cur == '\'' ) {
569
+ /* quoted value */
570
+ value = sq_dequote_step (cur , & cur );
571
+ if (!value || (cur && !isspace (* cur ))) {
572
+ return error (_ ("bogus format in %s" ),
573
+ CONFIG_DATA_ENVIRONMENT );
574
+ }
575
+ } else if (!* cur || isspace (* cur )) {
576
+ /* implicit bool: 'key'= */
577
+ value = NULL ;
578
+ } else {
579
+ return error (_ ("bogus format in %s" ),
580
+ CONFIG_DATA_ENVIRONMENT );
581
+ }
582
+
583
+ if (config_parse_pair (key , value , fn , data ) < 0 )
584
+ return -1 ;
585
+ }
586
+ else {
587
+ /* unknown format */
588
+ return error (_ ("bogus format in %s" ),
589
+ CONFIG_DATA_ENVIRONMENT );
590
+ }
591
+
592
+ if (cur ) {
593
+ while (isspace (* cur ))
594
+ cur ++ ;
595
+ }
596
+ }
597
+ return 0 ;
598
+ }
599
+
475
600
int git_config_from_parameters (config_fn_t fn , void * data )
476
601
{
477
- const char * env = getenv (CONFIG_DATA_ENVIRONMENT );
602
+ const char * env ;
603
+ struct strbuf envvar = STRBUF_INIT ;
604
+ struct strvec to_free = STRVEC_INIT ;
478
605
int ret = 0 ;
479
- char * envw ;
480
- const char * * argv = NULL ;
481
- int nr = 0 , alloc = 0 ;
482
- int i ;
606
+ char * envw = NULL ;
483
607
struct config_source source ;
484
608
485
- if (!env )
486
- return 0 ;
487
-
488
609
memset (& source , 0 , sizeof (source ));
489
610
source .prev = cf ;
490
611
source .origin_type = CONFIG_ORIGIN_CMDLINE ;
491
612
cf = & source ;
492
613
493
- /* sq_dequote will write over it */
494
- envw = xstrdup (env );
614
+ env = getenv (CONFIG_COUNT_ENVIRONMENT );
615
+ if (env ) {
616
+ unsigned long count ;
617
+ char * endp ;
618
+ int i ;
495
619
496
- if (sq_dequote_to_argv (envw , & argv , & nr , & alloc ) < 0 ) {
497
- ret = error (_ ("bogus format in %s" ), CONFIG_DATA_ENVIRONMENT );
498
- goto out ;
620
+ count = strtoul (env , & endp , 10 );
621
+ if (* endp ) {
622
+ ret = error (_ ("bogus count in %s" ), CONFIG_COUNT_ENVIRONMENT );
623
+ goto out ;
624
+ }
625
+ if (count > INT_MAX ) {
626
+ ret = error (_ ("too many entries in %s" ), CONFIG_COUNT_ENVIRONMENT );
627
+ goto out ;
628
+ }
629
+
630
+ for (i = 0 ; i < count ; i ++ ) {
631
+ const char * key , * value ;
632
+
633
+ strbuf_addf (& envvar , "GIT_CONFIG_KEY_%d" , i );
634
+ key = getenv_safe (& to_free , envvar .buf );
635
+ if (!key ) {
636
+ ret = error (_ ("missing config key %s" ), envvar .buf );
637
+ goto out ;
638
+ }
639
+ strbuf_reset (& envvar );
640
+
641
+ strbuf_addf (& envvar , "GIT_CONFIG_VALUE_%d" , i );
642
+ value = getenv_safe (& to_free , envvar .buf );
643
+ if (!value ) {
644
+ ret = error (_ ("missing config value %s" ), envvar .buf );
645
+ goto out ;
646
+ }
647
+ strbuf_reset (& envvar );
648
+
649
+ if (config_parse_pair (key , value , fn , data ) < 0 ) {
650
+ ret = -1 ;
651
+ goto out ;
652
+ }
653
+ }
499
654
}
500
655
501
- for (i = 0 ; i < nr ; i ++ ) {
502
- if (git_config_parse_parameter (argv [i ], fn , data ) < 0 ) {
656
+ env = getenv (CONFIG_DATA_ENVIRONMENT );
657
+ if (env ) {
658
+ /* sq_dequote will write over it */
659
+ envw = xstrdup (env );
660
+ if (parse_config_env_list (envw , fn , data ) < 0 ) {
503
661
ret = -1 ;
504
662
goto out ;
505
663
}
506
664
}
507
665
508
666
out :
509
- free (argv );
667
+ strbuf_release (& envvar );
668
+ strvec_clear (& to_free );
510
669
free (envw );
511
670
cf = source .prev ;
512
671
return ret ;
0 commit comments