index : git-mirror-sync.git

ascending towards madness

use std::path::PathBuf;

use clap::Parser;
use humantime::Duration;

use crate::error::ParseError;

#[derive(Debug, Parser)]
pub struct CliArgs {
    /// The time to wait before refreshing repositories.
    /// eg. 10m, 60s, etc.
    #[clap(short, long, default_value = "10m")]
    #[arg(value_parser = parse_refresh_time)]
    pub refresh_time: Duration,

    /// The directory to search for git repositories.
    /// This must be valid, and accessible by the application.
    #[clap(required = true)]
    #[arg(value_parser = parse_directory)]
    pub directory: PathBuf,

    /// The limit to the depth of recursion in the directory tree.
    /// Keep this number reasonable.
    #[clap(short, long, default_value_t = 3)]
    pub max_recursion_depth: usize,
}

impl Default for CliArgs {
    fn default() -> Self {
        Self {
            refresh_time: parse_refresh_time("10m").unwrap(),
            directory: Default::default(),
            max_recursion_depth: 3,
        }
    }
}

/// Parses the given string argument into a `PathBuf` and checks if it is a valid directory.
///
/// # Arguments
///
/// - `arg` - A string containing the path to be parsed.
///
/// # Returns
///
/// This function returns `Ok(PathBuf)` if the path is a valid directory,
/// or `Err(ParseError)` if the path is not a valid directory.
fn parse_directory(arg: &str) -> Result<PathBuf, ParseError> {
    let directory = PathBuf::from(arg);

    if directory.exists() && directory.is_dir() {
        Ok(PathBuf::from(arg))
    } else {
        Err(ParseError::new(
            "path does not exist or is not a directory.",
        ))
    }
}

/// Parses a duration string into a `humantime::Duration`.
///
/// This function takes a duration string (e.g., "10m", "2h 15min")
/// and parses it to `humantime::Duration`.
///
/// # Arguments
///
/// - `arg` - A string representing the duration.
///
/// # Returns
///
/// A `Result` which is `Ok(humantime::Duration)` if the string is successfully parsed,
/// or `Err(ParseError)` if unsuccessful.
fn parse_refresh_time(arg: &str) -> Result<humantime::Duration, ParseError> {
    arg.parse::<humantime::Duration>().map_err(ParseError::from)
}