Implement command module

This commit is contained in:
Leonard Steppy 2024-12-17 10:31:02 +01:00
parent d0a14d7763
commit f3e965394e

View File

@ -1,31 +1,93 @@
use crate::logger::Logger; use crate::log;
use crate::logger::{LogLevel, Logger};
use std::error::Error;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::io; use std::io;
use std::process::{Command, ExitStatus}; use std::process::{Command, ExitStatus, Stdio};
pub trait LogRunnable { pub trait LogRunnable {
fn run(&mut self, logger: &Logger) -> Result<(), ExecutionError>; fn run(&mut self, logger: &Logger) -> Result<(), ExecutionError>;
} }
impl LogRunnable for Command { impl LogRunnable for Command {
//TODO use specific execution error as error type fn run(&mut self, logger: &Logger) -> Result<(), SpecificExecutionError> {
fn run(&mut self, logger: &Logger) -> Result<(), ExecutionError> { //TODO I'm not happy yet with the implementation of this method
todo!("depending on log level, pipe output and only print with logger on error") match logger.level {
LogLevel::Debug | LogLevel::Info => self
.status()
.map_err(ExecutionError::StartError)
.and_then(|status| {
if status.success() {
Ok(())
} else {
Err(ExecutionError::BadExitStatus(status))
}
}),
LogLevel::Error => self
.stdout(Stdio::piped())
.output()
.map_err(ExecutionError::StartError)
.and_then(|output| {
if output.status.success() {
Ok(())
} else {
log!(logger, error, "{}", String::from_utf8_lossy(&output.stderr));
Err(ExecutionError::BadExitStatus(output.status))
}
}),
}
.map_err(|error| SpecificExecutionError {
command: self,
error,
})
} }
} }
//TODO show command in specific execution error #[derive(Debug)]
pub struct SpecificExecutionError<'a> {
pub command: &'a Command,
pub error: ExecutionError,
}
impl Display for SpecificExecutionError<'_> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Failed to execute command {}: {}",
self.command, self.error
)
}
}
impl Error for SpecificExecutionError<'_> {}
#[derive(Debug)] #[derive(Debug)]
pub enum ExecutionError { pub enum ExecutionError {
StartError(io::Error), StartError(io::Error),
BadExitStatus(ExitStatus), BadExitStatus(ExitStatus),
} }
impl From<io::Error> for ExecutionError {
fn from(value: io::Error) -> Self {
Self::StartError(value)
}
}
impl From<ExitStatus> for ExecutionError {
fn from(value: ExitStatus) -> Self {
Self::BadExitStatus(value)
}
}
impl Display for ExecutionError { impl Display for ExecutionError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
ExecutionError::StartError(e) => write!(f, "failed to start command: {}", e), ExecutionError::StartError(e) => write!(f, "failed to start command: {}", e),
ExecutionError::BadExitStatus(status) => write!(f, "command failed with exit status: {}", status), ExecutionError::BadExitStatus(status) => {
write!(f, "command failed with exit status: {}", status)
}
} }
} }
} }
impl Error for ExecutionError {}