From d33daf85a3b7f39f6790ad0b86aec1262fc9d340 Mon Sep 17 00:00:00 2001 From: kdesjard Date: Mon, 11 Dec 2023 14:10:30 +0000 Subject: [PATCH 1/3] allow the use of the Content struct Signed-off-by: kdesjard --- src/task/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/task/mod.rs b/src/task/mod.rs index 3cdb3f9..7d11590 100644 --- a/src/task/mod.rs +++ b/src/task/mod.rs @@ -30,7 +30,8 @@ use std::sync::atomic::AtomicUsize; pub use self::action::{Action, Complex, Simple}; pub use self::cmd::CommandAction; pub use self::default_task::DefaultTask; -pub(crate) use self::state::{Content, ExecState}; +pub use self::state::Content; +pub(crate) use self::state::ExecState; pub use self::state::{Input, Output}; mod action; From 4c84d9fc460e15137e1c42ca0fbc8f53f00a6174 Mon Sep 17 00:00:00 2001 From: kdesjard Date: Mon, 11 Dec 2023 14:12:14 +0000 Subject: [PATCH 2/3] For the Err variant of Output, allow for the capturing of an exit code in the case of an error and allow for setting a Content payload Signed-off-by: kdesjard --- src/task/state.rs | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/task/state.rs b/src/task/state.rs index a81acc1..80c1bb0 100644 --- a/src/task/state.rs +++ b/src/task/state.rs @@ -22,7 +22,8 @@ //! //! ```rust //! use dagrs::Output; -//! let err_out = Output::Err("some error messages!".to_string()); +//! use dagrs::task::Content; +//! let err_out = Output::Err(None,Some(Content::new("some error messages!".to_string()))); //! ``` //! //! # [`Input`] @@ -95,7 +96,7 @@ pub(crate) struct ExecState { #[derive(Debug)] pub enum Output { Out(Option), - Err(String), + Err(Option,Option), } /// Task's input value. @@ -165,14 +166,14 @@ impl Output { } /// Construct an [`Output`]` with an error message. - pub fn error(msg: String) -> Self { - Self::Err(msg) + pub fn error(code: Option, msg: String) -> Self { + Self::Err(code,Some(Content::new(msg))) } /// Determine whether [`Output`] stores error information. pub(crate) fn is_err(&self) -> bool { match self { - Self::Err(_) => true, + Self::Err(_,_) => true, Self::Out(_) => false, } } @@ -181,7 +182,7 @@ impl Output { pub(crate) fn get_out(&self) -> Option { match self { Self::Out(ref out) => out.clone(), - Self::Err(_) => None, + Self::Err(_,_) => None, } } @@ -189,7 +190,13 @@ impl Output { pub(crate) fn get_err(&self) -> Option { match self { Self::Out(_) => None, - Self::Err(err) => Some(err.to_string()), + Self::Err(_,err) => { + if let Some(e) = err { + Some(e.get::()?.to_string()) + } else { + None + } + } } } } From d2806af9b3151ac4a79d865fc672399905f9008f Mon Sep 17 00:00:00 2001 From: kdesjard Date: Mon, 11 Dec 2023 14:13:27 +0000 Subject: [PATCH 3/3] Captue stdout and stderr regardless of whether a task was successful or not. Convert stdout and stderr into a Vec of Strings for downstream use. In the case an error, attempt return the operating systems exit code Signed-off-by: kdesjard --- src/task/cmd.rs | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/task/cmd.rs b/src/task/cmd.rs index 0faa781..a0ab576 100644 --- a/src/task/cmd.rs +++ b/src/task/cmd.rs @@ -2,6 +2,8 @@ use crate::{Complex, EnvVar, Input, Output}; use std::process::Command; use std::sync::Arc; +use crate::task::Content; + /// [`CommandAction`] is a specific implementation of [`Complex`], used to execute operating system commands. pub struct CommandAction { command: String, @@ -33,19 +35,38 @@ impl Complex for CommandAction { args.push(inp) } }); - let out = match cmd.args(args).output() { - Ok(o) => o, - Err(e) => return Output::Err(e.to_string()), + let(code,out) = match cmd.args(args).output() { + Ok(o) => { + (0,o) + }, + Err(e) => { + return Output::Err( + e.raw_os_error(), + Some(Content::new(e.to_string())) + ) + } }; - - if out.status.success() { - let mut out = String::from_utf8(out.stdout).unwrap(); + let stdout: Vec = { + let out = String::from_utf8(out.stdout).unwrap_or("".to_string()); if cfg!(target_os = "windows") { - out = out.replace("\r\n", " ").replace('\n', " "); + out.rsplit_terminator("\r\n").map(str::to_string).collect() + } else { + out.split_terminator('\n').map(str::to_string).collect() } - Output::new(out) + }; + let stderr: Vec = { + let out = String::from_utf8(out.stderr).unwrap_or("".to_string()); + if cfg!(target_os = "windows") { + out.rsplit_terminator("\r\n").map(str::to_string).collect() + } else { + out.split_terminator('\n').map(str::to_string).collect() + } + }; + let output = Content::new((stdout,stderr)); + if out.status.success() { + Output::new(output) } else { - Output::Err(String::from_utf8(out.stderr).unwrap()) + Output::Err(Some(code),Some(output)) } } }