use anyhow::Result;
use std::path::Path;
use std::path::PathBuf;
use crate::adoption::exclusion::Exclusion;
use crate::adoption::exclusion_outcome::ExclusionOutcome;
pub struct ExclusionSet {
exclusions: Vec<Exclusion>,
}
impl ExclusionSet {
pub fn new(patterns: &[String]) -> Result<Self> {
let exclusions = patterns
.iter()
.map(|pattern| Exclusion::new(pattern))
.collect::<Result<Vec<_>>>()?;
Ok(Self { exclusions })
}
pub fn is_empty(&self) -> bool {
self.exclusions.is_empty()
}
pub fn apply(&self, paths: Vec<PathBuf>, root: &Path) -> ExclusionOutcome {
let mut counts = vec![0usize; self.exclusions.len()];
let mut kept = Vec::new();
for path in paths {
match self.covering(&path, root) {
Some(index) => counts[index] += 1,
None => kept.push(path),
}
}
let excluded = self
.exclusions
.iter()
.zip(counts)
.map(|(exclusion, count)| (exclusion.pattern().to_string(), count))
.collect();
ExclusionOutcome::new(kept, excluded)
}
fn covering(&self, path: &Path, root: &Path) -> Option<usize> {
let relative = path.strip_prefix(root).unwrap_or(path);
self.exclusions
.iter()
.position(|exclusion| exclusion.matches(relative))
}
}