Skip to content

Commit 0255c30

Browse files
committed
store uppercased env var names; look for uppercased version on Windows when var is not in self.env
1 parent 8353396 commit 0255c30

File tree

1 file changed

+42
-12
lines changed

1 file changed

+42
-12
lines changed

src/cargo/util/config/mod.rs

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -201,8 +201,12 @@ pub struct Config {
201201
target_dir: Option<Filesystem>,
202202
/// Environment variables, separated to assist testing.
203203
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>,
206210
/// Tracks which sources have been updated to avoid multiple updates.
207211
updated_sources: LazyCell<RefCell<HashSet<SourceId>>>,
208212
/// Cache of credentials from configuration or credential providers.
@@ -262,10 +266,16 @@ impl Config {
262266

263267
let env: HashMap<_, _> = env::vars_os().collect();
264268

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
266275
.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()))
269279
.collect();
270280

271281
let cache_key: &OsStr = "CARGO_CACHE_RUSTC_INFO".as_ref();
@@ -303,7 +313,8 @@ impl Config {
303313
creation_time: Instant::now(),
304314
target_dir: None,
305315
env,
306-
upper_case_env,
316+
case_insensitive_env,
317+
normalized_env,
307318
updated_sources: LazyCell::new(),
308319
credential_cache: LazyCell::new(),
309320
package_cache_lock: RefCell::new(None),
@@ -772,10 +783,10 @@ impl Config {
772783
/// This can be used similarly to `std::env::var`.
773784
pub fn get_env(&self, key: impl AsRef<OsStr>) -> CargoResult<String> {
774785
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+
779790
match s.to_str() {
780791
Some(s) => Ok(s.to_owned()),
781792
None => bail!("environment variable value is not valid unicode: {s:?}"),
@@ -786,7 +797,26 @@ impl Config {
786797
///
787798
/// This can be used similarly to `std::env::var_os`.
788799
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)
790820
}
791821

792822
/// Get the value of environment variable `key`.
@@ -821,7 +851,7 @@ impl Config {
821851
}
822852

823853
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()) {
825855
let _ = self.shell().warn(format!(
826856
"Environment variables are expected to use uppercase letters and underscores, \
827857
the variable `{}` will be ignored and have no effect",

0 commit comments

Comments
 (0)