|
1 | 1 | //! Cargo-like environment variables injection.
|
2 | 2 | use base_db::Env;
|
3 |
| -use paths::{Utf8Path, Utf8PathBuf}; |
4 |
| -use rustc_hash::FxHashMap; |
| 3 | +use paths::Utf8Path; |
5 | 4 | use toolchain::Tool;
|
6 | 5 |
|
7 |
| -use crate::{ManifestPath, PackageData, Sysroot, TargetKind, utf8_stdout}; |
| 6 | +use crate::{ManifestPath, PackageData, TargetKind, cargo_config_file::CargoConfigFile}; |
8 | 7 |
|
9 | 8 | /// Recreates the compile-time environment variables that Cargo sets.
|
10 | 9 | ///
|
@@ -61,104 +60,68 @@ pub(crate) fn inject_rustc_tool_env(env: &mut Env, cargo_name: &str, kind: Targe
|
61 | 60 | env.set("CARGO_CRATE_NAME", cargo_name.replace('-', "_"));
|
62 | 61 | }
|
63 | 62 |
|
64 |
| -pub(crate) fn cargo_config_env( |
65 |
| - manifest: &ManifestPath, |
66 |
| - extra_env: &FxHashMap<String, Option<String>>, |
67 |
| - sysroot: &Sysroot, |
68 |
| -) -> Env { |
69 |
| - let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env); |
70 |
| - cargo_config |
71 |
| - .args(["-Z", "unstable-options", "config", "get", "env"]) |
72 |
| - .env("RUSTC_BOOTSTRAP", "1"); |
73 |
| - if manifest.is_rust_manifest() { |
74 |
| - cargo_config.arg("-Zscript"); |
75 |
| - } |
76 |
| - // if successful we receive `env.key.value = "value" per entry |
77 |
| - tracing::debug!("Discovering cargo config env by {:?}", cargo_config); |
78 |
| - utf8_stdout(&mut cargo_config) |
79 |
| - .map(|stdout| parse_output_cargo_config_env(manifest, &stdout)) |
80 |
| - .inspect(|env| { |
81 |
| - tracing::debug!("Discovered cargo config env: {:?}", env); |
82 |
| - }) |
83 |
| - .inspect_err(|err| { |
84 |
| - tracing::debug!("Failed to discover cargo config env: {:?}", err); |
85 |
| - }) |
86 |
| - .unwrap_or_default() |
87 |
| -} |
88 |
| - |
89 |
| -fn parse_output_cargo_config_env(manifest: &ManifestPath, stdout: &str) -> Env { |
| 63 | +pub(crate) fn cargo_config_env(manifest: &ManifestPath, config: &Option<CargoConfigFile>) -> Env { |
90 | 64 | let mut env = Env::default();
|
91 |
| - let mut relatives = vec![]; |
92 |
| - for (key, val) in |
93 |
| - stdout.lines().filter_map(|l| l.strip_prefix("env.")).filter_map(|l| l.split_once(" = ")) |
94 |
| - { |
95 |
| - let val = val.trim_matches('"').to_owned(); |
96 |
| - if let Some((key, modifier)) = key.split_once('.') { |
97 |
| - match modifier { |
98 |
| - "relative" => relatives.push((key, val)), |
99 |
| - "value" => _ = env.insert(key, val), |
100 |
| - _ => { |
101 |
| - tracing::warn!( |
102 |
| - "Unknown modifier in cargo config env: {}, expected `relative` or `value`", |
103 |
| - modifier |
104 |
| - ); |
105 |
| - continue; |
106 |
| - } |
107 |
| - } |
108 |
| - } else { |
109 |
| - env.insert(key, val); |
110 |
| - } |
111 |
| - } |
| 65 | + let Some(serde_json::Value::Object(env_json)) = config.as_ref().and_then(|c| c.get("env")) |
| 66 | + else { |
| 67 | + return env; |
| 68 | + }; |
| 69 | + |
112 | 70 | // FIXME: The base here should be the parent of the `.cargo/config` file, not the manifest.
|
113 | 71 | // But cargo does not provide this information.
|
114 | 72 | let base = <_ as AsRef<Utf8Path>>::as_ref(manifest.parent());
|
115 |
| - for (key, relative) in relatives { |
116 |
| - if relative != "true" { |
| 73 | + |
| 74 | + for (key, entry) in env_json { |
| 75 | + let serde_json::Value::Object(entry) = entry else { |
117 | 76 | continue;
|
118 |
| - } |
119 |
| - if let Some(suffix) = env.get(key) { |
120 |
| - env.insert(key, base.join(suffix).to_string()); |
121 |
| - } |
122 |
| - } |
123 |
| - env |
124 |
| -} |
| 77 | + }; |
| 78 | + let Some(value) = entry.get("value").and_then(|v| v.as_str()) else { |
| 79 | + continue; |
| 80 | + }; |
125 | 81 |
|
126 |
| -pub(crate) fn cargo_config_build_target_dir( |
127 |
| - manifest: &ManifestPath, |
128 |
| - extra_env: &FxHashMap<String, Option<String>>, |
129 |
| - sysroot: &Sysroot, |
130 |
| -) -> Option<Utf8PathBuf> { |
131 |
| - let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent(), extra_env); |
132 |
| - cargo_config |
133 |
| - .args(["-Z", "unstable-options", "config", "get", "build.target-dir"]) |
134 |
| - .env("RUSTC_BOOTSTRAP", "1"); |
135 |
| - if manifest.is_rust_manifest() { |
136 |
| - cargo_config.arg("-Zscript"); |
| 82 | + let value = if entry |
| 83 | + .get("relative") |
| 84 | + .and_then(|v| v.as_bool()) |
| 85 | + .is_some_and(std::convert::identity) |
| 86 | + { |
| 87 | + base.join(value).to_string() |
| 88 | + } else { |
| 89 | + value.to_owned() |
| 90 | + }; |
| 91 | + env.insert(key, value); |
137 | 92 | }
|
138 |
| - utf8_stdout(&mut cargo_config) |
139 |
| - .map(|stdout| { |
140 |
| - Utf8Path::new(stdout.trim_start_matches("build.target-dir = ").trim_matches('"')) |
141 |
| - .to_owned() |
142 |
| - }) |
143 |
| - .ok() |
| 93 | + |
| 94 | + env |
144 | 95 | }
|
145 | 96 |
|
146 | 97 | #[test]
|
147 | 98 | fn parse_output_cargo_config_env_works() {
|
148 |
| - let stdout = r#" |
149 |
| -env.CARGO_WORKSPACE_DIR.relative = true |
150 |
| -env.CARGO_WORKSPACE_DIR.value = "" |
151 |
| -env.RELATIVE.relative = true |
152 |
| -env.RELATIVE.value = "../relative" |
153 |
| -env.INVALID.relative = invalidbool |
154 |
| -env.INVALID.value = "../relative" |
155 |
| -env.TEST.value = "test" |
156 |
| -"# |
157 |
| - .trim(); |
| 99 | + let raw = r#" |
| 100 | +{ |
| 101 | + "env": { |
| 102 | + "CARGO_WORKSPACE_DIR": { |
| 103 | + "relative": true, |
| 104 | + "value": "" |
| 105 | + }, |
| 106 | + "INVALID": { |
| 107 | + "relative": "invalidbool", |
| 108 | + "value": "../relative" |
| 109 | + }, |
| 110 | + "RELATIVE": { |
| 111 | + "relative": true, |
| 112 | + "value": "../relative" |
| 113 | + }, |
| 114 | + "TEST": { |
| 115 | + "value": "test" |
| 116 | + } |
| 117 | + } |
| 118 | +} |
| 119 | +"#; |
| 120 | + let config: CargoConfigFile = serde_json::from_str(raw).unwrap(); |
158 | 121 | let cwd = paths::Utf8PathBuf::try_from(std::env::current_dir().unwrap()).unwrap();
|
159 | 122 | let manifest = paths::AbsPathBuf::assert(cwd.join("Cargo.toml"));
|
160 | 123 | let manifest = ManifestPath::try_from(manifest).unwrap();
|
161 |
| - let env = parse_output_cargo_config_env(&manifest, stdout); |
| 124 | + let env = cargo_config_env(&manifest, &Some(config)); |
162 | 125 | assert_eq!(env.get("CARGO_WORKSPACE_DIR").as_deref(), Some(cwd.join("").as_str()));
|
163 | 126 | assert_eq!(env.get("RELATIVE").as_deref(), Some(cwd.join("../relative").as_str()));
|
164 | 127 | assert_eq!(env.get("INVALID").as_deref(), Some("../relative"));
|
|
0 commit comments