@@ -546,66 +546,84 @@ impl Solc {
546546 Ok ( out)
547547 }
548548
549- /// Run `solc --stand-json` and return the `solc`'s output as
550- /// `CompilerOutput`
549+ /// Compiles with `--standard-json` and deserializes the output as [`CompilerOutput`].
551550 ///
552551 /// # Example
553552 ///
554553 /// ```no_run
555- /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
556554 /// use foundry_compilers::{CompilerInput, Solc};
555+ ///
557556 /// let solc = Solc::default();
558557 /// let input = CompilerInput::new("./contracts")?;
559558 /// let output = solc.compile(&input)?;
560- /// # Ok(())
561- /// # }
559+ /// # Ok::<_, foundry_compilers::error::SolcError>(())
562560 /// ```
563- pub fn compile < T : Serialize > ( & self , input : & T ) -> Result < CompilerOutput > {
561+ pub fn compile < T : Serialize + std :: fmt :: Debug > ( & self , input : & T ) -> Result < CompilerOutput > {
564562 self . compile_as ( input)
565563 }
566564
567- /// Run `solc --stand-json` and return the `solc`'s output as the given json
568- /// output
569- pub fn compile_as < T : Serialize , D : DeserializeOwned > ( & self , input : & T ) -> Result < D > {
565+ /// Compiles with `--standard-json` and deserializes the output as the given `D`.
566+ pub fn compile_as < T : Serialize + std:: fmt:: Debug , D : DeserializeOwned > (
567+ & self ,
568+ input : & T ,
569+ ) -> Result < D > {
570570 let output = self . compile_output ( input) ?;
571- Ok ( serde_json:: from_slice ( & output) ?)
571+
572+ // Only run UTF-8 validation once.
573+ let output = std:: str:: from_utf8 ( & output) . map_err ( |_| SolcError :: InvalidUtf8 ) ?;
574+
575+ Ok ( serde_json:: from_str ( output) ?)
572576 }
573577
574- pub fn compile_output < T : Serialize > ( & self , input : & T ) -> Result < Vec < u8 > > {
578+ /// Compiles with `--standard-json` and returns the raw `stdout` output.
579+ #[ instrument( name = "compile" , level = "debug" , skip_all) ]
580+ pub fn compile_output < T : Serialize + std:: fmt:: Debug > ( & self , input : & T ) -> Result < Vec < u8 > > {
575581 let mut cmd = Command :: new ( & self . solc ) ;
576- if let Some ( ref base_path) = self . base_path {
582+ if let Some ( base_path) = & self . base_path {
577583 cmd. current_dir ( base_path) ;
578584 cmd. arg ( "--base-path" ) . arg ( base_path) ;
579585 }
580- let mut child = cmd
581- . args ( & self . args )
582- . arg ( "--standard-json" )
583- . stdin ( Stdio :: piped ( ) )
584- . stderr ( Stdio :: piped ( ) )
585- . stdout ( Stdio :: piped ( ) )
586- . spawn ( )
587- . map_err ( |err| SolcError :: io ( err, & self . solc ) ) ?;
588- let stdin = child. stdin . take ( ) . expect ( "Stdin exists." ) ;
586+ cmd. args ( & self . args ) . arg ( "--standard-json" ) ;
587+ cmd. stdin ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) . stdout ( Stdio :: piped ( ) ) ;
588+
589+ trace ! ( ?input) ;
590+ debug ! ( ?cmd, "compiling" ) ;
591+
592+ let mut child = cmd. spawn ( ) . map_err ( self . map_io_err ( ) ) ?;
593+ debug ! ( "spawned" ) ;
594+
595+ let stdin = child. stdin . as_mut ( ) . unwrap ( ) ;
589596 serde_json:: to_writer ( stdin, input) ?;
590- compile_output ( child. wait_with_output ( ) . map_err ( |err| SolcError :: io ( err, & self . solc ) ) ?)
597+ debug ! ( "wrote JSON input to stdin" ) ;
598+
599+ let output = child. wait_with_output ( ) . map_err ( self . map_io_err ( ) ) ?;
600+ debug ! ( %output. status, output. stderr = ?String :: from_utf8_lossy( & output. stderr) , "finished" ) ;
601+
602+ compile_output ( output)
591603 }
592604
605+ /// Invokes `solc --version` and parses the output as a SemVer [`Version`], stripping the
606+ /// pre-release and build metadata.
593607 pub fn version_short ( & self ) -> Result < Version > {
594608 let version = self . version ( ) ?;
595609 Ok ( Version :: new ( version. major , version. minor , version. patch ) )
596610 }
597611
598- /// Returns the version from the configured `solc`
612+ /// Invokes `solc --version` and parses the output as a SemVer [`Version`].
613+ #[ instrument( level = "debug" , skip_all) ]
599614 pub fn version ( & self ) -> Result < Version > {
600- version_from_output (
601- Command :: new ( & self . solc )
602- . arg ( "--version" )
603- . stdin ( Stdio :: piped ( ) )
604- . stderr ( Stdio :: piped ( ) )
605- . stdout ( Stdio :: piped ( ) )
606- . output ( )
607- . map_err ( |err| SolcError :: io ( err, & self . solc ) ) ?,
608- )
615+ let mut cmd = Command :: new ( & self . solc ) ;
616+ cmd. arg ( "--version" ) . stdin ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) . stdout ( Stdio :: piped ( ) ) ;
617+ debug ! ( ?cmd, "getting Solc version" ) ;
618+ let output = cmd. output ( ) . map_err ( self . map_io_err ( ) ) ?;
619+ trace ! ( ?output) ;
620+ let version = version_from_output ( output) ?;
621+ debug ! ( %version) ;
622+ Ok ( version)
623+ }
624+
625+ fn map_io_err ( & self ) -> impl FnOnce ( std:: io:: Error ) -> SolcError + ' _ {
626+ move |err| SolcError :: io ( err, & self . solc )
609627 }
610628}
611629
@@ -647,28 +665,21 @@ impl Solc {
647665 . stderr ( Stdio :: piped ( ) )
648666 . stdout ( Stdio :: piped ( ) )
649667 . spawn ( )
650- . map_err ( |err| SolcError :: io ( err , & self . solc ) ) ?;
668+ . map_err ( self . map_io_err ( ) ) ?;
651669 let stdin = child. stdin . as_mut ( ) . unwrap ( ) ;
652- stdin. write_all ( & content) . await . map_err ( |err| SolcError :: io ( err, & self . solc ) ) ?;
653- stdin. flush ( ) . await . map_err ( |err| SolcError :: io ( err, & self . solc ) ) ?;
654- compile_output (
655- child. wait_with_output ( ) . await . map_err ( |err| SolcError :: io ( err, & self . solc ) ) ?,
656- )
670+ stdin. write_all ( & content) . await . map_err ( self . map_io_err ( ) ) ?;
671+ stdin. flush ( ) . await . map_err ( self . map_io_err ( ) ) ?;
672+ compile_output ( child. wait_with_output ( ) . await . map_err ( self . map_io_err ( ) ) ?)
657673 }
658674
659675 pub async fn async_version ( & self ) -> Result < Version > {
660- version_from_output (
661- tokio:: process:: Command :: new ( & self . solc )
662- . arg ( "--version" )
663- . stdin ( Stdio :: piped ( ) )
664- . stderr ( Stdio :: piped ( ) )
665- . stdout ( Stdio :: piped ( ) )
666- . spawn ( )
667- . map_err ( |err| SolcError :: io ( err, & self . solc ) ) ?
668- . wait_with_output ( )
669- . await
670- . map_err ( |err| SolcError :: io ( err, & self . solc ) ) ?,
671- )
676+ let mut cmd = tokio:: process:: Command :: new ( & self . solc ) ;
677+ cmd. arg ( "--version" ) . stdin ( Stdio :: piped ( ) ) . stderr ( Stdio :: piped ( ) ) . stdout ( Stdio :: piped ( ) ) ;
678+ debug ! ( ?cmd, "getting version" ) ;
679+ let output = cmd. output ( ) . await . map_err ( self . map_io_err ( ) ) ?;
680+ let version = version_from_output ( output) ?;
681+ debug ! ( %version) ;
682+ Ok ( version)
672683 }
673684
674685 /// Compiles all `CompilerInput`s with their associated `Solc`.
0 commit comments