44mod conv;
55
66use std:: {
7- env, error , fmt ,
8- io:: { BufRead , BufReader } ,
7+ env,
8+ io:: { self , BufRead , BufReader } ,
99 path:: PathBuf ,
1010 process:: { Command , Stdio } ,
1111 time:: Instant ,
@@ -23,10 +23,9 @@ use crate::conv::{map_rust_diagnostic_to_lsp, MappedRustDiagnostic};
2323pub use crate :: conv:: url_from_path_with_drive_lowercasing;
2424
2525#[ derive( Clone , Debug ) ]
26- pub struct FlycheckConfig {
27- pub command : String ,
28- pub all_targets : bool ,
29- pub extra_args : Vec < String > ,
26+ pub enum FlycheckConfig {
27+ CargoCommand { command : String , all_targets : bool , extra_args : Vec < String > } ,
28+ CustomCommand { command : String , args : Vec < String > } ,
3029}
3130
3231/// Flycheck wraps the shared state and communication machinery used for
@@ -215,18 +214,25 @@ impl FlycheckThread {
215214 self . message_recv = never ( ) ;
216215 self . check_process = None ;
217216
218- let cmd = {
219- let mut cmd = Command :: new ( cargo_binary ( ) ) ;
220- cmd. arg ( & self . config . command ) ;
221- cmd. args ( & [ "--workspace" , "--message-format=json" , "--manifest-path" ] ) ;
222- cmd. arg ( self . workspace_root . join ( "Cargo.toml" ) ) ;
223- if self . config . all_targets {
224- cmd. arg ( "--all-targets" ) ;
217+ let mut cmd = match & self . config {
218+ FlycheckConfig :: CargoCommand { command, all_targets, extra_args } => {
219+ let mut cmd = Command :: new ( cargo_binary ( ) ) ;
220+ cmd. arg ( command) ;
221+ cmd. args ( & [ "--workspace" , "--message-format=json" , "--manifest-path" ] ) ;
222+ cmd. arg ( self . workspace_root . join ( "Cargo.toml" ) ) ;
223+ if * all_targets {
224+ cmd. arg ( "--all-targets" ) ;
225+ }
226+ cmd. args ( extra_args) ;
227+ cmd
228+ }
229+ FlycheckConfig :: CustomCommand { command, args } => {
230+ let mut cmd = Command :: new ( command) ;
231+ cmd. args ( args) ;
232+ cmd
225233 }
226- cmd. args ( self . config . extra_args . iter ( ) ) ;
227- cmd. current_dir ( & self . workspace_root ) ;
228- cmd
229234 } ;
235+ cmd. current_dir ( & self . workspace_root ) ;
230236
231237 let ( message_send, message_recv) = unbounded ( ) ;
232238 self . message_recv = message_recv;
@@ -273,27 +279,12 @@ enum CheckEvent {
273279 End ,
274280}
275281
276- #[ derive( Debug ) ]
277- pub struct CargoError ( String ) ;
278-
279- impl fmt:: Display for CargoError {
280- fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
281- write ! ( f, "Cargo failed: {}" , self . 0 )
282- }
283- }
284- impl error:: Error for CargoError { }
285-
286282fn run_cargo (
287283 mut command : Command ,
288284 on_message : & mut dyn FnMut ( cargo_metadata:: Message ) -> bool ,
289- ) -> Result < ( ) , CargoError > {
290- dbg ! ( & command) ;
291- let mut child = command
292- . stdout ( Stdio :: piped ( ) )
293- . stderr ( Stdio :: null ( ) )
294- . stdin ( Stdio :: null ( ) )
295- . spawn ( )
296- . expect ( "couldn't launch cargo" ) ;
285+ ) -> io:: Result < ( ) > {
286+ let mut child =
287+ command. stdout ( Stdio :: piped ( ) ) . stderr ( Stdio :: null ( ) ) . stdin ( Stdio :: null ( ) ) . spawn ( ) ?;
297288
298289 // We manually read a line at a time, instead of using serde's
299290 // stream deserializers, because the deserializer cannot recover
@@ -307,13 +298,7 @@ fn run_cargo(
307298 let mut read_at_least_one_message = false ;
308299
309300 for line in stdout. lines ( ) {
310- let line = match line {
311- Ok ( line) => line,
312- Err ( err) => {
313- log:: error!( "Couldn't read line from cargo: {}" , err) ;
314- continue ;
315- }
316- } ;
301+ let line = line?;
317302
318303 let message = serde_json:: from_str :: < cargo_metadata:: Message > ( & line) ;
319304 let message = match message {
@@ -334,20 +319,20 @@ fn run_cargo(
334319 // It is okay to ignore the result, as it only errors if the process is already dead
335320 let _ = child. kill ( ) ;
336321
337- let err_msg = match child. wait ( ) {
338- Ok ( exit_code) if !exit_code. success ( ) && !read_at_least_one_message => {
339- // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment:
340- // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298
322+ let exit_status = child. wait ( ) ?;
323+ if !exit_status. success ( ) && !read_at_least_one_message {
324+ // FIXME: Read the stderr to display the reason, see `read2()` reference in PR comment:
325+ // https://github.com/rust-analyzer/rust-analyzer/pull/3632#discussion_r395605298
326+ return Err ( io:: Error :: new (
327+ io:: ErrorKind :: Other ,
341328 format ! (
342329 "the command produced no valid metadata (exit code: {:?}): {:?}" ,
343- exit_code, command
344- )
345- }
346- Err ( err) => format ! ( "io error: {:?}" , err) ,
347- Ok ( _) => return Ok ( ( ) ) ,
348- } ;
330+ exit_status, command
331+ ) ,
332+ ) ) ;
333+ }
349334
350- Err ( CargoError ( err_msg ) )
335+ Ok ( ( ) )
351336}
352337
353338fn cargo_binary ( ) -> String {
0 commit comments