Skip to content

Commit 548288f

Browse files
committed
Clean up new logic and merge with CmdChildHandle::wait()
1 parent ff05adb commit 548288f

File tree

1 file changed

+49
-72
lines changed

1 file changed

+49
-72
lines changed

src/child.rs

Lines changed: 49 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,14 @@ impl FunChildren {
171171
let last_child_res = if let Some(stdout) = last_child.stdout {
172172
let mut stdout: Box<dyn Read> = Box::new(stdout);
173173
f(&mut stdout);
174+
// The provided function may have left some of stdout unread.
175+
// Continue reading stdout on its behalf, until the child exits.
174176
let mut buf = vec![0; 65536];
175-
let status: Box<dyn ChildOutcome> = loop {
177+
let outcome: Box<dyn ChildOutcome> = loop {
176178
match last_child.handle {
177179
CmdChildHandle::Proc(ref mut child) => {
178-
if let Ok(Some(status)) = child.try_wait() {
179-
break Box::new(status);
180+
if let Some(result) = child.try_wait().transpose() {
181+
break Box::new(ProcWaitOutcome::from(result));
180182
}
181183
}
182184
CmdChildHandle::Thread(ref mut join_handle) => {
@@ -194,16 +196,7 @@ impl FunChildren {
194196
}
195197
let _ = stdout.read(&mut buf);
196198
};
197-
if status.success() {
198-
Ok(())
199-
} else {
200-
Err(CmdChildHandle::outcome_to_io_error(
201-
&*status,
202-
&last_child.cmd,
203-
&last_child.file,
204-
last_child.line,
205-
))
206-
}
199+
outcome.to_io_result(&last_child.cmd, &last_child.file, last_child.line)
207200
} else {
208201
last_child.wait(true)
209202
};
@@ -329,6 +322,29 @@ pub(crate) enum CmdChildHandle {
329322
SyncFn,
330323
}
331324

325+
#[derive(Debug)]
326+
struct ProcWaitOutcome(std::io::Result<ExitStatus>);
327+
impl From<std::io::Result<ExitStatus>> for ProcWaitOutcome {
328+
fn from(result: std::io::Result<ExitStatus>) -> Self {
329+
Self(result)
330+
}
331+
}
332+
impl Display for ProcWaitOutcome {
333+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
334+
match &self.0 {
335+
Ok(status) => {
336+
if status.success() {
337+
write!(f, "Command process succeeded")
338+
} else if let Some(code) = status.code() {
339+
write!(f, "Command process exited normally with status code {code}")
340+
} else {
341+
write!(f, "Command process exited abnormally: {status}")
342+
}
343+
}
344+
Err(error) => write!(f, "Failed to wait for command process: {error:?}"),
345+
}
346+
}
347+
}
332348
#[derive(Debug)]
333349
enum ThreadJoinOutcome {
334350
Ok,
@@ -362,86 +378,47 @@ impl Display for SyncFnOutcome {
362378
}
363379
trait ChildOutcome: Display {
364380
fn success(&self) -> bool;
365-
fn code(&self) -> Option<i32>;
381+
fn to_io_result(&self, cmd: &str, file: &str, line: u32) -> std::io::Result<()> {
382+
if self.success() {
383+
Ok(())
384+
} else {
385+
Err(Error::new(
386+
ErrorKind::Other,
387+
format!("Running [{cmd}] exited with error; {self} at {file}:{line}"),
388+
))
389+
}
390+
}
366391
}
367-
impl ChildOutcome for ExitStatus {
392+
impl ChildOutcome for ProcWaitOutcome {
368393
fn success(&self) -> bool {
369-
self.success()
370-
}
371-
fn code(&self) -> Option<i32> {
372-
self.code()
394+
self.0.as_ref().is_ok_and(|status| status.success())
373395
}
374396
}
375397
impl ChildOutcome for ThreadJoinOutcome {
376398
fn success(&self) -> bool {
377399
matches!(self, Self::Ok)
378400
}
379-
fn code(&self) -> Option<i32> {
380-
None
381-
}
382401
}
383402
impl ChildOutcome for SyncFnOutcome {
384403
fn success(&self) -> bool {
385404
true
386405
}
387-
fn code(&self) -> Option<i32> {
388-
None
389-
}
390406
}
391407

392408
impl CmdChildHandle {
393409
fn wait(self, cmd: &str, file: &str, line: u32) -> CmdResult {
394-
match self {
395-
CmdChildHandle::Proc(mut proc) => {
396-
let status = proc.wait();
397-
match status {
398-
Err(e) => return Err(process::new_cmd_io_error(&e, cmd, file, line)),
399-
Ok(status) => {
400-
if !status.success() {
401-
return Err(Self::outcome_to_io_error(&status, cmd, file, line));
402-
}
403-
}
404-
}
405-
}
410+
let outcome: Box<dyn ChildOutcome> = match self {
411+
CmdChildHandle::Proc(mut proc) => Box::new(ProcWaitOutcome::from(proc.wait())),
406412
CmdChildHandle::Thread(mut thread) => {
407413
if let Some(thread) = thread.take() {
408-
let status = thread.join();
409-
match status {
410-
Ok(result) => {
411-
if let Err(e) = result {
412-
return Err(process::new_cmd_io_error(&e, cmd, file, line));
413-
}
414-
}
415-
Err(e) => {
416-
return Err(Error::new(
417-
ErrorKind::Other,
418-
format!(
419-
"Running [{cmd}] thread joined with error: {e:?} at {file}:{line}"
420-
),
421-
))
422-
}
423-
}
414+
Box::new(ThreadJoinOutcome::from(thread.join()))
415+
} else {
416+
unreachable!()
424417
}
425418
}
426-
CmdChildHandle::SyncFn => {}
427-
}
428-
Ok(())
429-
}
430-
431-
fn outcome_to_io_error(outcome: &dyn ChildOutcome, cmd: &str, file: &str, line: u32) -> Error {
432-
if let Some(code) = outcome.code() {
433-
Error::new(
434-
ErrorKind::Other,
435-
format!("Running [{cmd}] exited with error; status code: {code} at {file}:{line}"),
436-
)
437-
} else {
438-
Error::new(
439-
ErrorKind::Other,
440-
format!(
441-
"Running [{cmd}] exited with error; terminated by {outcome} at {file}:{line}"
442-
),
443-
)
444-
}
419+
CmdChildHandle::SyncFn => return Ok(()),
420+
};
421+
outcome.to_io_result(cmd, file, line)
445422
}
446423

447424
fn kill(self, cmd: &str, file: &str, line: u32) -> CmdResult {

0 commit comments

Comments
 (0)