use crate::error::{Error, ErrorKind::ExecError};
use std::process::{Child, Command, ExitStatus, Stdio};
#[derive(Debug)]
pub struct TransparentExecutor {
child: Child,
exit_status: Option<ExitStatus>,
}
impl TransparentExecutor {
pub(crate) fn new(command: &mut Command) -> Result<Self, Error> {
command.stdout(Stdio::inherit());
command.stderr(Stdio::inherit());
let child = command.spawn().map_err(|e| error!(ExecError, with: e, "failed to execute child"))?;
Ok(Self { child, exit_status: None })
}
pub fn close_stdin(&mut self) {
self.child.stdin = None
}
pub fn close_stdout(&mut self) {
self.child.stdout = None
}
pub fn close_stderr(&mut self) {
self.child.stderr = None
}
pub fn is_running(&mut self) -> Result<bool, Error> {
if self.exit_status.is_none() {
self.exit_status =
self.child.try_wait().map_err(|e| error!(ExecError, with: e, "failed to get child exit status"))?;
}
Ok(self.exit_status.is_none())
}
pub fn wait(mut self) -> Result<(), Error> {
self.child.stdin = None;
let exit_status = self
.exit_status
.take()
.map_or_else(|| self.child.wait(), Ok)
.map_err(|e| error!(ExecError, with: e, "failed to get child exit status"))?;
if !exit_status.success() {
return Err(error!(ExecError, "child process failed ({:?})", exit_status.code()));
}
Ok(())
}
}