guardy 0.2.4

Fast, secure git hooks in Rust with secret scanning and protected file synchronization
Documentation
use std::sync::Arc;

use crate::{cli::commands::sync::SyncArgs, config_build};

config_build! {
    SyncConfig<crate::cli::commands::sync::SyncArgs> {
        // Force update without prompts
        force: bool => {
            cli: |args: &SyncArgs| {
                // Check both main args and subcommand args
                if args.force {
                    Some(true)
                } else if let Some(crate::cli::commands::sync::SyncSubcommand::Update { force, .. }) = &args.command {
                    Some(*force)
                } else {
                    None
                }
            },
            env: "GUARDY_SYNC_FORCE",
            default: false,
        },

        // Auto-update files without confirmation
        auto_update: bool => {
            env: "GUARDY_SYNC_AUTO_UPDATE",
            default: false,
        },

        // Interactive mode (prompts for confirmation)
        interactive: bool => {
            cli: |args: &SyncArgs| {
                // If force is true, interactive should be false
                if args.force {
                    Some(false)
                } else if let Some(crate::cli::commands::sync::SyncSubcommand::Update { force, .. }) = &args.command {
                    Some(!force)
                } else {
                    None
                }
            },
            env: "GUARDY_SYNC_INTERACTIVE",
            default: true,
        },

        // Always show diff before updating (used in interactive mode)
        show_diff: bool => {
            env: "GUARDY_SYNC_SHOW_DIFF",
            default: true,
        },

        // Git operation timeout in seconds
        git_timeout_seconds: u32 => {
            env: "GUARDY_SYNC_GIT_TIMEOUT",
            default: 30,
        },

        // Number of context lines to show in diffs
        diff_context_lines: u8 => {
            env: "GUARDY_SYNC_DIFF_CONTEXT",
            default: 3,
        },

        // Cache directory path (relative to project root)
        cache_dir: String => {
            env: "GUARDY_SYNC_CACHE_DIR",
            default: ".guardy/cache".to_string(),
        },

        // Single repo URL (from CLI/ENV/file)
        repo: Option<String> => {
            cli: |args: &SyncArgs| {
                args.repo.clone().or_else(|| {
                    if let Some(crate::cli::commands::sync::SyncSubcommand::Update { repo, .. }) = &args.command {
                        repo.clone()
                    } else {
                        None
                    }
                })
            },
            env: "GUARDY_SYNC_REPO",
            default: None,
        },

        // Single repo version (from CLI/ENV/file)
        version: Option<String> => {
            cli: |args: &SyncArgs| {
                args.version.clone().or_else(|| {
                    if let Some(crate::cli::commands::sync::SyncSubcommand::Update { version, .. }) = &args.command {
                        version.clone()
                    } else {
                        None
                    }
                })
            },
            env: "GUARDY_SYNC_VERSION",
            default: None,
        },

        // Single repo source path (from CLI/ENV/file)
        source_path: Option<String> => {
            cli: |args: &SyncArgs| {
                args.source_path.clone().or_else(|| {
                    if let Some(crate::cli::commands::sync::SyncSubcommand::Update { source_path, .. }) = &args.command {
                        source_path.clone()
                    } else {
                        None
                    }
                })
            },
            env: "GUARDY_SYNC_SOURCE_PATH",
            default: None,
        },

        // Single repo destination path (from CLI/ENV/file)
        dest_path: Option<String> => {
            cli: |args: &SyncArgs| {
                args.dest_path.clone().or_else(|| {
                    if let Some(crate::cli::commands::sync::SyncSubcommand::Update { dest_path, .. }) = &args.command {
                        dest_path.clone()
                    } else {
                        None
                    }
                })
            },
            env: "GUARDY_SYNC_DEST_PATH",
            default: None,
        },

        // Single repo include patterns (from CLI/ENV/file)
        include: Vec<String> => {
            cli: |args: &SyncArgs| {
                let mut patterns = args.include.clone();
                if let Some(crate::cli::commands::sync::SyncSubcommand::Update { include, .. }) = &args.command {
                    patterns.extend(include.clone());
                }
                if patterns.is_empty() { None } else { Some(patterns) }
            },
            env: "GUARDY_SYNC_INCLUDE",
            default: Vec::new(),
        },

        // Single repo exclude patterns (from CLI/ENV/file)
        exclude: Vec<String> => {
            cli: |args: &SyncArgs| {
                let mut patterns = args.exclude.clone();
                if let Some(crate::cli::commands::sync::SyncSubcommand::Update { exclude, .. }) = &args.command {
                    patterns.extend(exclude.clone());
                }
                if patterns.is_empty() { None } else { Some(patterns) }
            },
            env: "GUARDY_SYNC_EXCLUDE",
            default: Vec::new(),
        },

        // Repository configurations loaded from file (complex nested structures)
        repolist: Arc<Vec<RepoConfig>> => {
            default: Arc::new(Vec::new()),
        },
    }
}

// Repository configuration structure for sync functionality
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct RepoConfig {
    pub name: Arc<str>,
    pub repo: Arc<str>,
    pub version: Arc<str>,
    pub source_path: Arc<str>,
    pub dest_path: Arc<str>,
    #[serde(default)]
    pub include: Vec<String>,
    #[serde(default)]
    pub exclude: Vec<String>,
    #[serde(default)]
    pub protected: bool,
}