use std::fs;
use std::path::Path;
use crate::spec::{Deployment, Lock};
use super::{DeploymentStatus, Plan, builtin};
pub fn execute_plan(
root: &Path,
plan: &Plan,
_old_lock: &Lock,
check: bool,
) -> anyhow::Result<Lock> {
if plan.has_conflicts() {
let reasons: Vec<&str> = plan
.items
.iter()
.filter_map(|d| match &d.status {
DeploymentStatus::Conflict { reason } => Some(reason.as_str()),
_ => None,
})
.collect();
anyhow::bail!("unresolved conflicts:\n{}", reasons.join("\n"));
}
let mut deployments = Vec::new();
for item in &plan.items {
match &item.status {
DeploymentStatus::Create | DeploymentStatus::Update => {
let target = root.join(&item.target_path);
if !check {
if let Some(parent) = target.parent() {
fs::create_dir_all(parent)?;
}
fs::write(&target, &item.rendered_content)?;
}
if item.rule_id != builtin::BUILTIN_RTANGO_RULE_ID {
deployments.push(Deployment {
rule_id: item.rule_id.clone(),
agent: item.agent.clone(),
source: item.source.clone(),
source_hash: item.source_hash.clone(),
content: item.target_path.clone(),
content_hash: super::hash_content(&item.rendered_content),
});
}
}
DeploymentStatus::UpToDate => {
if item.rule_id != builtin::BUILTIN_RTANGO_RULE_ID {
deployments.push(Deployment {
rule_id: item.rule_id.clone(),
agent: item.agent.clone(),
source: item.source.clone(),
source_hash: item.source_hash.clone(),
content: item.target_path.clone(),
content_hash: super::hash_content(&item.rendered_content),
});
}
}
DeploymentStatus::Orphan => {
let target = root.join(&item.target_path);
if !check && target.exists() {
fs::remove_file(&target)?;
}
}
DeploymentStatus::Conflict { .. } => {
unreachable!();
}
}
}
Ok(Lock {
version: 1,
tracked_agents: vec![], owners: plan.owners.clone(),
deployments,
})
}