1
- use crate :: info;
1
+ use crate :: { info, warn } ;
2
2
use crate :: { process, CmdResult , FunResult } ;
3
3
use os_pipe:: PipeReader ;
4
4
use std:: io:: { BufRead , BufReader , Error , ErrorKind , Read , Result } ;
@@ -77,24 +77,40 @@ pub struct FunChildren {
77
77
}
78
78
79
79
impl 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.
81
87
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 {
82
99
// wait for the last child result
83
100
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 ) ;
85
102
match wait_last {
86
103
Err ( e) => {
87
104
let _ = CmdChildren :: wait_children ( & mut self . children ) ;
88
105
Err ( e)
89
106
}
90
- Ok ( output ) => {
107
+ Ok ( _ ) => {
91
108
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
96
113
}
97
- Ok ( output)
98
114
}
99
115
}
100
116
}
@@ -127,19 +143,23 @@ impl FunChildren {
127
143
CmdChildren :: wait_children ( & mut self . children )
128
144
}
129
145
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 ) {
133
152
// wait for the last child result
134
153
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) ;
136
157
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)
143
163
}
144
164
}
145
165
@@ -183,45 +203,41 @@ impl CmdChild {
183
203
Ok ( ( ) )
184
204
}
185
205
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 ( ( ) ) ;
190
211
}
191
- stdout
212
+ res
192
213
}
193
214
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 {
195
221
let mut stderr_thread = StderrThread :: new (
196
222
& self . cmd ,
197
223
& self . file ,
198
224
self . line ,
199
225
self . stderr . take ( ) ,
200
- capture ,
226
+ capture_stderr ,
201
227
) ;
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)
216
232
}
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 )
221
237
}
222
238
223
239
fn kill ( self ) -> CmdResult {
224
- self . handle . kill ( )
240
+ self . handle . kill ( & self . cmd , & self . file , self . line )
225
241
}
226
242
227
243
fn pid ( & self ) -> Option < u32 > {
@@ -244,12 +260,7 @@ impl CmdChildHandle {
244
260
Err ( e) => return Err ( process:: new_cmd_io_error ( & e, cmd, file, line) ) ,
245
261
Ok ( status) => {
246
262
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) ) ;
253
264
}
254
265
}
255
266
}
@@ -277,26 +288,34 @@ impl CmdChildHandle {
277
288
Ok ( ( ) )
278
289
}
279
290
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 {
281
292
if let Some ( code) = status. code ( ) {
282
293
Error :: new (
283
294
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}" ) ,
285
296
)
286
297
} else {
287
298
Error :: new (
288
299
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
+ ) ,
290
303
)
291
304
}
292
305
}
293
306
294
- fn kill ( self ) -> CmdResult {
307
+ fn kill ( self , cmd : & str , file : & str , line : u32 ) -> CmdResult {
295
308
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
+ ) ) ,
300
319
CmdChildHandle :: SyncFn => Ok ( ( ) ) ,
301
320
}
302
321
}
@@ -352,27 +371,24 @@ impl StderrThread {
352
371
}
353
372
}
354
373
355
- fn join ( & mut self ) -> FunResult {
374
+ fn join ( & mut self ) -> String {
356
375
if let Some ( thread) = self . thread . take ( ) {
357
376
match thread. join ( ) {
358
377
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
+ ) ;
366
382
}
367
- Ok ( output) => return Ok ( output) ,
383
+ Ok ( output) => return output,
368
384
}
369
385
}
370
- Ok ( "" . into ( ) )
386
+ "" . into ( )
371
387
}
372
388
}
373
389
374
390
impl Drop for StderrThread {
375
391
fn drop ( & mut self ) {
376
- let _ = self . join ( ) ;
392
+ self . join ( ) ;
377
393
}
378
394
}
0 commit comments