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.rs78
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"));
}