use std::collections::HashSet;
use crate::package_manager::Project;
use crate::path::AbsolutePath;
pub fn match_files_to_projects(
projects: &[Project],
git_root: &AbsolutePath,
changed_files: &HashSet<String>,
) -> Vec<bool> {
let rel_paths: Vec<Option<String>> = projects
.iter()
.map(|p| {
p.path()
.strip_prefix(git_root.as_path())
.ok()
.map(|r| r.to_string_lossy().into_owned())
})
.collect();
let mut matched = vec![false; projects.len()];
for file in changed_files {
let candidates: Vec<(usize, usize)> = rel_paths
.iter()
.enumerate()
.filter_map(|(i, rel_opt)| {
let rel = rel_opt.as_deref()?;
if rel.is_empty() {
Some((i, 0usize))
} else if file.starts_with(rel)
&& (file.len() == rel.len() || file.as_bytes().get(rel.len()) == Some(&b'/'))
{
Some((i, rel.len()))
} else {
None
}
})
.collect();
if let Some(&(_, best_len)) = candidates.iter().max_by_key(|(_, len)| *len) {
candidates
.iter()
.filter(|(_, len)| *len == best_len)
.for_each(|(i, _)| matched[*i] = true);
}
}
matched
}
pub fn match_files_to_projects_in_scope(
projects: &[Project],
attribution_scope: &[Project],
git_root: &AbsolutePath,
changed_files: &HashSet<String>,
) -> Vec<bool> {
let scope_matched = match_files_to_projects(attribution_scope, git_root, changed_files);
let matched_paths: HashSet<&AbsolutePath> = attribution_scope
.iter()
.zip(scope_matched.iter())
.filter_map(|(p, &m)| m.then_some(p.path()))
.collect();
projects
.iter()
.map(|p| matched_paths.contains(p.path()))
.collect()
}