use super::helpers::*;
use super::helpers_state::*;
use crate::core::{planner, resolver, types};
use std::path::Path;
pub(super) fn print_dry_run_actions(
config: &types::ForjarConfig,
state_dir: &Path,
machine_filter: Option<&str>,
tag_filter: Option<&str>,
) -> Result<(), String> {
let execution_order = resolver::build_execution_order(config)?;
let plan_locks = load_machine_locks(config, state_dir, machine_filter)?;
let mut plan = planner::plan(config, &execution_order, &plan_locks, tag_filter);
super::plan_selector::apply_machine_filter(&mut plan, machine_filter);
print!("{}", render_dry_run_actions(&plan));
Ok(())
}
pub(super) fn render_dry_run_actions(plan: &types::ExecutionPlan) -> String {
use std::fmt::Write;
let mut out = String::new();
let _ = writeln!(out, "{}", bold("Dry run — would execute:"));
for change in &plan.changes {
let icon = match change.action {
types::PlanAction::Create => green("+"),
types::PlanAction::Update => yellow("~"),
types::PlanAction::Destroy => red("-"),
types::PlanAction::NoOp => dim("="),
};
let _ = writeln!(
out,
" {} {} on {}: {}",
icon, change.resource_id, change.machine, change.description
);
}
if plan.changes.is_empty() {
let _ = writeln!(out, " {}", dim("(nothing selected)"));
}
let _ = writeln!(
out,
"\n{} to add, {} to change, {} to destroy, {} unchanged. No changes applied.",
plan.to_create, plan.to_update, plan.to_destroy, plan.unchanged
);
out
}