Add collect_full_output method to commands
This commit is contained in:
parent
930e02d802
commit
ffd8f71f8b
@ -1,27 +1,34 @@
|
|||||||
use crate::log;
|
use crate::log;
|
||||||
use crate::logger::{LogLevel, Logger};
|
use crate::logger::{LogLevel, Logger};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::process::{Command, ExitStatus, Output};
|
use std::process::{Command, ExitStatus, Output};
|
||||||
|
|
||||||
pub trait LogRunnable {
|
pub trait LogRunnable {
|
||||||
fn run(&mut self, logger: &Logger) -> Result<(), SpecificExecutionError>;
|
fn run(&mut self, logger: &Logger) -> Result<(), CommandSpecificError<ExecutionError>>;
|
||||||
fn collect_output(&mut self) -> Result<Output, SpecificExecutionError>;
|
fn collect_output(&mut self) -> Result<Output, CommandSpecificError<ExecutionError>>;
|
||||||
//TODO collect_full_output
|
fn collect_full_output(&mut self) -> Result<Output, CommandSpecificError<StartError>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LogRunnable for Command {
|
impl LogRunnable for Command {
|
||||||
fn run(&mut self, logger: &Logger) -> Result<(), SpecificExecutionError> {
|
fn run(&mut self, logger: &Logger) -> Result<(), CommandSpecificError<ExecutionError>> {
|
||||||
run(self, logger).map_err(|error| SpecificExecutionError {
|
run(self, logger).map_err(|error| CommandSpecificError {
|
||||||
command: self,
|
command: self,
|
||||||
error,
|
error,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn collect_output(&mut self) -> Result<Output, SpecificExecutionError> {
|
fn collect_output(&mut self) -> Result<Output, CommandSpecificError<ExecutionError>> {
|
||||||
collect_output(self, None).map_err(|error| SpecificExecutionError {
|
collect_output(self, None).map_err(|error| CommandSpecificError {
|
||||||
|
command: self,
|
||||||
|
error,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_full_output(&mut self) -> Result<Output, CommandSpecificError<StartError>> {
|
||||||
|
collect_full_output(self).map_err(|error| CommandSpecificError {
|
||||||
command: self,
|
command: self,
|
||||||
error,
|
error,
|
||||||
})
|
})
|
||||||
@ -47,7 +54,7 @@ fn collect_output(
|
|||||||
command: &mut Command,
|
command: &mut Command,
|
||||||
logger: Option<&Logger>,
|
logger: Option<&Logger>,
|
||||||
) -> Result<Output, ExecutionError> {
|
) -> Result<Output, ExecutionError> {
|
||||||
let output = command.output()?; //pipes stdout and stderr automatically
|
let output = collect_full_output(command)?;
|
||||||
if !output.status.success() {
|
if !output.status.success() {
|
||||||
if let Some(logger) = logger {
|
if let Some(logger) = logger {
|
||||||
log!(logger, error, "{}", String::from_utf8_lossy(&output.stdout));
|
log!(logger, error, "{}", String::from_utf8_lossy(&output.stdout));
|
||||||
@ -58,13 +65,20 @@ fn collect_output(
|
|||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
fn collect_full_output(command: &mut Command) -> Result<Output, StartError> {
|
||||||
pub struct SpecificExecutionError<'a> {
|
Ok(command.output()?)
|
||||||
pub command: &'a Command,
|
|
||||||
pub error: ExecutionError,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for SpecificExecutionError<'_> {
|
#[derive(Debug)]
|
||||||
|
pub struct CommandSpecificError<'a, E> {
|
||||||
|
pub command: &'a Command,
|
||||||
|
pub error: E,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<E> Display for CommandSpecificError<'_, E>
|
||||||
|
where
|
||||||
|
E: Display,
|
||||||
|
{
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -76,22 +90,52 @@ impl Display for SpecificExecutionError<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn command_to_string(command: &Command) -> String {
|
fn command_to_string(command: &Command) -> String {
|
||||||
once(command.get_program().to_string_lossy())
|
once(command.get_program().to_string_lossy().to_string())
|
||||||
.chain(command.get_args().map(|arg| arg.to_string_lossy()))
|
.chain(command.get_args().map(|arg| {
|
||||||
|
let arg_str = arg.to_string_lossy();
|
||||||
|
if arg_str.contains(' ') {
|
||||||
|
format!("\"{arg_str}\"")
|
||||||
|
} else {
|
||||||
|
arg_str.to_string()
|
||||||
|
}
|
||||||
|
}))
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(" ")
|
.join(" ")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for SpecificExecutionError<'_> {}
|
impl<E> Error for CommandSpecificError<'_, E> where E: Debug + Display {}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct StartError(io::Error);
|
||||||
|
|
||||||
|
impl From<io::Error> for StartError {
|
||||||
|
fn from(value: io::Error) -> Self {
|
||||||
|
StartError(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for StartError {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Failed to start command: {}", self.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for StartError {}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ExecutionError {
|
pub enum ExecutionError {
|
||||||
StartError(io::Error),
|
StartError(StartError),
|
||||||
BadExitStatus(ExitStatus),
|
BadExitStatus(ExitStatus),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<io::Error> for ExecutionError {
|
impl From<io::Error> for ExecutionError {
|
||||||
fn from(value: io::Error) -> Self {
|
fn from(value: io::Error) -> Self {
|
||||||
|
Self::StartError(StartError(value))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<StartError> for ExecutionError {
|
||||||
|
fn from(value: StartError) -> Self {
|
||||||
Self::StartError(value)
|
Self::StartError(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -105,10 +149,8 @@ impl From<ExitStatus> for ExecutionError {
|
|||||||
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) => Display::fmt(e, f),
|
||||||
ExecutionError::BadExitStatus(status) => {
|
ExecutionError::BadExitStatus(status) => write!(f, "Command failed with {}", status),
|
||||||
write!(f, "Command failed with {}", status)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -117,7 +159,7 @@ impl Error for ExecutionError {}
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::command::{ExecutionError, LogRunnable, SpecificExecutionError};
|
use crate::command::{CommandSpecificError, ExecutionError, LogRunnable};
|
||||||
use crate::logger::Logger;
|
use crate::logger::Logger;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
@ -126,7 +168,7 @@ mod test {
|
|||||||
fn test_unknown_command() {
|
fn test_unknown_command() {
|
||||||
let mut command = Command::new("python7");
|
let mut command = Command::new("python7");
|
||||||
let Err(
|
let Err(
|
||||||
e @ SpecificExecutionError {
|
e @ CommandSpecificError {
|
||||||
error: ExecutionError::StartError(_),
|
error: ExecutionError::StartError(_),
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
@ -143,7 +185,7 @@ mod test {
|
|||||||
fn test_error() {
|
fn test_error() {
|
||||||
let mut command = Command::new("python3");
|
let mut command = Command::new("python3");
|
||||||
let Err(
|
let Err(
|
||||||
e @ SpecificExecutionError {
|
e @ CommandSpecificError {
|
||||||
error: ExecutionError::BadExitStatus(_),
|
error: ExecutionError::BadExitStatus(_),
|
||||||
..
|
..
|
||||||
},
|
},
|
||||||
|
|||||||
21
src/main.rs
21
src/main.rs
@ -6,7 +6,7 @@ mod os_string_builder;
|
|||||||
mod server;
|
mod server;
|
||||||
|
|
||||||
use crate::action::{Action, FileAction, ServerActions};
|
use crate::action::{Action, FileAction, ServerActions};
|
||||||
use crate::command::{ExecutionError, LogRunnable, SpecificExecutionError};
|
use crate::command::{CommandSpecificError, ExecutionError, LogRunnable};
|
||||||
use crate::file::{FileMatcher, FileNameInfo};
|
use crate::file::{FileMatcher, FileNameInfo};
|
||||||
use crate::logger::{LogLevel, Logger};
|
use crate::logger::{LogLevel, Logger};
|
||||||
use crate::os_string_builder::ReplaceWithOsStr;
|
use crate::os_string_builder::ReplaceWithOsStr;
|
||||||
@ -216,7 +216,7 @@ fn main() -> Result<(), String> {
|
|||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(&OsString::from(","))
|
.join(&OsString::from(","))
|
||||||
+ "}";
|
+ "}";
|
||||||
|
|
||||||
//TODO handle bad exit status
|
//TODO handle bad exit status
|
||||||
let realpath_output = ShellCmd::new("ssh")
|
let realpath_output = ShellCmd::new("ssh")
|
||||||
.arg(ssh_address)
|
.arg(ssh_address)
|
||||||
@ -234,17 +234,12 @@ fn main() -> Result<(), String> {
|
|||||||
check_file_exists_on_server(file, ssh_address, &file_server.server_directory_path)?;
|
check_file_exists_on_server(file, ssh_address, &file_server.server_directory_path)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ServerAddress::Localhost => {
|
ServerAddress::Localhost => files
|
||||||
for file in &files {
|
.iter()
|
||||||
check_local_file_exists(file_server.server_directory_path.join(file))?;
|
.map(|file| file_server.server_directory_path.join(file))
|
||||||
}
|
.try_for_each(check_local_file_exists)?,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
None => {
|
None => files.iter().try_for_each(check_local_file_exists)?,
|
||||||
for file in &files {
|
|
||||||
check_local_file_exists(file)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let file_details = files
|
let file_details = files
|
||||||
@ -587,7 +582,7 @@ where
|
|||||||
.collect_output()
|
.collect_output()
|
||||||
{
|
{
|
||||||
Ok(_) => Ok(()), //file exists on file server
|
Ok(_) => Ok(()), //file exists on file server
|
||||||
Err(SpecificExecutionError {
|
Err(CommandSpecificError {
|
||||||
error: ExecutionError::BadExitStatus(_), //test failed
|
error: ExecutionError::BadExitStatus(_), //test failed
|
||||||
..
|
..
|
||||||
}) => Err(format!(
|
}) => Err(format!(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user