use anyhow::Result;
use fs2::FileExt;
use std::fs;
use std::path::PathBuf;
use crate::default::default::default_flows;
use crate::models::flow::FlowModel;
use crate::utils;
use crate::validate::ValidateTrait;
#[derive(Debug, Clone)]
pub struct FlowsModel {
pub flows: Vec<FlowModel>,
}
impl FlowsModel {
pub fn find(&self, name: &str) -> Option<&FlowModel> {
self.flows.iter().find(|f| f.name == name)
}
pub fn load() -> Result<Self> {
let path = utils::path::actions_dir();
let cache_dir = utils::path::cache_dir();
fs::create_dir_all(&path)?;
fs::create_dir_all(&cache_dir)?;
let lock_file = cache_dir.join(".lock");
let _lock = std::fs::File::create(&lock_file)?;
_lock.lock_exclusive()?;
Self::load_inner(&path, &cache_dir).map_err(|e| {
vibe_fs::clean(&path, Some(&cache_dir)).ok();
e
})
}
fn load_inner(path: &PathBuf, cache_dir: &PathBuf) -> Result<Self> {
let scan = vibe_fs::scan(path, false, Some(cache_dir), Some(&["yaml", "yml"]))?;
if scan.changed.is_empty() && scan.unchanged.is_empty() {
Self::save_defaults(path)?;
vibe_fs::scan(path, true, Some(cache_dir), Some(&["yaml", "yml"]))?;
return Self::load_inner(path, cache_dir);
}
let has_changes = !scan.changed.is_empty();
if has_changes {
for file_path in &scan.changed {
let flow = FlowModel::load(file_path)?;
flow.validate().map_err(|e| {
anyhow::anyhow!("Validation failed for {}: {}", file_path.display(), e)
})?;
}
}
let mut actions = Self { flows: vec![] };
for file_path in scan.changed.iter().chain(scan.unchanged.iter()) {
let flow = FlowModel::load(file_path)?;
actions.flows.push(flow);
}
if has_changes {
actions.validate()?;
}
Ok(actions)
}
fn save_defaults(path: &PathBuf) -> Result<()> {
if !path.exists() {
fs::create_dir_all(path)?;
}
for flow in default_flows() {
let yaml = flow.flow()?;
let name = flow.name()?;
let file_path = path.join(format!("{}.yaml", name));
if file_path.exists() {
continue;
}
fs::write(&file_path, &yaml)?;
}
Ok(())
}
}