use std::collections::BTreeSet;
use std::path::Path;
use crate::find::FindOptions;
use crate::indicator::Match;
use crate::registry::Registry;
impl Registry {
pub fn detect(&self, dir: impl AsRef<Path>) -> Vec<Match> {
let (files, subdirs) = match read_listing(dir.as_ref()) {
Ok(v) => v,
Err(_) => return Vec::new(),
};
self.match_dir(&files, &subdirs)
}
pub(crate) fn match_dir(&self, files: &[String], subdirs: &[String]) -> Vec<Match> {
let mut matches: Vec<Match> = self
.types
.iter()
.filter_map(|t| {
t.match_listing(files, subdirs).map(|ind| Match {
r#type: t.name.clone(),
indicator: ind,
})
})
.collect();
matches.sort_by(|a, b| a.r#type.cmp(&b.r#type));
matches
}
pub fn collect_build_excludes(
&self,
root: impl AsRef<Path>,
) -> crate::error::Result<Vec<String>> {
let res = self.find(
root,
&FindOptions {
nested: true,
..Default::default()
},
)?;
let by_name: std::collections::HashMap<&str, &[String]> = self
.types
.iter()
.map(|t| (t.name.as_str(), t.build_excludes.as_slice()))
.collect();
let mut seen: BTreeSet<String> = BTreeSet::new();
for p in &res.projects {
for m in &p.types {
if let Some(excludes) = by_name.get(m.r#type.as_str()) {
for ex in *excludes {
seen.insert(ex.clone());
}
}
}
}
Ok(seen.into_iter().collect())
}
}
pub(crate) fn read_listing(dir: &Path) -> std::io::Result<(Vec<String>, Vec<String>)> {
let mut files = Vec::new();
let mut subdirs = Vec::new();
for entry in std::fs::read_dir(dir)? {
let entry = entry?;
let name = entry.file_name().to_string_lossy().into_owned();
let is_dir = entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false);
if is_dir {
subdirs.push(name);
} else {
files.push(name);
}
}
Ok((files, subdirs))
}