use crate::core::shell_escape::{render_command_inline, sh_squote};
use crate::core::types::Resource;
use crate::resources::verdict;
pub fn state_query_script(resource: &Resource) -> String {
if !resource.output_artifacts.is_empty() {
let hash_cmds: Vec<String> = resource
.output_artifacts
.iter()
.map(|a| {
let q = sh_squote(a);
format!(
"[ -f {q} ] && b3sum {q} 2>/dev/null || echo {}",
sh_squote(&format!("missing:{a}"))
)
})
.collect();
return hash_cmds.join("\n");
}
if let Some(ref check) = resource.completion_check {
return verdict::single(check, "task=completed", "task=pending");
}
let command = resource.command.as_deref().unwrap_or("true");
format!(
"printf '%s\\n' {}",
sh_squote(&format!(
"unobservable:no-completion-check:{}",
render_command_inline(command)
))
)
}
pub fn scatter_script(resource: &Resource) -> Option<String> {
if resource.scatter.is_empty() {
return None;
}
let mut script = String::from("set -euo pipefail\n# FJ-2704: scatter artifacts\n");
for mapping in &resource.scatter {
if let Some((local, remote)) = mapping.split_once(':') {
let (l, r) = (sh_squote(local), sh_squote(remote));
script.push_str(&format!("mkdir -p \"$(dirname {r})\"\ncp -r {l} {r}\n"));
}
}
Some(script)
}
pub fn gather_script(resource: &Resource) -> Option<String> {
if resource.gather.is_empty() {
return None;
}
let mut script = String::from("set -euo pipefail\n# FJ-2704: gather artifacts\n");
for mapping in &resource.gather {
if let Some((remote, local)) = mapping.split_once(':') {
let (r, l) = (sh_squote(remote), sh_squote(local));
script.push_str(&format!("mkdir -p \"$(dirname {l})\"\ncp -r {r} {l}\n"));
}
}
Some(script)
}