1
1
//! Handles build script specific information
2
2
3
3
use std:: {
4
- io:: BufReader ,
5
4
path:: PathBuf ,
6
5
process:: { Command , Stdio } ,
7
6
sync:: Arc ,
@@ -13,7 +12,8 @@ use cargo_metadata::{BuildScript, Message};
13
12
use itertools:: Itertools ;
14
13
use paths:: { AbsPath , AbsPathBuf } ;
15
14
use rustc_hash:: FxHashMap ;
16
- use stdx:: { format_to, JodChild } ;
15
+ use serde:: Deserialize ;
16
+ use stdx:: format_to;
17
17
18
18
use crate :: { cfg_flag:: CfgFlag , CargoConfig } ;
19
19
@@ -171,67 +171,86 @@ impl WorkspaceBuildData {
171
171
172
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
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) => {
213
- progress ( format ! ( "metadata {}" , message. target. name) ) ;
214
-
215
- if message. target . kind . contains ( & "proc-macro" . to_string ( ) ) {
216
- let package_id = message. package_id ;
217
- // Skip rmeta file
218
- if let Some ( filename) = message. filenames . iter ( ) . find ( |name| is_dylib ( name) )
219
- {
220
- let filename = AbsPathBuf :: assert ( PathBuf :: from ( & filename) ) ;
221
- let package_build_data =
222
- res. per_package . entry ( package_id. repr . clone ( ) ) . or_default ( ) ;
223
- package_build_data. proc_macro_dylib_path = Some ( filename) ;
183
+
184
+ // Copy-pasted from existing cargo_metadata. It seems like we
185
+ // should be using sered_stacker here?
186
+ let mut deserializer = serde_json:: Deserializer :: from_str ( & line) ;
187
+ deserializer. disable_recursion_limit ( ) ;
188
+ let message = Message :: deserialize ( & mut deserializer)
189
+ . unwrap_or ( Message :: TextLine ( line. to_string ( ) ) ) ;
190
+
191
+ match message {
192
+ Message :: BuildScriptExecuted ( BuildScript {
193
+ package_id,
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) => {
228
- progress ( message. target . name . clone ( ) ) ;
229
- }
230
- Message :: BuildFinished ( _) => { }
231
- Message :: TextLine ( _) => { }
232
- _ => { }
233
- }
234
- }
251
+ } ,
252
+ & mut |_| ( ) ,
253
+ ) ?;
235
254
236
255
for package in packages {
237
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
266
if !output. status . success ( ) {
249
267
let mut stderr = String :: from_utf8 ( output. stderr ) . unwrap_or_default ( ) ;
250
268
if stderr. is_empty ( ) {
0 commit comments