use crate::entries::Entry;
use crate::fetcher::{Fetcher, FetcherArgs};
use crate::warning;
use anyhow::{Result, anyhow};
use std::path::PathBuf;
#[derive(Debug)]
pub struct InputInfo {
pub num_valid: usize,
pub had_invalid: bool,
}
impl TryFrom<FetcherArgs> for (Fetcher, InputInfo) {
type Error = anyhow::Error;
fn try_from(args: FetcherArgs) -> Result<(Fetcher, InputInfo)> {
let (dirs, info) = validate(args.dirs)?;
Ok((
Fetcher {
dirs,
recursion: args.recursion.into(),
filter: args.filter.try_into()?,
},
info,
))
}
}
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() {
warning!("duplicated directories: {}", 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) => {
warning!("entry is not a directory: {entry}");
None
}
Err((pb, err)) => {
warning!("invalid path: {pb:?}: {err}");
None
}
})
.collect::<Vec<_>>();
let had_invalid = n != dirs.len();
let dirs = dirs
.into_iter()
.fold(Vec::new(), |mut acc: Vec<Entry>, entry| {
match acc.last().is_some_and(|prev| {
let (s, p) = (entry.to_str(), prev.to_str());
s.starts_with(p) && s[p.len()..].starts_with('/')
}) {
true => warning!("dir is contained within another: {entry}"),
false => acc.push(entry),
}
acc
});
if dirs.is_empty() {
return Err(anyhow!("no valid paths given"));
}
let info = InputInfo {
num_valid: dirs.len(),
had_invalid,
};
Ok((dirs, info))
}