use globset::{Glob, GlobSet, GlobSetBuilder};
use std::sync::Arc;
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum OutputFormat {
Text,
Json,
Csv,
}
impl OutputFormat {
pub fn from_flags(json: bool, csv: bool) -> Self {
if json {
OutputFormat::Json
} else if csv {
OutputFormat::Csv
} else {
OutputFormat::Text
}
}
pub fn extension(self) -> &'static str {
match self {
OutputFormat::Text => "txt",
OutputFormat::Json => "json",
OutputFormat::Csv => "csv",
}
}
}
#[derive(Clone, Copy)]
pub struct ScanOptions {
pub quiet: bool,
pub threads: Option<usize>,
pub follow_symlinks: bool,
pub max_depth: Option<usize>,
pub sizes: bool,
pub format: OutputFormat,
}
pub struct ScanFilter {
ext: Option<Vec<String>>,
exclude: Option<Arc<GlobSet>>,
}
impl ScanFilter {
pub fn new(ext_args: &[String], exclude_args: &[String]) -> Result<Self, String> {
let ext = if ext_args.is_empty() {
None
} else {
Some(
ext_args
.iter()
.map(|e| format!(".{}", e.trim().trim_start_matches('.').to_lowercase()))
.collect(),
)
};
let exclude = if exclude_args.is_empty() {
None
} else {
let mut builder = GlobSetBuilder::new();
for pattern in exclude_args {
let glob = Glob::new(pattern)
.map_err(|e| format!("invalid --exclude pattern '{pattern}': {e}"))?;
builder.add(glob);
}
let set = builder
.build()
.map_err(|e| format!("failed to build exclude patterns: {e}"))?;
Some(Arc::new(set))
};
Ok(ScanFilter { ext, exclude })
}
pub fn ext_allowed(&self, ext: &str) -> bool {
match &self.ext {
Some(allowed) => allowed.iter().any(|e| e == ext),
None => true,
}
}
pub fn exclude(&self) -> Option<&Arc<GlobSet>> {
self.exclude.as_ref()
}
}