use anyhow::bail;
use serde::{Deserialize, Serialize};
use std::io::Read;
use std::path::PathBuf;
use crate::bmap;
use crate::entities::auto_version::AutoVersionExtractFromRule;
use crate::entities::environment::RunEnvironment;
use crate::entities::info::ContentInfo;
use crate::entities::placements::Placement;
use crate::storage::{add_single_to_storage, add_to_storage};
#[derive(Deserialize, Serialize, PartialEq, Eq, PartialOrd, Ord, Clone)]
pub struct AddToStorageAction {
pub short_name: String,
pub auto_version_rule: AutoVersionExtractFromRule,
#[serde(default, skip_serializing_if = "PutContentRule::is_default")]
pub content: PutContentRule,
}
impl AddToStorageAction {
pub async fn execute(&self, env: &RunEnvironment<'_>) -> anyhow::Result<(bool, Vec<String>)> {
let version = match &self.auto_version_rule {
AutoVersionExtractFromRule::CmdStdout { cmd } => {
let (succ, out) = cmd.execute(env, &bmap!()).await?;
if !succ || out.is_empty() {
return Ok((false, out));
}
out.last().unwrap().trim().replace(">>> ", "")
}
AutoVersionExtractFromRule::PlainFile { path } => {
let mut file = std::fs::File::open(path)?;
let mut ver = String::new();
file.read_to_string(&mut ver)?;
ver.trim().to_string()
}
};
let info = ContentInfo::new(self.short_name.as_str(), version.as_str())?;
Ok(match &self.content {
PutContentRule::Artifacts => {
if let Err(e) = add_to_storage(env.storage_dir, env.artifacts_dir, &info) {
(false, vec![e.to_string()])
} else {
(true, vec![])
}
}
PutContentRule::FixedFiles { placements } => {
for placement in placements {
if let Err(e) = add_single_to_storage(
env.storage_dir,
&env.run_dir.join(&placement.from),
&PathBuf::from(placement.to.as_str()),
&info,
) {
return Ok((false, vec![e.to_string()]));
}
}
(true, vec![])
}
})
}
pub async fn to_shell(&self, _: &RunEnvironment<'_>) -> anyhow::Result<Vec<String>> {
bail!("`AddToStorage` actions can't be translated into shell script!")
}
}
#[derive(Deserialize, Serialize, Default, PartialEq, Eq, PartialOrd, Ord, Clone)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum PutContentRule {
#[default]
Artifacts,
FixedFiles {
placements: Vec<Placement>,
},
}
impl PutContentRule {
fn is_default(&self) -> bool {
matches!(self, PutContentRule::Artifacts)
}
}