11//! This crate provides common functionality for Roc to interface with `std::process::Command`
2+
23use roc_std:: { RocList , RocResult , RocStr } ;
34
45#[ derive( Clone , Debug , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
@@ -61,29 +62,50 @@ impl From<&Command> for std::process::Command {
6162
6263#[ derive( Clone , Debug , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
6364#[ repr( C ) ]
64- pub struct OutputFromHost {
65- pub status : roc_std:: RocResult < i32 , roc_io_error:: IOErr > ,
66- pub stderr : roc_std:: RocList < u8 > ,
67- pub stdout : roc_std:: RocList < u8 > ,
65+ pub struct OutputFromHostSuccess {
66+ pub stdout_bytes : roc_std:: RocList < u8 > ,
67+ pub stderr_bytes : roc_std:: RocList < u8 > ,
68+ }
69+
70+ #[ derive( Clone , Debug , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
71+ #[ repr( C ) ]
72+ pub struct OutputFromHostFailure {
73+ pub status : i32 ,
74+ pub stdout_bytes : roc_std:: RocList < u8 > ,
75+ pub stderr_bytes : roc_std:: RocList < u8 > ,
6876}
6977
70- impl roc_std:: RocRefcounted for OutputFromHost {
78+ impl roc_std:: RocRefcounted for OutputFromHostSuccess {
79+ fn inc ( & mut self ) {
80+ self . stderr_bytes . inc ( ) ;
81+ self . stdout_bytes . inc ( ) ;
82+ }
83+ fn dec ( & mut self ) {
84+ self . stderr_bytes . dec ( ) ;
85+ self . stdout_bytes . dec ( ) ;
86+ }
87+ fn is_refcounted ( ) -> bool {
88+ true
89+ }
90+ }
91+
92+ impl roc_std:: RocRefcounted for OutputFromHostFailure {
7193 fn inc ( & mut self ) {
7294 self . status . inc ( ) ;
73- self . stderr . inc ( ) ;
74- self . stdout . inc ( ) ;
95+ self . stderr_bytes . inc ( ) ;
96+ self . stdout_bytes . inc ( ) ;
7597 }
7698 fn dec ( & mut self ) {
7799 self . status . dec ( ) ;
78- self . stderr . dec ( ) ;
79- self . stdout . dec ( ) ;
100+ self . stderr_bytes . dec ( ) ;
101+ self . stdout_bytes . dec ( ) ;
80102 }
81103 fn is_refcounted ( ) -> bool {
82104 true
83105 }
84106}
85107
86- pub fn command_status ( roc_cmd : & Command ) -> RocResult < i32 , roc_io_error:: IOErr > {
108+ pub fn command_exec_exit_code ( roc_cmd : & Command ) -> RocResult < i32 , roc_io_error:: IOErr > {
87109 match std:: process:: Command :: from ( roc_cmd) . status ( ) {
88110 Ok ( status) => from_exit_status ( status) ,
89111 Err ( err) => RocResult :: err ( err. into ( ) ) ,
@@ -94,29 +116,33 @@ pub fn command_status(roc_cmd: &Command) -> RocResult<i32, roc_io_error::IOErr>
94116fn from_exit_status ( status : std:: process:: ExitStatus ) -> RocResult < i32 , roc_io_error:: IOErr > {
95117 match status. code ( ) {
96118 Some ( code) => RocResult :: ok ( code) ,
97- None => killed_by_signal ( ) ,
119+ None => RocResult :: err ( killed_by_signal_err ( ) ) ,
98120 }
99121}
100122
101- // If no exit code is returned, the process was terminated by a signal.
102- fn killed_by_signal ( ) -> RocResult < i32 , roc_io_error:: IOErr > {
103- RocResult :: err ( roc_io_error:: IOErr {
123+ fn killed_by_signal_err ( ) -> roc_io_error:: IOErr {
124+ roc_io_error:: IOErr {
104125 tag : roc_io_error:: IOErrTag :: Other ,
105- msg : "Killed by signal" . into ( ) ,
106- } )
126+ msg : "Process was killed by operating system signal. " . into ( ) ,
127+ }
107128}
108129
109- pub fn command_output ( roc_cmd : & Command ) -> OutputFromHost {
130+ // TODO Can we make this return a tag union (with three variants) ?
131+ pub fn command_exec_output ( roc_cmd : & Command ) -> RocResult < OutputFromHostSuccess , RocResult < OutputFromHostFailure , roc_io_error:: IOErr > > {
110132 match std:: process:: Command :: from ( roc_cmd) . output ( ) {
111- Ok ( output) => OutputFromHost {
112- status : from_exit_status ( output. status ) ,
113- stdout : RocList :: from ( & output. stdout [ ..] ) ,
114- stderr : RocList :: from ( & output. stderr [ ..] ) ,
115- } ,
116- Err ( err) => OutputFromHost {
117- status : RocResult :: err ( err. into ( ) ) ,
118- stdout : RocList :: empty ( ) ,
119- stderr : RocList :: empty ( ) ,
120- } ,
133+ Ok ( output) =>
134+ match output. status . code ( ) {
135+ Some ( status) if status == 0 => RocResult :: ok ( OutputFromHostSuccess {
136+ stdout_bytes : RocList :: from ( & output. stdout [ ..] ) ,
137+ stderr_bytes : RocList :: from ( & output. stderr [ ..] ) ,
138+ } ) ,
139+ Some ( status) => RocResult :: err ( RocResult :: ok ( OutputFromHostFailure {
140+ status : status,
141+ stdout_bytes : RocList :: from ( & output. stdout [ ..] ) ,
142+ stderr_bytes : RocList :: from ( & output. stdout [ ..] ) ,
143+ } ) ) ,
144+ None => RocResult :: err ( RocResult :: err ( killed_by_signal_err ( ) ) )
145+ }
146+ Err ( err) => RocResult :: err ( RocResult :: err ( err. into ( ) ) )
121147 }
122148}
0 commit comments