use std::{fs, io, path};
#[derive(Default)]
pub struct Config {
pub all_urls: bool,
pub ignore_urls: Vec<String>,
pub list_files: bool,
pub verbose: bool,
}
impl Config {
pub fn new() -> Self {
Self::default()
}
pub fn all_urls(mut self) -> Self {
self.all_urls = true;
self
}
pub fn ignore_urls(mut self, ignore_urls: &str) -> Self {
self.ignore_urls = ignore_urls.split(',').map(|s| s.to_string()).collect();
self
}
pub fn list_files(mut self) -> Self {
self.list_files = true;
self
}
}
pub struct Info {
pub files_list: Option<Vec<String>>,
pub num_files: u64,
pub num_urls: u64,
}
pub struct FileURL {
pub url: String,
pub filepath: String,
pub bad: bool,
pub line: usize,
pub col: usize,
}
pub fn check_paths(
input_paths: &[&str],
config: Option<&Config>,
) -> Result<(Vec<FileURL>, Info), io::Error> {
let verbose = config.map_or(false, |config| config.verbose);
let mut files_list: Option<Vec<String>> = if config.map_or(false, |config| config.list_files) {
Some(Vec::new())
} else {
None
};
let mut urls = vec![];
let mut num_files = 0;
let mut num_urls = 0;
for path in input_paths {
if verbose {
println!("Checking {}...", path);
}
let metadata = fs::metadata(path)?;
if metadata.is_dir() {
if verbose {
println!("Recursing into directory {}...", path);
}
let entries = fs::read_dir(path)?;
let pathbufs = entries
.map(|entry| Ok(entry?.path()))
.collect::<Result<Vec<path::PathBuf>, io::Error>>()?;
let paths = pathbufs
.iter()
.map(|path| path.to_str().unwrap())
.collect::<Vec<&str>>();
let (new_urls, info) = check_paths(&paths, config)?;
urls.extend(new_urls);
if let Some(ref mut files) = files_list {
files.extend(info.files_list.unwrap());
}
num_files += info.num_files;
num_urls += info.num_urls;
if verbose {
println!("Leaving directory {}...", path);
}
} else if metadata.is_file() {
if let Some(ref mut files) = files_list {
files.push(path.to_string());
}
num_files += 1;
}
}
let info = Info { files_list, num_files, num_urls };
Ok((urls, info))
}