package com.loopperfect.buckaroo;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.*;
public final class DependencyResolver {
private DependencyResolver() {
}
private static Optional<Map.Entry<SemanticVersion, DependencyGroup>> getLatest(final ImmutableMap<SemanticVersion, DependencyGroup> versions) {
Preconditions.checkNotNull(versions);
return versions.entrySet()
.stream()
.max(Comparator.comparing(Map.Entry::getKey));
}
public static Either<ImmutableList<DependencyResolverException>, ImmutableMap<RecipeIdentifier, SemanticVersion>> resolve(
final DependencyGroup dependencyGroup, final DependencyFetcher fetcher) {
Preconditions.checkNotNull(dependencyGroup);
Preconditions.checkNotNull(fetcher);
final Stack<Dependency> todo = new Stack<>();
final Map<RecipeIdentifier, SemanticVersion> resolved = new HashMap<>();
final List<DependencyResolverException> unresolved = new ArrayList<>();
todo.addAll(dependencyGroup.entries());
while (!todo.isEmpty()) {
final Dependency next = todo.pop();
if (resolved.containsKey(next.project)) {
if (!next.versionRequirement.isSatisfiedBy(resolved.get(next.project))) {
unresolved.add(new VersionRequirementNotSatisfiedException(next.project, next.versionRequirement));
}
continue;
}
fetcher.fetch(next).join(
error -> Action.of(() -> unresolved.add(error)),
x -> Action.of(() -> {
final Optional<Map.Entry<SemanticVersion, DependencyGroup>> latest = getLatest(x);
if (latest.isPresent()) {
resolved.put(next.project, latest.get().getKey());
todo.addAll(latest.get().getValue().entries());
} else {
unresolved.add(new VersionRequirementNotSatisfiedException(
next.project, next.versionRequirement));
}
})).run();
}
if (unresolved.isEmpty()) {
return Either.right(ImmutableMap.copyOf(resolved));
}
return Either.left(ImmutableList.copyOf(unresolved));
}
// public static ImmutableSet<Identifier> removableDependencies(
// final ImmutableMap<Identifier, SemanticVersionRequirement> dependencies,
// final RecipeIdentifier project,
// final DependencyFetcher fetcher) {
//
// if (!dependencies.containsKey(project)) {
// return ImmutableSet.of();
// }
//
// final SemanticVersionRequirement version = dependencies.get(project);
// final ImmutableMap<SemanticVersion, DependencyGroup> removableVersions = fetcher.fetch(project, version)
// .right()
// .get();
//
// return getLatest(removableVersions).map( removable ->
// removable.getValue().dependencies
// .keySet()
// .stream()
// .filter(x ->
// !dependencies.containsKey(x)
// ).collect(ImmutableSet.toImmutableSet()))
// .orElse(ImmutableSet.of());
// }
}