Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/project-model/src/env.rs')
| -rw-r--r-- | crates/project-model/src/env.rs | 78 |
1 files changed, 61 insertions, 17 deletions
diff --git a/crates/project-model/src/env.rs b/crates/project-model/src/env.rs index d281492fc9..ae0458af7a 100644 --- a/crates/project-model/src/env.rs +++ b/crates/project-model/src/env.rs @@ -1,6 +1,7 @@ //! Cargo-like environment variables injection. use base_db::Env; use paths::Utf8Path; +use rustc_hash::FxHashMap; use toolchain::Tool; use crate::{ManifestPath, PackageData, TargetKind, cargo_config_file::CargoConfigFile}; @@ -60,8 +61,14 @@ pub(crate) fn inject_rustc_tool_env(env: &mut Env, cargo_name: &str, kind: Targe env.set("CARGO_CRATE_NAME", cargo_name.replace('-', "_")); } -pub(crate) fn cargo_config_env(manifest: &ManifestPath, config: &Option<CargoConfigFile>) -> Env { +pub(crate) fn cargo_config_env( + manifest: &ManifestPath, + config: &Option<CargoConfigFile>, + extra_env: &FxHashMap<String, Option<String>>, +) -> Env { let mut env = Env::default(); + env.extend(extra_env.iter().filter_map(|(k, v)| v.as_ref().map(|v| (k.clone(), v.clone())))); + let Some(serde_json::Value::Object(env_json)) = config.as_ref().and_then(|c| c.get("env")) else { return env; @@ -72,22 +79,34 @@ pub(crate) fn cargo_config_env(manifest: &ManifestPath, config: &Option<CargoCon let base = <_ as AsRef<Utf8Path>>::as_ref(manifest.parent()); for (key, entry) in env_json { - let serde_json::Value::Object(entry) = entry else { - continue; - }; - let Some(value) = entry.get("value").and_then(|v| v.as_str()) else { - continue; - }; + let value = match entry { + serde_json::Value::String(s) => s.clone(), + serde_json::Value::Object(entry) => { + // Each entry MUST have a `value` key. + let Some(value) = entry.get("value").and_then(|v| v.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_bool()).unwrap_or(false) + { + continue; + } - let value = if entry - .get("relative") - .and_then(|v| v.as_bool()) - .is_some_and(std::convert::identity) - { - base.join(value).to_string() - } else { - value.to_owned() + if entry + .get("relative") + .and_then(|v| v.as_bool()) + .is_some_and(std::convert::identity) + { + base.join(value).to_string() + } else { + value.to_owned() + } + } + _ => continue, }; + env.insert(key, value); } @@ -113,7 +132,19 @@ fn parse_output_cargo_config_env_works() { }, "TEST": { "value": "test" - } + }, + "FORCED": { + "value": "test", + "force": true + }, + "UNFORCED": { + "value": "test", + "force": false + }, + "OVERWRITTEN": { + "value": "test" + }, + "NOT_AN_OBJECT": "value" } } "#; @@ -121,9 +152,22 @@ fn parse_output_cargo_config_env_works() { let cwd = paths::Utf8PathBuf::try_from(std::env::current_dir().unwrap()).unwrap(); let manifest = paths::AbsPathBuf::assert(cwd.join("Cargo.toml")); let manifest = ManifestPath::try_from(manifest).unwrap(); - let env = cargo_config_env(&manifest, &Some(config)); + let extra_env = [ + ("FORCED", Some("ignored")), + ("UNFORCED", Some("newvalue")), + ("OVERWRITTEN", Some("newvalue")), + ("TEST", None), + ] + .iter() + .map(|(k, v)| (k.to_string(), v.map(ToString::to_string))) + .collect(); + let env = cargo_config_env(&manifest, &Some(config), &extra_env); assert_eq!(env.get("CARGO_WORKSPACE_DIR").as_deref(), Some(cwd.join("").as_str())); assert_eq!(env.get("RELATIVE").as_deref(), Some(cwd.join("../relative").as_str())); assert_eq!(env.get("INVALID").as_deref(), Some("../relative")); assert_eq!(env.get("TEST").as_deref(), Some("test")); + assert_eq!(env.get("FORCED").as_deref(), Some("test")); + assert_eq!(env.get("UNFORCED").as_deref(), Some("newvalue")); + assert_eq!(env.get("OVERWRITTEN").as_deref(), Some("newvalue")); + assert_eq!(env.get("NOT_AN_OBJECT").as_deref(), Some("value")); } |