Unnamed repository; edit this file 'description' to name the repository.
Fix [env] in .cargo/config.toml overriding process environment variables
cargo_config_env() only checked extra_env (rust-analyzer.cargo.extraEnv) when deciding whether to skip an existing variable, but never checked the actual process environment via std::env::var. This caused config.toml values to unconditionally override real environment variables even without force = true, diverging from Cargo's behavior. Additionally, plain string entries (e.g. `KEY = "value"`) skipped the force check entirely. When a process env var takes precedence, its value is now inserted into the Env so that env!/option_env! resolution stays correct. Fixes rust-lang/rust-analyzer#21994
smihica 6 weeks ago
parent ea1a153 · commit 6093315
-rw-r--r--crates/project-model/src/env.rs27
1 files changed, 20 insertions, 7 deletions
diff --git a/crates/project-model/src/env.rs b/crates/project-model/src/env.rs
index 8375215136..1a660fbf5b 100644
--- a/crates/project-model/src/env.rs
+++ b/crates/project-model/src/env.rs
@@ -79,18 +79,31 @@ pub(crate) fn cargo_config_env(
for (key, entry) in env_toml {
let key = key.as_ref().as_ref();
let value = match entry.as_ref() {
- DeValue::String(s) => String::from(s.clone()),
+ DeValue::String(s) => {
+ // Plain string entries have no `force` option, so they should not
+ // override existing environment variables (matching Cargo behavior).
+ if extra_env.get(key).is_some_and(Option::is_some) {
+ continue;
+ }
+ if let Ok(val) = std::env::var(key) { val } else { String::from(s.clone()) }
+ }
DeValue::Table(entry) => {
// Each entry MUST have a `value` key.
let Some(map) = entry.get("value").and_then(|v| v.as_ref().as_str()) else {
continue;
};
- // If the entry already exists in the environment AND the `force` key is not set to
- // true, then don't overwrite the value.
- if extra_env.get(key).is_some_and(Option::is_some)
- && !entry.get("force").and_then(|v| v.as_ref().as_bool()).unwrap_or(false)
- {
- continue;
+ let is_forced =
+ entry.get("force").and_then(|v| v.as_ref().as_bool()).unwrap_or(false);
+ // If the entry already exists in the environment AND the `force` key is not set
+ // to true, use the existing value instead of the config value.
+ if !is_forced {
+ if extra_env.get(key).is_some_and(Option::is_some) {
+ continue;
+ }
+ if let Ok(val) = std::env::var(key) {
+ env.insert(key, val);
+ continue;
+ }
}
if let Some(base) = entry.get("relative").and_then(|v| {