cockup 0.2.3

Yet another backup tool for various configurations
use super::{rules::rule, state::CopyState};
use crate::{
    config::{Config, Symlinks},
    manifest, report,
};
use std::fs;

pub(super) fn run(cfg: &Config, state: &mut CopyState) -> Result<(), String> {
    if state.restore && !cfg.destination.is_dir() {
        return Err("Backup destination is not a directory".into());
    }
    if !state.restore && fs::symlink_metadata(&cfg.destination).is_ok() && !cfg.destination.is_dir()
    {
        return Err("Backup destination is not a directory".into());
    }
    println!(
        "Dry run: {} (no files changed; hooks skipped)",
        if state.restore { "restore" } else { "backup" }
    );
    for hook in cfg.all_hooks().filter(|hook| hook.cwd.is_some()) {
        let directory = crate::hooks::directory(hook, &cfg.directory)
            .map_err(|error| format!("Hook `{}` {error}", hook.name))?;
        println!(
            "Would run hook `{}` in: {} (skipped)",
            hook.name,
            directory.display()
        );
    }
    if !state.restore && cfg.clean && cfg.destination.is_dir() {
        for entry in fs::read_dir(&cfg.destination).map_err(|e| e.to_string())? {
            let entry = entry.map_err(|e| e.to_string())?;
            if entry.file_name() != manifest::NAME && entry.file_name() != ".cockup-incomplete" {
                println!("Would remove: {}", entry.path().display());
            }
        }
    }
    state.planning = true;
    let mut failures = 0;
    for config_rule in &cfg.rules {
        failures += rule(
            config_rule,
            &cfg.destination,
            state.restore,
            config_rule.metadata.unwrap(),
            if state.restore {
                Symlinks::Reference
            } else {
                config_rule.symlinks.unwrap()
            },
            state,
        );
    }
    if failures > 0 {
        return Err(format!("Dry run completed with {failures} failures."));
    }
    report::success("Dry run completed; no files changed.");
    Ok(())
}