1- use crate :: info;
1+ use crate :: { info, warn } ;
22use crate :: { process, CmdResult , FunResult } ;
33use os_pipe:: PipeReader ;
44use std:: io:: { BufRead , BufReader , Error , ErrorKind , Read , Result } ;
@@ -77,24 +77,40 @@ pub struct FunChildren {
7777}
7878
7979impl FunChildren {
80- /// Waits for the children processes to exit completely, returning the output.
80+ /// Waits for the children processes to exit completely, returning the command result, stdout
81+ /// content string and stderr content string.
82+ pub fn wait_with_all ( & mut self ) -> ( CmdResult , String , String ) {
83+ self . inner_wait_with_all ( true )
84+ }
85+
86+ /// Waits for the children processes to exit completely, returning the stdout output.
8187 pub fn wait_with_output ( & mut self ) -> FunResult {
88+ let ( res, stdout, _) = self . inner_wait_with_all ( false ) ;
89+ if let Err ( e) = res {
90+ if !self . ignore_error {
91+ return Err ( e) ;
92+ }
93+ }
94+ Ok ( stdout)
95+ }
96+
97+ /// Waits for the children processes to exit completely, and read all bytes from stdout into `buf`.
98+ pub fn wait_with_raw_output ( & mut self , buf : & mut Vec < u8 > ) -> CmdResult {
8299 // wait for the last child result
83100 let handle = self . children . pop ( ) . unwrap ( ) ;
84- let wait_last = handle. wait_with_output ( self . ignore_error ) ;
101+ let wait_last = handle. wait_with_raw_output ( self . ignore_error , buf ) ;
85102 match wait_last {
86103 Err ( e) => {
87104 let _ = CmdChildren :: wait_children ( & mut self . children ) ;
88105 Err ( e)
89106 }
90- Ok ( output ) => {
107+ Ok ( _ ) => {
91108 let ret = CmdChildren :: wait_children ( & mut self . children ) ;
92- if let Err ( e ) = ret {
93- if ! self . ignore_error {
94- return Err ( e ) ;
95- }
109+ if self . ignore_error {
110+ Ok ( ( ) )
111+ } else {
112+ ret
96113 }
97- Ok ( output)
98114 }
99115 }
100116 }
@@ -127,19 +143,23 @@ impl FunChildren {
127143 CmdChildren :: wait_children ( & mut self . children )
128144 }
129145
130- /// Waits for the children processes to exit completely, returning the command result, stdout
131- /// read result and stderr read result.
132- pub fn wait_with_all ( & mut self ) -> ( CmdResult , FunResult , FunResult ) {
146+ /// Returns the OS-assigned process identifiers associated with these children processes.
147+ pub fn pids ( & self ) -> Vec < u32 > {
148+ self . children . iter ( ) . filter_map ( |x| x. pid ( ) ) . collect ( )
149+ }
150+
151+ fn inner_wait_with_all ( & mut self , capture_stderr : bool ) -> ( CmdResult , String , String ) {
133152 // wait for the last child result
134153 let handle = self . children . pop ( ) . unwrap ( ) ;
135- let wait_all = handle. wait_with_all ( true ) ;
154+ let mut stdout_buf = Vec :: new ( ) ;
155+ let mut stderr = String :: new ( ) ;
156+ let res = handle. wait_with_all ( capture_stderr, & mut stdout_buf, & mut stderr) ;
136157 let _ = CmdChildren :: wait_children ( & mut self . children ) ;
137- wait_all
138- }
139-
140- /// Returns the OS-assigned process identifiers associated with these children processes
141- pub fn pids ( & self ) -> Vec < u32 > {
142- self . children . iter ( ) . filter_map ( |x| x. pid ( ) ) . collect ( )
158+ let mut stdout: String = String :: from_utf8_lossy ( & stdout_buf) . into ( ) ;
159+ if stdout. ends_with ( '\n' ) {
160+ stdout. pop ( ) ;
161+ }
162+ ( res, stdout, stderr)
143163 }
144164}
145165
@@ -183,45 +203,41 @@ impl CmdChild {
183203 Ok ( ( ) )
184204 }
185205
186- fn wait_with_output ( self , ignore_error : bool ) -> FunResult {
187- let ( res, stdout, _) = self . wait_with_all ( false ) ;
188- if !ignore_error {
189- res?;
206+ fn wait_with_raw_output ( self , ignore_error : bool , stdout_buf : & mut Vec < u8 > ) -> CmdResult {
207+ let mut _stderr = String :: new ( ) ;
208+ let res = self . wait_with_all ( false , stdout_buf, & mut _stderr) ;
209+ if ignore_error {
210+ return Ok ( ( ) ) ;
190211 }
191- stdout
212+ res
192213 }
193214
194- fn wait_with_all ( mut self , capture : bool ) -> ( CmdResult , FunResult , FunResult ) {
215+ fn wait_with_all (
216+ mut self ,
217+ capture_stderr : bool ,
218+ stdout_buf : & mut Vec < u8 > ,
219+ stderr_buf : & mut String ,
220+ ) -> CmdResult {
195221 let mut stderr_thread = StderrThread :: new (
196222 & self . cmd ,
197223 & self . file ,
198224 self . line ,
199225 self . stderr . take ( ) ,
200- capture ,
226+ capture_stderr ,
201227 ) ;
202- let stdout_output = {
203- if let Some ( mut out) = self . stdout . take ( ) {
204- let mut s = String :: new ( ) ;
205- match out. read_to_string ( & mut s) {
206- Err ( e) => Err ( e) ,
207- Ok ( _) => {
208- if s. ends_with ( '\n' ) {
209- s. pop ( ) ;
210- }
211- Ok ( s)
212- }
213- }
214- } else {
215- Ok ( "" . into ( ) )
228+ let mut stdout_res = Ok ( ( ) ) ;
229+ if let Some ( mut stdout) = self . stdout . take ( ) {
230+ if let Err ( e) = stdout. read_to_end ( stdout_buf) {
231+ stdout_res = Err ( e)
216232 }
217- } ;
218- let stderr_output = stderr_thread. join ( ) ;
219- let res = self . handle . wait ( & self . cmd , & self . file , self . line ) ;
220- ( res , stdout_output , stderr_output )
233+ }
234+ * stderr_buf = stderr_thread. join ( ) ;
235+ let wait_res = self . handle . wait ( & self . cmd , & self . file , self . line ) ;
236+ wait_res . and ( stdout_res )
221237 }
222238
223239 fn kill ( self ) -> CmdResult {
224- self . handle . kill ( )
240+ self . handle . kill ( & self . cmd , & self . file , self . line )
225241 }
226242
227243 fn pid ( & self ) -> Option < u32 > {
@@ -244,12 +260,7 @@ impl CmdChildHandle {
244260 Err ( e) => return Err ( process:: new_cmd_io_error ( & e, cmd, file, line) ) ,
245261 Ok ( status) => {
246262 if !status. success ( ) {
247- return Err ( Self :: status_to_io_error (
248- status,
249- & format ! ( "Running [{cmd}] exited with error" ) ,
250- file,
251- line,
252- ) ) ;
263+ return Err ( Self :: status_to_io_error ( status, cmd, file, line) ) ;
253264 }
254265 }
255266 }
@@ -277,26 +288,34 @@ impl CmdChildHandle {
277288 Ok ( ( ) )
278289 }
279290
280- fn status_to_io_error ( status : ExitStatus , run_cmd : & str , file : & str , line : u32 ) -> Error {
291+ fn status_to_io_error ( status : ExitStatus , cmd : & str , file : & str , line : u32 ) -> Error {
281292 if let Some ( code) = status. code ( ) {
282293 Error :: new (
283294 ErrorKind :: Other ,
284- format ! ( "{run_cmd} ; status code: {code} at {file}:{line}" ) ,
295+ format ! ( "Running [{cmd}] exited with error ; status code: {code} at {file}:{line}" ) ,
285296 )
286297 } else {
287298 Error :: new (
288299 ErrorKind :: Other ,
289- format ! ( "{run_cmd}; terminated by {status} at {file}:{line}" ) ,
300+ format ! (
301+ "Running [{cmd}] exited with error; terminated by {status} at {file}:{line}"
302+ ) ,
290303 )
291304 }
292305 }
293306
294- fn kill ( self ) -> CmdResult {
307+ fn kill ( self , cmd : & str , file : & str , line : u32 ) -> CmdResult {
295308 match self {
296- CmdChildHandle :: Proc ( mut proc) => proc. kill ( ) ,
297- CmdChildHandle :: Thread ( _thread) => {
298- panic ! ( "thread killing not suppported!" )
299- }
309+ CmdChildHandle :: Proc ( mut proc) => proc. kill ( ) . map_err ( |e| {
310+ Error :: new (
311+ e. kind ( ) ,
312+ format ! ( "Killing process [{cmd}] failed with error: {e} at {file}:{line}" ) ,
313+ )
314+ } ) ,
315+ CmdChildHandle :: Thread ( _thread) => Err ( Error :: new (
316+ ErrorKind :: Other ,
317+ format ! ( "Killing thread [{cmd}] failed: not supported at {file}:{line}" ) ,
318+ ) ) ,
300319 CmdChildHandle :: SyncFn => Ok ( ( ) ) ,
301320 }
302321 }
@@ -352,27 +371,24 @@ impl StderrThread {
352371 }
353372 }
354373
355- fn join ( & mut self ) -> FunResult {
374+ fn join ( & mut self ) -> String {
356375 if let Some ( thread) = self . thread . take ( ) {
357376 match thread. join ( ) {
358377 Err ( e) => {
359- return Err ( Error :: new (
360- ErrorKind :: Other ,
361- format ! (
362- "Running [{}] stderr thread joined with error: {:?} at {}:{}" ,
363- self . cmd, e, self . file, self . line
364- ) ,
365- ) ) ;
378+ warn ! (
379+ "Running [{}] stderr thread joined with error: {:?} at {}:{}" ,
380+ self . cmd, e, self . file, self . line
381+ ) ;
366382 }
367- Ok ( output) => return Ok ( output) ,
383+ Ok ( output) => return output,
368384 }
369385 }
370- Ok ( "" . into ( ) )
386+ "" . into ( )
371387 }
372388}
373389
374390impl Drop for StderrThread {
375391 fn drop ( & mut self ) {
376- let _ = self . join ( ) ;
392+ self . join ( ) ;
377393 }
378394}
0 commit comments