use std::path::{Path, PathBuf};
use crate::models::{DatasourceId, Dependency, FileInfo, Package, PackageUid, TopLevelDependency};
pub(super) struct ProjectRoot {
pub root: PathBuf,
pub package_index: usize,
pub package_uid: PackageUid,
}
pub(super) struct ProjectFileAssignment<'roots, RelevantFn, FindFn, IncludeFn> {
pub datasource_id: DatasourceId,
pub project_roots: &'roots [ProjectRoot],
pub is_relevant_file: RelevantFn,
pub find_root: FindFn,
pub include_dependency: IncludeFn,
}
pub(super) fn assign_project_files<RelevantFn, FindFn, IncludeFn>(
files: &mut [FileInfo],
packages: &mut [Package],
dependencies: &mut Vec<TopLevelDependency>,
assignment: ProjectFileAssignment<'_, RelevantFn, FindFn, IncludeFn>,
) where
RelevantFn: Fn(&FileInfo) -> bool,
FindFn: for<'a> Fn(&Path, &'a [ProjectRoot]) -> Option<&'a ProjectRoot>,
IncludeFn: Fn(&Dependency) -> bool,
{
let ProjectFileAssignment {
datasource_id,
project_roots,
is_relevant_file,
find_root,
include_dependency,
} = assignment;
for file in files.iter_mut() {
if !is_relevant_file(file) || !file.for_packages.is_empty() {
continue;
}
let Some(project_root) = find_root(Path::new(&file.path), project_roots) else {
continue;
};
if !file.for_packages.contains(&project_root.package_uid) {
file.for_packages.push(project_root.package_uid.clone());
}
let package = &mut packages[project_root.package_index];
if !package.datafile_paths.contains(&file.path) {
package.datafile_paths.push(file.path.clone());
}
if !package.datasource_ids.contains(&datasource_id) {
package.datasource_ids.push(datasource_id);
}
let mut already_materialized = false;
for dependency in dependencies.iter_mut() {
if dependency.datasource_id == datasource_id && dependency.datafile_path == file.path {
already_materialized = true;
if dependency.for_package_uid.is_none() {
dependency.for_package_uid = Some(project_root.package_uid.clone());
}
}
}
if already_materialized {
continue;
}
for pkg_data in &file.package_data {
if pkg_data.datasource_id != Some(datasource_id) {
continue;
}
dependencies.extend(
pkg_data
.dependencies
.iter()
.filter(|dep| include_dependency(dep))
.map(|dep| {
TopLevelDependency::from_dependency(
dep,
file.path.clone(),
datasource_id,
Some(project_root.package_uid.clone()),
)
}),
);
}
}
}