diff options
Diffstat (limited to 'crates/project_model/src')
-rw-r--r-- | crates/project_model/src/build_data.rs | 134 |
1 files changed, 76 insertions, 58 deletions
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs index ab5cc8c49..faca336de 100644 --- a/crates/project_model/src/build_data.rs +++ b/crates/project_model/src/build_data.rs | |||
@@ -1,7 +1,6 @@ | |||
1 | //! Handles build script specific information | 1 | //! Handles build script specific information |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | io::BufReader, | ||
5 | path::PathBuf, | 4 | path::PathBuf, |
6 | process::{Command, Stdio}, | 5 | process::{Command, Stdio}, |
7 | sync::Arc, | 6 | sync::Arc, |
@@ -13,7 +12,8 @@ use cargo_metadata::{BuildScript, Message}; | |||
13 | use itertools::Itertools; | 12 | use itertools::Itertools; |
14 | use paths::{AbsPath, AbsPathBuf}; | 13 | use paths::{AbsPath, AbsPathBuf}; |
15 | use rustc_hash::FxHashMap; | 14 | use rustc_hash::FxHashMap; |
16 | use stdx::{format_to, JodChild}; | 15 | use serde::Deserialize; |
16 | use stdx::format_to; | ||
17 | 17 | ||
18 | use crate::{cfg_flag::CfgFlag, CargoConfig}; | 18 | use crate::{cfg_flag::CfgFlag, CargoConfig}; |
19 | 19 | ||
@@ -171,67 +171,86 @@ impl WorkspaceBuildData { | |||
171 | 171 | ||
172 | cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); | 172 | cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null()); |
173 | 173 | ||
174 | let mut child = cmd.spawn().map(JodChild)?; | ||
175 | let child_stdout = child.stdout.take().unwrap(); | ||
176 | let stdout = BufReader::new(child_stdout); | ||
177 | |||
178 | let mut res = WorkspaceBuildData::default(); | 174 | let mut res = WorkspaceBuildData::default(); |
179 | for message in cargo_metadata::Message::parse_stream(stdout).flatten() { | ||
180 | match message { | ||
181 | Message::BuildScriptExecuted(BuildScript { | ||
182 | package_id, | ||
183 | out_dir, | ||
184 | cfgs, | ||
185 | env, | ||
186 | .. | ||
187 | }) => { | ||
188 | let cfgs = { | ||
189 | let mut acc = Vec::new(); | ||
190 | for cfg in cfgs { | ||
191 | match cfg.parse::<CfgFlag>() { | ||
192 | Ok(it) => acc.push(it), | ||
193 | Err(err) => { | ||
194 | anyhow::bail!("invalid cfg from cargo-metadata: {}", err) | ||
195 | } | ||
196 | }; | ||
197 | } | ||
198 | acc | ||
199 | }; | ||
200 | let package_build_data = | ||
201 | res.per_package.entry(package_id.repr.clone()).or_default(); | ||
202 | // cargo_metadata crate returns default (empty) path for | ||
203 | // older cargos, which is not absolute, so work around that. | ||
204 | if !out_dir.as_str().is_empty() { | ||
205 | let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string())); | ||
206 | package_build_data.out_dir = Some(out_dir); | ||
207 | package_build_data.cfgs = cfgs; | ||
208 | } | ||
209 | 175 | ||
210 | package_build_data.envs = env; | 176 | let mut callback_err = None; |
177 | let output = stdx::process::streaming_output( | ||
178 | cmd, | ||
179 | &mut |line| { | ||
180 | if callback_err.is_some() { | ||
181 | return; | ||
211 | } | 182 | } |
212 | Message::CompilerArtifact(message) => { | 183 | |
213 | progress(format!("metadata {}", message.target.name)); | 184 | // Copy-pasted from existing cargo_metadata. It seems like we |
214 | 185 | // should be using sered_stacker here? | |
215 | if message.target.kind.contains(&"proc-macro".to_string()) { | 186 | let mut deserializer = serde_json::Deserializer::from_str(&line); |
216 | let package_id = message.package_id; | 187 | deserializer.disable_recursion_limit(); |
217 | // Skip rmeta file | 188 | let message = Message::deserialize(&mut deserializer) |
218 | if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) | 189 | .unwrap_or(Message::TextLine(line.to_string())); |
219 | { | 190 | |
220 | let filename = AbsPathBuf::assert(PathBuf::from(&filename)); | 191 | match message { |
221 | let package_build_data = | 192 | Message::BuildScriptExecuted(BuildScript { |
222 | res.per_package.entry(package_id.repr.clone()).or_default(); | 193 | package_id, |
223 | package_build_data.proc_macro_dylib_path = Some(filename); | 194 | out_dir, |
195 | cfgs, | ||
196 | env, | ||
197 | .. | ||
198 | }) => { | ||
199 | let cfgs = { | ||
200 | let mut acc = Vec::new(); | ||
201 | for cfg in cfgs { | ||
202 | match cfg.parse::<CfgFlag>() { | ||
203 | Ok(it) => acc.push(it), | ||
204 | Err(err) => { | ||
205 | callback_err = Some(anyhow::format_err!( | ||
206 | "invalid cfg from cargo-metadata: {}", | ||
207 | err | ||
208 | )); | ||
209 | return; | ||
210 | } | ||
211 | }; | ||
212 | } | ||
213 | acc | ||
214 | }; | ||
215 | let package_build_data = | ||
216 | res.per_package.entry(package_id.repr.clone()).or_default(); | ||
217 | // cargo_metadata crate returns default (empty) path for | ||
218 | // older cargos, which is not absolute, so work around that. | ||
219 | if !out_dir.as_str().is_empty() { | ||
220 | let out_dir = | ||
221 | AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string())); | ||
222 | package_build_data.out_dir = Some(out_dir); | ||
223 | package_build_data.cfgs = cfgs; | ||
224 | } | 224 | } |
225 | |||
226 | package_build_data.envs = env; | ||
225 | } | 227 | } |
228 | Message::CompilerArtifact(message) => { | ||
229 | progress(format!("metadata {}", message.target.name)); | ||
230 | |||
231 | if message.target.kind.contains(&"proc-macro".to_string()) { | ||
232 | let package_id = message.package_id; | ||
233 | // Skip rmeta file | ||
234 | if let Some(filename) = | ||
235 | message.filenames.iter().find(|name| is_dylib(name)) | ||
236 | { | ||
237 | let filename = AbsPathBuf::assert(PathBuf::from(&filename)); | ||
238 | let package_build_data = | ||
239 | res.per_package.entry(package_id.repr.clone()).or_default(); | ||
240 | package_build_data.proc_macro_dylib_path = Some(filename); | ||
241 | } | ||
242 | } | ||
243 | } | ||
244 | Message::CompilerMessage(message) => { | ||
245 | progress(message.target.name.clone()); | ||
246 | } | ||
247 | Message::BuildFinished(_) => {} | ||
248 | Message::TextLine(_) => {} | ||
249 | _ => {} | ||
226 | } | 250 | } |
227 | Message::CompilerMessage(message) => { | 251 | }, |
228 | progress(message.target.name.clone()); | 252 | &mut |_| (), |
229 | } | 253 | )?; |
230 | Message::BuildFinished(_) => {} | ||
231 | Message::TextLine(_) => {} | ||
232 | _ => {} | ||
233 | } | ||
234 | } | ||
235 | 254 | ||
236 | for package in packages { | 255 | for package in packages { |
237 | let package_build_data = res.per_package.entry(package.id.repr.clone()).or_default(); | 256 | let package_build_data = res.per_package.entry(package.id.repr.clone()).or_default(); |
@@ -244,7 +263,6 @@ impl WorkspaceBuildData { | |||
244 | } | 263 | } |
245 | } | 264 | } |
246 | 265 | ||
247 | let output = child.into_inner().wait_with_output()?; | ||
248 | if !output.status.success() { | 266 | if !output.status.success() { |
249 | let mut stderr = String::from_utf8(output.stderr).unwrap_or_default(); | 267 | let mut stderr = String::from_utf8(output.stderr).unwrap_or_default(); |
250 | if stderr.is_empty() { | 268 | if stderr.is_empty() { |