@@ -201,8 +201,12 @@ pub struct Config {
201
201
target_dir : Option < Filesystem > ,
202
202
/// Environment variables, separated to assist testing.
203
203
env : HashMap < OsString , OsString > ,
204
- /// Environment variables, converted to uppercase to check for case mismatch
205
- upper_case_env : HashMap < String , String > ,
204
+ /// Environment variables converted to uppercase to check for case mismatch
205
+ /// (relevant on Windows, where environment variables are case-insensitive).
206
+ case_insensitive_env : HashMap < OsString , OsString > ,
207
+ /// Environment variables converted to uppercase and with "-" replaced by "_"
208
+ /// (the format expected by Cargo).
209
+ normalized_env : HashMap < String , String > ,
206
210
/// Tracks which sources have been updated to avoid multiple updates.
207
211
updated_sources : LazyCell < RefCell < HashSet < SourceId > > > ,
208
212
/// Cache of credentials from configuration or credential providers.
@@ -262,10 +266,16 @@ impl Config {
262
266
263
267
let env: HashMap < _ , _ > = env:: vars_os ( ) . collect ( ) ;
264
268
265
- let upper_case_env = env
269
+ let case_insensitive_env: HashMap < _ , _ > = env
270
+ . keys ( )
271
+ . map ( |k| ( k. to_ascii_uppercase ( ) , k. to_owned ( ) ) )
272
+ . collect ( ) ;
273
+
274
+ let normalized_env = env
266
275
. iter ( )
267
- . filter_map ( |( k, _) | k. to_str ( ) ) // Only keep valid UTF-8
268
- . map ( |k| ( k. to_uppercase ( ) . replace ( "-" , "_" ) , k. to_owned ( ) ) )
276
+ // Only keep entries where both the key and value are valid UTF-8
277
+ . filter_map ( |( k, v) | Some ( ( k. to_str ( ) ?, v. to_str ( ) ?) ) )
278
+ . map ( |( k, _) | ( k. to_uppercase ( ) . replace ( "-" , "_" ) , k. to_owned ( ) ) )
269
279
. collect ( ) ;
270
280
271
281
let cache_key: & OsStr = "CARGO_CACHE_RUSTC_INFO" . as_ref ( ) ;
@@ -303,7 +313,8 @@ impl Config {
303
313
creation_time : Instant :: now ( ) ,
304
314
target_dir : None ,
305
315
env,
306
- upper_case_env,
316
+ case_insensitive_env,
317
+ normalized_env,
307
318
updated_sources : LazyCell :: new ( ) ,
308
319
credential_cache : LazyCell :: new ( ) ,
309
320
package_cache_lock : RefCell :: new ( None ) ,
@@ -772,10 +783,10 @@ impl Config {
772
783
/// This can be used similarly to `std::env::var`.
773
784
pub fn get_env ( & self , key : impl AsRef < OsStr > ) -> CargoResult < String > {
774
785
let key = key. as_ref ( ) ;
775
- let s = match self . env . get ( key ) {
776
- Some ( s ) => s ,
777
- None => bail ! ( "{key:?} could not be found in the environment snapshot" , ) ,
778
- } ;
786
+ let s = self
787
+ . get_env_os ( key )
788
+ . ok_or_else ( || anyhow ! ( "{key:?} could not be found in the environment snapshot" ) ) ? ;
789
+
779
790
match s. to_str ( ) {
780
791
Some ( s) => Ok ( s. to_owned ( ) ) ,
781
792
None => bail ! ( "environment variable value is not valid unicode: {s:?}" ) ,
@@ -786,7 +797,26 @@ impl Config {
786
797
///
787
798
/// This can be used similarly to `std::env::var_os`.
788
799
pub fn get_env_os ( & self , key : impl AsRef < OsStr > ) -> Option < OsString > {
789
- self . env . get ( key. as_ref ( ) ) . cloned ( )
800
+ match self . env . get ( key. as_ref ( ) ) {
801
+ Some ( s) => Some ( s. clone ( ) ) ,
802
+ None => {
803
+ if cfg ! ( windows) {
804
+ self . get_env_case_insensitive ( key) . cloned ( )
805
+ } else {
806
+ None
807
+ }
808
+ }
809
+ }
810
+ }
811
+
812
+ /// Wrapper for `self.env.get` when `key` should be case-insensitive.
813
+ /// This is relevant on Windows, where environment variables are case-insensitive.
814
+ fn get_env_case_insensitive ( & self , key : impl AsRef < OsStr > ) -> Option < & OsString > {
815
+ let upper_case_key = key. as_ref ( ) . to_ascii_uppercase ( ) ;
816
+ // `self.case_insensitive_env` holds pairs like `("PATH", "Path")`
817
+ // or `("MY-VAR", "my-var")`.
818
+ let env_key = self . case_insensitive_env . get ( & upper_case_key) ?;
819
+ self . env . get ( env_key)
790
820
}
791
821
792
822
/// Get the value of environment variable `key`.
@@ -821,7 +851,7 @@ impl Config {
821
851
}
822
852
823
853
fn check_environment_key_case_mismatch ( & self , key : & ConfigKey ) {
824
- if let Some ( env_key) = self . upper_case_env . get ( key. as_env_key ( ) ) {
854
+ if let Some ( env_key) = self . normalized_env . get ( key. as_env_key ( ) ) {
825
855
let _ = self . shell ( ) . warn ( format ! (
826
856
"Environment variables are expected to use uppercase letters and underscores, \
827
857
the variable `{}` will be ignored and have no effect",
0 commit comments