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)) } } } 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; 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 + } + } } } }