use crate::entries::{Entry, Fetcher, Filter};
use anyhow::{Result, anyhow};
use clap::Args;
use std::path::PathBuf;
#[derive(Debug, Args)]
pub struct Input {
#[arg(long, global = true)]
show: bool,
#[arg(global = true, help_heading = None)]
dirs: Vec<PathBuf>,
#[arg(short = 'R', long, default_value_t = 0, value_name = "INT", global = true, help_heading = Some("Fetch"))]
recursion: u32,
#[command(flatten)]
filter: Filter,
}
#[derive(Debug)]
pub struct EffectiveInput {
pub show: bool,
pub info: InputInfo,
fetcher: Fetcher,
}
impl EffectiveInput {
pub fn fetcher(self) -> Fetcher {
self.fetcher
}
}
#[derive(Debug)]
pub struct InputInfo {
pub num_valid: usize,
pub has_invalid: bool,
}
impl TryFrom<Input> for EffectiveInput {
type Error = anyhow::Error;
fn try_from(input: Input) -> Result<EffectiveInput> {
let (dirs, info) = validate(input.dirs)?;
if dirs.is_empty() {
return Err(anyhow!("no valid paths given"));
}
let filter = input.filter.try_into()?;
let fetcher = Fetcher::new(dirs, input.recursion.into(), filter);
let ei = EffectiveInput {
show: input.show,
info,
fetcher,
};
Ok(ei)
}
}
fn validate(mut dirs: Vec<PathBuf>) -> Result<(Vec<Entry>, InputInfo)> {
if dirs.is_empty() {
dirs = vec![".".into()]; }
let n = dirs.len();
dirs.sort_unstable();
dirs.dedup();
if n != dirs.len() {
eprintln!("warning: {} duplicated directories ignored", n - dirs.len());
}
let n = dirs.len();
let dirs = dirs
.into_iter()
.map(Entry::try_from)
.filter_map(|res| match res {
Ok(entry) if entry.is_dir() => Some(entry),
Ok(entry) => {
eprintln!("warning: {entry} is not a directory, skipping");
None
}
Err((pb, err)) => {
eprintln!("warning: invalid path {pb:?}: {err}");
None
}
})
.collect::<Vec<_>>();
if dirs.is_empty() {
return Err(anyhow!("no valid paths given"));
}
let info = InputInfo {
num_valid: dirs.len(),
has_invalid: n != dirs.len(),
};
Ok((dirs, info))
}