Skip to content

Commit

Permalink
refactor: env_config supports resolve case insensitive env.
Browse files Browse the repository at this point in the history
  • Loading branch information
linyihai committed Nov 4, 2024
1 parent ab9438f commit 697a206
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 39 deletions.
8 changes: 5 additions & 3 deletions src/cargo/core/compiler/fingerprint/dep_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -294,7 +294,7 @@ pub fn translate_dep_info(
target_root: &Path,
rustc_cmd: &ProcessBuilder,
allow_package: bool,
env_config: &Arc<HashMap<String, OsString>>,
env_config: &Arc<EnvConfigResolved>,
) -> CargoResult<()> {
let depinfo = parse_rustc_dep_info(rustc_dep_info)?;

Expand Down Expand Up @@ -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| {
Expand Down
51 changes: 21 additions & 30 deletions src/cargo/core/compiler/fingerprint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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};
Expand Down Expand Up @@ -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<K: AsRef<str>>(
key: K,
env_config: &Arc<HashMap<String, OsString>>,
env_config_insensitive: &Arc<OnceCell<HashMap<String, OsString>>>,
) -> LocalFingerprint {
fn from_env<K: AsRef<str>>(key: K, env_config: &Arc<EnvConfigResolved>) -> 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()
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -1797,7 +1789,7 @@ fn local_fingerprints_deps(
deps: &BuildDeps,
target_root: &Path,
pkg_root: &Path,
env_config: &Arc<HashMap<String, OsString>>,
env_config: &Arc<EnvConfigResolved>,
) -> Vec<LocalFingerprint> {
debug!("new local fingerprints deps {:?}", pkg_root);
let mut local = Vec::new();
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
33 changes: 28 additions & 5 deletions src/cargo/util/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -227,7 +228,7 @@ pub struct GlobalContext {
target_cfgs: LazyCell<Vec<(String, TargetCfgConfig)>>,
doc_extern_map: LazyCell<RustdocExternMap>,
progress_config: ProgressConfig,
env_config: LazyCell<Arc<HashMap<String, OsString>>>,
env_config: LazyCell<Arc<EnvConfigResolved>>,
/// 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`
Expand Down Expand Up @@ -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<HashMap<String, OsString>>> {
pub fn env_config(&self) -> CargoResult<&Arc<EnvConfigResolved>> {
let env_config = self.env_config.try_borrow_with(|| {
CargoResult::Ok(Arc::new({
let env_config = self.get::<EnvConfig>("env")?;
Expand All @@ -1862,7 +1863,7 @@ impl GlobalContext {
);
}
}
env_config
let env_config: HashMap<String, OsString> = env_config
.into_iter()
.filter_map(|(k, v)| {
if v.is_force() || self.get_env_os(&k).is_none() {
Expand All @@ -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,
}
}))
})?;

Expand Down Expand Up @@ -2867,7 +2884,13 @@ impl EnvConfigValue {
}
}

pub type EnvConfig = HashMap<String, EnvConfigValue>;
type EnvConfig = HashMap<String, EnvConfigValue>;

#[derive(Debug)]
pub struct EnvConfigResolved {
pub case_insensitive_env: Option<HashMap<UncasedAscii<String>, OsString>>,
pub env: HashMap<String, OsString>,
}

fn parse_document(toml: &str, _file: &Path, _gctx: &GlobalContext) -> CargoResult<toml::Table> {
// At the moment, no compatibility checks are needed.
Expand Down

0 comments on commit 697a206

Please sign in to comment.