88#include "cache.h"
99#include "branch.h"
1010#include "config.h"
11+ #include "environment.h"
1112#include "repository.h"
1213#include "lockfile.h"
1314#include "exec-cmd.h"
@@ -332,19 +333,82 @@ int git_config_include(const char *var, const char *value, void *data)
332333 return ret ;
333334}
334335
335- void git_config_push_parameter (const char * text )
336+ static void git_config_push_split_parameter (const char * key , const char * value )
336337{
337338 struct strbuf env = STRBUF_INIT ;
338339 const char * old = getenv (CONFIG_DATA_ENVIRONMENT );
339340 if (old && * old ) {
340341 strbuf_addstr (& env , old );
341342 strbuf_addch (& env , ' ' );
342343 }
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 );
344348 setenv (CONFIG_DATA_ENVIRONMENT , env .buf , 1 );
345349 strbuf_release (& env );
346350}
347351
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+
348412static inline int iskeychar (int c )
349413{
350414 return isalnum (c ) || c == '-' ;
@@ -437,11 +501,26 @@ int git_config_key_is_valid(const char *key)
437501 return !git_config_parse_key_1 (key , NULL , NULL , 1 );
438502}
439503
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+
440520int git_config_parse_parameter (const char * text ,
441521 config_fn_t fn , void * data )
442522{
443523 const char * value ;
444- char * canonical_name ;
445524 struct strbuf * * pair ;
446525 int ret ;
447526
@@ -462,51 +541,131 @@ int git_config_parse_parameter(const char *text,
462541 return error (_ ("bogus config parameter: %s" ), text );
463542 }
464543
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 );
471545 strbuf_list_free (pair );
472546 return ret ;
473547}
474548
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+
475600int git_config_from_parameters (config_fn_t fn , void * data )
476601{
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 ;
478605 int ret = 0 ;
479- char * envw ;
480- const char * * argv = NULL ;
481- int nr = 0 , alloc = 0 ;
482- int i ;
606+ char * envw = NULL ;
483607 struct config_source source ;
484608
485- if (!env )
486- return 0 ;
487-
488609 memset (& source , 0 , sizeof (source ));
489610 source .prev = cf ;
490611 source .origin_type = CONFIG_ORIGIN_CMDLINE ;
491612 cf = & source ;
492613
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 ;
495619
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+ }
499654 }
500655
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 ) {
503661 ret = -1 ;
504662 goto out ;
505663 }
506664 }
507665
508666out :
509- free (argv );
667+ strbuf_release (& envvar );
668+ strvec_clear (& to_free );
510669 free (envw );
511670 cf = source .prev ;
512671 return ret ;
0 commit comments