2023-04-19 21:49:30 +02:00
|
|
|
use crate::utils::cmd::Cmd;
|
|
|
|
|
|
|
|
use std::path::PathBuf;
|
|
|
|
|
|
|
|
pub mod builder;
|
|
|
|
pub mod condition;
|
|
|
|
|
|
|
|
use builder::{CommandBuilder, NoCondition, NoCmd};
|
|
|
|
use condition::SomeCondition;
|
|
|
|
|
|
|
|
use crate::{Module, ModuleSetup, Facts};
|
|
|
|
|
|
|
|
/// A copy of the argument passed to the [`CommandBuilder`],
|
|
|
|
/// as returned serialized in the task run output
|
2023-10-05 17:58:41 +02:00
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
2023-04-19 21:49:30 +02:00
|
|
|
pub struct CommandArgs {
|
|
|
|
#[serde(flatten)]
|
|
|
|
pub args: Cmd,
|
|
|
|
pub condition: Option<SomeCondition>,
|
|
|
|
}
|
|
|
|
|
2023-10-05 17:58:41 +02:00
|
|
|
impl ModuleSetup<CommandModule, CommandArgs, CommandStatus, CommandError> for CommandArgs {
|
|
|
|
fn with_facts(self, _facts: &Facts) -> CommandModule {
|
|
|
|
CommandModule {
|
|
|
|
cmd: self.args,
|
|
|
|
condition: self.condition,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
2023-04-19 21:49:30 +02:00
|
|
|
pub struct CommandModule {
|
|
|
|
cmd: Cmd,
|
|
|
|
condition: Option<SomeCondition>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CommandModule {
|
|
|
|
pub fn new() -> CommandBuilder<NoCmd, NoCondition> {
|
|
|
|
CommandBuilder::new()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-20 12:44:48 +02:00
|
|
|
impl ModuleSetup<CommandModule, CommandArgs, CommandStatus, CommandError> for CommandModule {
|
|
|
|
fn with_facts(self, _facts: &Facts) -> CommandModule {
|
|
|
|
self
|
2023-04-19 21:49:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Module<CommandArgs, CommandStatus, CommandError> for CommandModule {
|
|
|
|
|
|
|
|
fn serialize_args(&self) -> serde_json::Value {
|
|
|
|
serde_json::to_value(&CommandArgs {
|
|
|
|
args: self.cmd.clone(),
|
|
|
|
condition: self.condition.clone(),
|
|
|
|
}).unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn module_name(&self) -> &'static str {
|
|
|
|
"command"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run(self) -> Result<CommandStatus, CommandError> {
|
|
|
|
// The command was built successfully, run it
|
|
|
|
let Self { cmd, condition, .. } = self;
|
|
|
|
|
|
|
|
// Check conditions
|
|
|
|
if let Some(condition) = condition {
|
|
|
|
if ! condition.should_run() {
|
|
|
|
return Ok(CommandStatus::Skipped(condition));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let res = cmd.run()?;
|
|
|
|
|
|
|
|
Ok(CommandStatus::Done(
|
|
|
|
CommandReturn {
|
|
|
|
success: res.success,
|
|
|
|
stdin: res.stdin,
|
|
|
|
dir: res.dir,
|
|
|
|
stdout: res.stdout,
|
|
|
|
stderr: res.stderr,
|
|
|
|
}
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Command module has inner parameters to determine whether the command should run (`creates` and `removes`). Because of this,
|
|
|
|
/// it returns a special [`CommandStatus`] that can be Done or Skipped. These variants are flattened into the textual/JSON output
|
|
|
|
#[derive(Clone, Debug, Serialize)]
|
|
|
|
#[serde(tag="status")]
|
|
|
|
pub enum CommandStatus {
|
|
|
|
#[serde(rename="done")]
|
|
|
|
Done(CommandReturn),
|
|
|
|
#[serde(rename="skip")]
|
|
|
|
Skipped(SomeCondition),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CommandStatus {
|
|
|
|
pub fn success(&self) -> bool {
|
|
|
|
match self {
|
|
|
|
Self::Done(ret) => ret.success,
|
|
|
|
Self::Skipped(_c) => true,
|
|
|
|
}
|
|
|
|
}
|
2023-04-21 17:25:31 +02:00
|
|
|
|
|
|
|
pub fn stdout(&self) -> Option<String> {
|
|
|
|
match self {
|
|
|
|
Self::Done(ret) => Some(ret.stdout.to_string()),
|
|
|
|
Self::Skipped(_c) => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn stderr(&self) -> Option<String> {
|
|
|
|
match self {
|
|
|
|
Self::Done(ret) => Some(ret.stdout.to_string()),
|
|
|
|
Self::Skipped(_c) => None,
|
|
|
|
}
|
|
|
|
}
|
2023-04-19 21:49:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Return of a Command that was effectively run
|
|
|
|
#[derive(Clone, Debug, Serialize)]
|
|
|
|
pub struct CommandReturn {
|
|
|
|
pub success: bool,
|
|
|
|
pub stdin: Option<String>,
|
|
|
|
pub dir: Option<PathBuf>,
|
|
|
|
pub stdout: String,
|
|
|
|
pub stderr: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Serialize)]
|
|
|
|
pub struct CommandSkipped(SomeCondition);
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Serialize)]
|
|
|
|
pub struct CommandError(String);
|
|
|
|
|
|
|
|
impl From<std::io::Error> for CommandError {
|
|
|
|
fn from(e: std::io::Error) -> CommandError {
|
|
|
|
CommandError(e.to_string())
|
|
|
|
}
|
|
|
|
}
|