diff --git a/src/cargo/core/compiler/fingerprint/dep_info.rs b/src/cargo/core/compiler/fingerprint/dep_info.rs index e8628f34ebfd..7824cfcf9e0a 100644 --- a/src/cargo/core/compiler/fingerprint/dep_info.rs +++ b/src/cargo/core/compiler/fingerprint/dep_info.rs @@ -4,7 +4,6 @@ //! [the documentation]: crate::core::compiler::fingerprint#dep-info-files use std::collections::HashMap; -use std::ffi::OsString; use std::fmt; use std::io; use std::io::Read; @@ -19,6 +18,7 @@ use cargo_util::paths; use cargo_util::ProcessBuilder; use cargo_util::Sha256; +use crate::util::context::EnvConfigResolved; use crate::CargoResult; use crate::CARGO_ENV; @@ -294,7 +294,7 @@ pub fn translate_dep_info( target_root: &Path, rustc_cmd: &ProcessBuilder, allow_package: bool, - env_config: &Arc>, + env_config: &Arc, ) -> CargoResult<()> { let depinfo = parse_rustc_dep_info(rustc_dep_info)?; @@ -334,7 +334,9 @@ pub fn translate_dep_info( // // For cargo#13280, We trace env vars that are defined in the `[env]` config table. on_disk_info.env.retain(|(key, _)| { - env_config.contains_key(key) || !rustc_cmd.get_envs().contains_key(key) || key == CARGO_ENV + env_config.env.contains_key(key) + || !rustc_cmd.get_envs().contains_key(key) + || key == CARGO_ENV }); let serialize_path = |file| { diff --git a/src/cargo/core/compiler/fingerprint/mod.rs b/src/cargo/core/compiler/fingerprint/mod.rs index 37a61a1366b9..8e2a5740c660 100644 --- a/src/cargo/core/compiler/fingerprint/mod.rs +++ b/src/cargo/core/compiler/fingerprint/mod.rs @@ -362,10 +362,8 @@ mod dep_info; mod dirty_reason; -use std::cell::OnceCell; use std::collections::hash_map::{Entry, HashMap}; use std::env; -use std::ffi::OsString; use std::fs; use std::fs::File; use std::hash::{self, Hash, Hasher}; @@ -382,10 +380,12 @@ use serde::de; use serde::ser; use serde::{Deserialize, Serialize}; use tracing::{debug, info}; +use unicase::Ascii as UncasedAscii; use crate::core::compiler::unit_graph::UnitDep; use crate::core::Package; use crate::util; +use crate::util::context::EnvConfigResolved; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; use crate::util::{internal, path_args, StableHasher}; @@ -799,33 +799,25 @@ impl LocalFingerprint { /// Read the environment variable of the given env `key`, and creates a new /// [`LocalFingerprint::RerunIfEnvChanged`] for it. #[allow(clippy::disallowed_methods)] - fn from_env>( - key: K, - env_config: &Arc>, - env_config_insensitive: &Arc>>, - ) -> LocalFingerprint { + fn from_env>(key: K, env_config: &Arc) -> LocalFingerprint { let key = key.as_ref(); let var = key.to_owned(); - let val = if let Some(val) = match env_config.get(key) { - Some(value) => value.to_str().map(|s| str::to_string(s)), - None => { - if cfg!(windows) { - let env_config_insensitive = env_config_insensitive.get_or_init(|| { - env_config - .iter() - .map(|(k, v)| (k.to_uppercase().clone(), v.clone())) - .collect() - }); - let val = env_config_insensitive - .get(&key.to_uppercase()) - .and_then(|s| s.to_str().map(|s| str::to_string(s))); - - val - } else { - None + let val = if let Some(val) = + match env_config.env.get(key) { + Some(value) => value.to_str().map(|s| str::to_string(s)), + None => { + if cfg!(windows) { + let val = env_config.case_insensitive_env.as_ref().and_then( + |case_insensitive_env| { + case_insensitive_env.get(&UncasedAscii::new(str::to_string(key))) + }, + ); + val.and_then(|s| s.to_str().map(|s| str::to_string(s))) + } else { + None + } } - } - } { + } { Some(val) } else { env::var(key).ok() @@ -874,7 +866,7 @@ impl LocalFingerprint { ) })?) } else { - if let Some(value) = gctx.env_config()?.get(key) { + if let Some(value) = gctx.env_config()?.env.get(key) { value.to_str() } else { gctx.get_env(key).ok() @@ -1797,7 +1789,7 @@ fn local_fingerprints_deps( deps: &BuildDeps, target_root: &Path, pkg_root: &Path, - env_config: &Arc>, + env_config: &Arc, ) -> Vec { debug!("new local fingerprints deps {:?}", pkg_root); let mut local = Vec::new(); @@ -1818,11 +1810,10 @@ fn local_fingerprints_deps( .collect(); local.push(LocalFingerprint::RerunIfChanged { output, paths }); } - let env_config_insensitive = Arc::new(OnceCell::new()); local.extend( deps.rerun_if_env_changed .iter() - .map(|s| LocalFingerprint::from_env(s, env_config, &env_config_insensitive)), + .map(|s| LocalFingerprint::from_env(s, env_config)), ); local diff --git a/src/cargo/core/compiler/mod.rs b/src/cargo/core/compiler/mod.rs index 5d0e2962c22a..27a821f51db9 100644 --- a/src/cargo/core/compiler/mod.rs +++ b/src/cargo/core/compiler/mod.rs @@ -1983,7 +1983,7 @@ pub(crate) fn apply_env_config( gctx: &crate::GlobalContext, cmd: &mut ProcessBuilder, ) -> CargoResult<()> { - for (key, value) in gctx.env_config()?.iter() { + for (key, value) in gctx.env_config()?.env.iter() { // never override a value that has already been set by cargo if cmd.get_envs().contains_key(key) { continue; diff --git a/src/cargo/util/context/mod.rs b/src/cargo/util/context/mod.rs index 2403675db199..560723e27bb7 100644 --- a/src/cargo/util/context/mod.rs +++ b/src/cargo/util/context/mod.rs @@ -91,6 +91,7 @@ use serde::Deserialize; use serde_untagged::UntaggedEnumVisitor; use time::OffsetDateTime; use toml_edit::Item; +use unicase::Ascii as UncasedAscii; use url::Url; mod de; @@ -227,7 +228,7 @@ pub struct GlobalContext { target_cfgs: LazyCell>, doc_extern_map: LazyCell, progress_config: ProgressConfig, - env_config: LazyCell>>, + env_config: LazyCell>, /// This should be false if: /// - this is an artifact of the rustc distribution process for "stable" or for "beta" /// - this is an `#[test]` that does not opt in with `enable_nightly_features` @@ -1835,7 +1836,7 @@ impl GlobalContext { /// Get the env vars from the config `[env]` table which /// are `force = true` or don't exist in the env snapshot [`GlobalContext::get_env`]. - pub fn env_config(&self) -> CargoResult<&Arc>> { + pub fn env_config(&self) -> CargoResult<&Arc> { let env_config = self.env_config.try_borrow_with(|| { CargoResult::Ok(Arc::new({ let env_config = self.get::("env")?; @@ -1862,7 +1863,7 @@ impl GlobalContext { ); } } - env_config + let env_config: HashMap = env_config .into_iter() .filter_map(|(k, v)| { if v.is_force() || self.get_env_os(&k).is_none() { @@ -1871,7 +1872,23 @@ impl GlobalContext { None } }) - .collect() + .collect(); + EnvConfigResolved { + case_insensitive_env: { + if cfg!(windows) { + Some( + env_config + .clone() + .into_iter() + .map(|(k, v)| (UncasedAscii::new(k), v)) + .collect(), + ) + } else { + None + } + }, + env: env_config, + } })) })?; @@ -2867,7 +2884,13 @@ impl EnvConfigValue { } } -pub type EnvConfig = HashMap; +type EnvConfig = HashMap; + +#[derive(Debug)] +pub struct EnvConfigResolved { + pub case_insensitive_env: Option, OsString>>, + pub env: HashMap, +} fn parse_document(toml: &str, _file: &Path, _gctx: &GlobalContext) -> CargoResult { // At the moment, no compatibility checks are needed.