use std::{
iter::{Once, once},
path::PathBuf,
process::{Child, ChildStdout, Command, Stdio},
sync::Mutex,
};
use crate::{
backend::{ReadSource, ReadSourceEntry},
error::{ErrorKind, RusticError, RusticResult},
repository::command_input::{CommandInput, CommandInputErrorKind},
};
#[derive(Debug)]
pub struct ChildStdoutSource {
path: PathBuf,
process: Mutex<Child>,
command: CommandInput,
}
impl ChildStdoutSource {
pub fn new(cmd: &CommandInput, path: PathBuf) -> RusticResult<Self> {
let process = Command::new(cmd.command())
.args(cmd.args())
.stdout(Stdio::piped())
.spawn()
.map_err(|err| CommandInputErrorKind::ProcessExecutionFailed {
command: cmd.clone(),
path: path.clone(),
source: err,
});
let process = cmd.on_failure().display_result(process)?;
Ok(Self {
path,
process: Mutex::new(process),
command: cmd.clone(),
})
}
pub fn finish(self) -> RusticResult<()> {
let status = self.process.lock().unwrap().wait();
self.command
.on_failure()
.handle_status(status, "stdin-command", "call")?;
Ok(())
}
}
impl ReadSource for ChildStdoutSource {
type Open = ChildStdout;
type Iter = Once<RusticResult<ReadSourceEntry<ChildStdout>>>;
fn size(&self) -> RusticResult<Option<u64>> {
Ok(None)
}
fn entries(&self) -> Self::Iter {
let open = self.process.lock().unwrap().stdout.take();
once(
ReadSourceEntry::from_path(self.path.clone(), open).map_err(|err| {
RusticError::with_source(
ErrorKind::Backend,
"Failed to create ReadSourceEntry from ChildStdout",
err,
)
}),
)
}
}