use std::collections::{HashMap, HashSet};
use crate::artifact::Artifact;
use crate::model::Dependency;
use crate::resolver::DependencyResolver;
pub struct TransitiveDependencyResolver {
resolver: DependencyResolver,
resolved_cache: HashMap<String, Vec<Artifact>>,
}
impl TransitiveDependencyResolver {
pub fn new(resolver: DependencyResolver) -> Self {
Self {
resolver,
resolved_cache: HashMap::new(),
}
}
pub fn resolve_transitive(
&mut self,
dependency: &Dependency,
) -> anyhow::Result<Vec<Artifact>> {
let key = format!("{}:{}:{}",
dependency.group_id,
dependency.artifact_id,
dependency.version.as_deref().unwrap_or("")
);
if let Some(cached) = self.resolved_cache.get(&key) {
return Ok(cached.clone());
}
let mut resolved = Vec::new();
let mut visited = HashSet::new();
self.resolve_recursive(dependency, &mut resolved, &mut visited)?;
self.resolved_cache.insert(key, resolved.clone());
Ok(resolved)
}
fn resolve_recursive(
&mut self,
dependency: &Dependency,
resolved: &mut Vec<Artifact>,
visited: &mut HashSet<String>,
) -> anyhow::Result<()> {
let dep_key = format!("{}:{}", dependency.group_id, dependency.artifact_id);
if visited.contains(&dep_key) {
return Ok(());
}
visited.insert(dep_key.clone());
if let Some(artifact) = self.resolver.resolve_dependency(dependency)? {
resolved.push(artifact.clone());
if let Ok(Some(model)) = self.resolver.resolve_pom(&artifact) {
if let Some(deps) = model.dependencies {
for sub_dep in deps.dependencies {
if sub_dep.scope.as_deref() == Some("test") || sub_dep.scope.as_deref() == Some("provided") {
continue;
}
if sub_dep.optional == Some(true) {
continue;
}
self.resolve_recursive(&sub_dep, resolved, visited)?;
}
}
}
}
Ok(())
}
pub fn resolve_all_transitive(
&mut self,
dependencies: &[Dependency],
) -> anyhow::Result<Vec<Artifact>> {
let mut all_resolved = Vec::new();
let mut seen = HashSet::new();
for dependency in dependencies {
let transitive = self.resolve_transitive(dependency)?;
for artifact in transitive {
let artifact_key = artifact.coordinates.full_id();
if !seen.contains(&artifact_key) {
seen.insert(artifact_key);
all_resolved.push(artifact);
}
}
}
Ok(all_resolved)
}
}