@@ -132,6 +132,24 @@ pub use schema::*;
132132
133133use super :: auth:: RegistryConfig ;
134134
135+ /// List of which configuration lists cannot be merged.
136+ ///
137+ /// Instead of merging,
138+ /// the higher priority list should replaces the lower priority list.
139+ ///
140+ /// ## What kind of config is non-mergeable
141+ ///
142+ /// The rule of thumb is that if a config is a path of a program,
143+ /// it should be added to this list.
144+ const NON_MERGEABLE_LISTS : & [ & str ] = & [
145+ "credential-alias.*" ,
146+ "doc.browser" ,
147+ "host.runner" ,
148+ "registries.*.credential-provider" ,
149+ "registry.credential-provider" ,
150+ "target.*.runner" ,
151+ ] ;
152+
135153/// Helper macro for creating typed access methods.
136154macro_rules! get_value_typed {
137155 ( $name: ident, $ty: ty, $variant: ident, $expected: expr) => {
@@ -1007,15 +1025,33 @@ impl GlobalContext {
10071025 return Ok ( ( ) ) ;
10081026 } ;
10091027
1010- if is_nonmergable_list ( & key) {
1011- output. clear ( ) ;
1028+ let env_def = Definition :: Environment ( key. as_env_key ( ) . to_string ( ) ) ;
1029+
1030+ if is_nonmergeable_list ( & key) {
1031+ assert ! (
1032+ output
1033+ . windows( 2 )
1034+ . all( |cvs| cvs[ 0 ] . definition( ) == cvs[ 1 ] . definition( ) ) ,
1035+ "non-mergeable list must have only one definition: {output:?}" ,
1036+ ) ;
1037+
1038+ // Keep existing config if higher priority than env (e.g., --config CLI),
1039+ // otherwise clear for env
1040+ if output
1041+ . first ( )
1042+ . map ( |o| o. definition ( ) > & env_def)
1043+ . unwrap_or_default ( )
1044+ {
1045+ return Ok ( ( ) ) ;
1046+ } else {
1047+ output. clear ( ) ;
1048+ }
10121049 }
10131050
1014- let def = Definition :: Environment ( key. as_env_key ( ) . to_string ( ) ) ;
10151051 if self . cli_unstable ( ) . advanced_env && env_val. starts_with ( '[' ) && env_val. ends_with ( ']' ) {
10161052 // Parse an environment string as a TOML array.
10171053 let toml_v = env_val. parse :: < toml:: Value > ( ) . map_err ( |e| {
1018- ConfigError :: new ( format ! ( "could not parse TOML list: {}" , e) , def . clone ( ) )
1054+ ConfigError :: new ( format ! ( "could not parse TOML list: {}" , e) , env_def . clone ( ) )
10191055 } ) ?;
10201056 let values = toml_v. as_array ( ) . expect ( "env var was not array" ) ;
10211057 for value in values {
@@ -1024,16 +1060,16 @@ impl GlobalContext {
10241060 let s = value. as_str ( ) . ok_or_else ( || {
10251061 ConfigError :: new (
10261062 format ! ( "expected string, found {}" , value. type_str( ) ) ,
1027- def . clone ( ) ,
1063+ env_def . clone ( ) ,
10281064 )
10291065 } ) ?;
1030- output. push ( CV :: String ( s. to_string ( ) , def . clone ( ) ) )
1066+ output. push ( CV :: String ( s. to_string ( ) , env_def . clone ( ) ) )
10311067 }
10321068 } else {
10331069 output. extend (
10341070 env_val
10351071 . split_whitespace ( )
1036- . map ( |s| CV :: String ( s. to_string ( ) , def . clone ( ) ) ) ,
1072+ . map ( |s| CV :: String ( s. to_string ( ) , env_def . clone ( ) ) ) ,
10371073 ) ;
10381074 }
10391075 output. sort_by ( |a, b| a. definition ( ) . cmp ( b. definition ( ) ) ) ;
@@ -2194,7 +2230,7 @@ impl ConfigValue {
21942230 let is_higher_priority = from. definition ( ) . is_higher_priority ( self . definition ( ) ) ;
21952231 match ( self , from) {
21962232 ( & mut CV :: List ( ref mut old, _) , CV :: List ( ref mut new, _) ) => {
2197- if is_nonmergable_list ( & parts) {
2233+ if is_nonmergeable_list ( & parts) {
21982234 // Use whichever list is higher priority.
21992235 if force || is_higher_priority {
22002236 mem:: swap ( new, old) ;
@@ -2342,15 +2378,8 @@ impl ConfigValue {
23422378 }
23432379}
23442380
2345- /// List of which configuration lists cannot be merged.
2346- /// Instead of merging, these the higher priority list replaces the lower priority list.
2347- fn is_nonmergable_list ( key : & ConfigKey ) -> bool {
2348- key. matches ( "registry.credential-provider" )
2349- || key. matches ( "registries.*.credential-provider" )
2350- || key. matches ( "target.*.runner" )
2351- || key. matches ( "host.runner" )
2352- || key. matches ( "credential-alias.*" )
2353- || key. matches ( "doc.browser" )
2381+ fn is_nonmergeable_list ( key : & ConfigKey ) -> bool {
2382+ NON_MERGEABLE_LISTS . iter ( ) . any ( |l| key. matches ( l) )
23542383}
23552384
23562385pub fn homedir ( cwd : & Path ) -> Option < PathBuf > {
0 commit comments