diff --git a/src/child.rs b/src/child.rs index 3d664b2..2ea2052 100644 --- a/src/child.rs +++ b/src/child.rs @@ -2,7 +2,7 @@ use crate::io::CmdIn; use crate::CmdResult; use log::info; use os_pipe::PipeReader; -use std::io::{BufRead, BufReader, Error, ErrorKind, Read, Result, Write}; +use std::io::{self, BufRead, BufReader, Error, ErrorKind, Read, Result, Write}; use std::process::{Child, ExitStatus}; use std::thread::JoinHandle; @@ -21,41 +21,55 @@ impl CmdChildHandle { } } - pub fn wait(self) -> CmdResult { + pub fn wait(self, is_last: bool) -> CmdResult { + let pipefail = std::env::var("CMD_LIB_PIPEFAIL") != Ok("0".into()); + let check_result = |result| { + if let Err(e) = result { + if is_last || pipefail { + return Err(e); + } + } + Ok(()) + }; match self { Self::ProcChild(mut p) => { let status = p.child.wait()?; Self::log_stderr(&mut p.child); - if !status.success() && std::env::var("CMD_LIB_PIPEFAIL") != Ok("0".into()) { + if !status.success() && (is_last || pipefail) { return Err(Self::status_to_io_error( status, &format!("{} exited with error", p.cmd), )); } - Ok(()) } Self::ThreadChild(t) => { let status = t.child.join(); - if let Err(e) = status { - return Err(Error::new( - ErrorKind::Other, - format!("{} thread exited with error: {:?}", t.cmd, e), - )); + match status { + Err(e) => { + if is_last || pipefail { + return Err(Error::new( + ErrorKind::Other, + format!("{} thread exited with error: {:?}", t.cmd, e), + )); + } + } + Ok(result) => { + check_result(result)?; + } } - Ok(()) } Self::SyncChild(s) => { if let Some(mut out) = s.output { let mut buf = vec![]; - out.read_to_end(&mut buf)?; - std::io::stdout().write_all(&buf[..])?; + check_result(out.read_to_end(&mut buf).map(|_|()))?; + check_result(io::stdout().write_all(&buf[..]))?; } - Ok(()) } } + Ok(()) } - pub fn wait_last_with_output(self) -> Result> { + pub fn wait_with_output(self) -> Result> { match self { Self::ProcChild(p) => { let output = p.child.wait_with_output()?; @@ -70,14 +84,7 @@ impl CmdChildHandle { } } Self::ThreadChild(t) => { - let status = t.child.join(); - if let Err(e) = status { - return Err(Error::new( - ErrorKind::Other, - format!("{} thread exited with error: {:?}", t.cmd, e), - )); - } - Ok(vec![]) + panic!("{} thread should not be waited for output", t.cmd); } Self::SyncChild(s) => { if let Some(mut out) = s.output { @@ -132,7 +139,7 @@ pub struct CmdProcChild { } pub struct CmdThreadChild { - pub child: JoinHandle<()>, + pub child: JoinHandle, pub cmd: String, pub stderr_logging: Option, } diff --git a/src/process.rs b/src/process.rs index 351e4c1..a2a888c 100644 --- a/src/process.rs +++ b/src/process.rs @@ -227,14 +227,14 @@ impl WaitCmd { fn wait_result_nolog(&mut self) -> CmdResult { // wait last process result let handle = self.0.pop().unwrap(); - handle.wait()?; + handle.wait(true)?; Self::wait_children(&mut self.0) } fn wait_children(children: &mut Vec) -> CmdResult { while !children.is_empty() { let child_handle = children.pop().unwrap(); - child_handle.wait()?; + child_handle.wait(false)?; } Ok(()) } @@ -256,7 +256,7 @@ impl WaitFun { pub fn wait_raw_result_nolog(&mut self) -> Result> { let handle = self.0.pop().unwrap(); - let wait_last = handle.wait_last_with_output(); + let wait_last = handle.wait_with_output(); match wait_last { Err(e) => { let _ = WaitCmd::wait_children(&mut self.0); @@ -284,7 +284,7 @@ impl WaitFun { pub fn wait_result_nolog(&mut self) -> FunResult { // wait last process result let handle = self.0.pop().unwrap(); - let wait_last = handle.wait_last_with_output(); + let wait_last = handle.wait_with_output(); match wait_last { Err(e) => { let _ = WaitCmd::wait_children(&mut self.0); @@ -474,9 +474,7 @@ impl Cmd { let internal_cmd = CMD_MAP.lock().unwrap()[&arg0]; if pipe_out { - let handle = std::thread::spawn(move || { - internal_cmd(&mut env).unwrap(); - }); + let handle = std::thread::spawn(move || internal_cmd(&mut env)); Ok(CmdChildHandle::ThreadChild(CmdThreadChild { child: handle, stderr_logging: self.stderr_logging,