diff --git a/src/main/java/rife/bld/dependencies/DependencyResolver.java b/src/main/java/rife/bld/dependencies/DependencyResolver.java
index d9c0c1c..5400505 100644
--- a/src/main/java/rife/bld/dependencies/DependencyResolver.java
+++ b/src/main/java/rife/bld/dependencies/DependencyResolver.java
@@ -9,7 +9,6 @@ import rife.tools.exceptions.FileUtilsErrorException;
import java.io.*;
import java.util.*;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
import static rife.bld.dependencies.Dependency.*;
@@ -180,46 +179,6 @@ public class DependencyResolver {
return result;
}
- /**
- * Resolves the transitive dependencies of multiple root dependencies,
- * merging the results in the order of the provided roots.
- *
- * The roots are resolved in parallel according to the resolution
- * parallelism, while a shared {@code PomPrefetcher} speculatively warms
- * the retriever cache across all of them. The merged result is identical
- * to resolving each root sequentially.
- *
- * @param resolution the version resolution state that can be cached
- * @param retriever the retriever to use to get artifacts
- * @param repositories the repositories to use for the resolution
- * @param roots the root dependencies to resolve
- * @param scopes the scopes to return the transitive dependencies for
- * @return the merged transitive dependencies of all the roots
- * @since 2.3.1
- */
- static DependencySet resolveAllDependencies(VersionResolution resolution, ArtifactRetriever retriever, List repositories, Collection roots, Scope... scopes) {
- var result = new DependencySet();
- if (roots.isEmpty()) {
- return result;
- }
-
- var prefetcher = PomPrefetcher.create(resolution, retriever, repositories);
- try {
- var resolutions = new ArrayList>(roots.size());
- for (var root : roots) {
- resolutions.add(() -> new DependencyResolver(resolution, retriever, repositories, root).getAllDependencies(prefetcher, scopes));
- }
- for (var dependencies : ParallelExecution.execute(resolutions, resolution.resolutionParallelism())) {
- result.addAll(dependencies);
- }
- } finally {
- if (prefetcher != null) {
- prefetcher.shutdown();
- }
- }
- return result;
- }
-
private boolean matchesExclusions(Dependency context, PomDependency checked) {
while (context != null) {
if (context.exclusions() != null) {
diff --git a/src/main/java/rife/bld/dependencies/DependencyScopes.java b/src/main/java/rife/bld/dependencies/DependencyScopes.java
index 7f0c8f2..d93e277 100644
--- a/src/main/java/rife/bld/dependencies/DependencyScopes.java
+++ b/src/main/java/rife/bld/dependencies/DependencyScopes.java
@@ -155,7 +155,7 @@ public class DependencyScopes extends LinkedHashMap {
roots.addAll(scoped_dependencies);
}
}
- var dependencies = DependencyResolver.resolveAllDependencies(resolution, retriever, repositories, roots, transitiveScopes);
+ var dependencies = new ParallelDependencyResolver(resolution, retriever, repositories).resolveAllDependencies(roots, transitiveScopes);
if (excluded != null) {
dependencies.removeAll(excluded);
}
diff --git a/src/main/java/rife/bld/dependencies/DependencySet.java b/src/main/java/rife/bld/dependencies/DependencySet.java
index a62bd10..47749b2 100644
--- a/src/main/java/rife/bld/dependencies/DependencySet.java
+++ b/src/main/java/rife/bld/dependencies/DependencySet.java
@@ -226,7 +226,7 @@ public class DependencySet extends AbstractSet implements Set repositories, Scope... scopes) {
- return DependencyResolver.resolveAllDependencies(resolution, retriever, repositories, this, scopes).generateDependencyTree();
+ return new ParallelDependencyResolver(resolution, retriever, repositories).resolveAllDependencies(this, scopes).generateDependencyTree();
}
/**
diff --git a/src/main/java/rife/bld/dependencies/ParallelDependencyResolver.java b/src/main/java/rife/bld/dependencies/ParallelDependencyResolver.java
new file mode 100644
index 0000000..76ee196
--- /dev/null
+++ b/src/main/java/rife/bld/dependencies/ParallelDependencyResolver.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2001-2026 Geert Bevin (gbevin[remove] at uwyn dot com)
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ */
+package rife.bld.dependencies;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.function.Supplier;
+
+/**
+ * Resolves multiple dependencies in parallel within a list of
+ * Maven-compatible repositories.
+ *
+ * The parallelism is determined by {@link VersionResolution#resolutionParallelism()},
+ * setting it to {@code 1} makes the resolution sequential. The results are
+ * always identical to resolving each dependency sequentially with a
+ * {@link DependencyResolver}, in the same order.
+ *
+ * @author Geert Bevin (gbevin[remove] at uwyn dot com)
+ * @since 2.3.1
+ */
+public class ParallelDependencyResolver {
+ private final VersionResolution resolution_;
+ private final ArtifactRetriever retriever_;
+ private final List repositories_;
+
+ /**
+ * Creates a new parallel resolver.
+ *
+ * The repositories will be checked in the order they're listed.
+ *
+ * @param resolution the version resolution state that can be cached
+ * @param retriever the retriever to use to get artifacts
+ * @param repositories the repositories to use for the resolution
+ * @since 2.3.1
+ */
+ public ParallelDependencyResolver(VersionResolution resolution, ArtifactRetriever retriever, List repositories) {
+ resolution_ = resolution;
+ retriever_ = retriever;
+ if (repositories == null) {
+ repositories = List.of();
+ }
+ repositories_ = repositories;
+ }
+
+ /**
+ * Resolves the transitive dependencies of multiple root dependencies,
+ * merging the results in the order of the provided roots.
+ *
+ * The roots are resolved in parallel while a shared prefetcher
+ * speculatively warms the retriever cache across all of them.
+ *
+ * @param roots the root dependencies to resolve
+ * @param scopes the scopes to return the transitive dependencies for
+ * @return the merged transitive dependencies of all the roots
+ * @since 2.3.1
+ */
+ public DependencySet resolveAllDependencies(Collection roots, Scope... scopes) {
+ var result = new DependencySet();
+ if (roots.isEmpty()) {
+ return result;
+ }
+
+ var prefetcher = PomPrefetcher.create(resolution_, retriever_, repositories_);
+ try {
+ var resolutions = new ArrayList>(roots.size());
+ for (var root : roots) {
+ resolutions.add(() -> new DependencyResolver(resolution_, retriever_, repositories_, root).getAllDependencies(prefetcher, scopes));
+ }
+ for (var dependencies : ParallelExecution.execute(resolutions, resolution_.resolutionParallelism())) {
+ result.addAll(dependencies);
+ }
+ } finally {
+ if (prefetcher != null) {
+ prefetcher.shutdown();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Resolves the latest versions of multiple dependencies, returning them
+ * in the same order as the provided dependencies.
+ *
+ * @param dependencies the dependencies to resolve the latest versions of
+ * @return the latest versions in the order of the provided dependencies
+ * @since 2.3.1
+ */
+ public List resolveLatestVersions(List dependencies) {
+ var resolutions = new ArrayList>(dependencies.size());
+ for (var dependency : dependencies) {
+ resolutions.add(() -> new DependencyResolver(resolution_, retriever_, repositories_, dependency).latestVersion());
+ }
+ return ParallelExecution.execute(resolutions, resolution_.resolutionParallelism());
+ }
+
+ /**
+ * Returns the version resolution state that can be cached.
+ *
+ * @return the version resolution state
+ * @since 2.3.1
+ */
+ public VersionResolution resolution() {
+ return resolution_;
+ }
+
+ /**
+ * Retrieve the repositories that are used by this resolver.
+ *
+ * @return the resolver's repositories
+ * @since 2.3.1
+ */
+ public List repositories() {
+ return repositories_;
+ }
+}
diff --git a/src/main/java/rife/bld/operations/UpdatesOperation.java b/src/main/java/rife/bld/operations/UpdatesOperation.java
index 43da649..67634b6 100644
--- a/src/main/java/rife/bld/operations/UpdatesOperation.java
+++ b/src/main/java/rife/bld/operations/UpdatesOperation.java
@@ -31,16 +31,26 @@ public class UpdatesOperation extends AbstractOperation {
*/
public void execute() {
var resolution = new VersionResolution(properties());
- var result = new DependencyScopes();
+
+ var scopes = new ArrayList();
+ var dependencies = new ArrayList();
for (var entry : dependencies_.entrySet()) {
- var scope = entry.getKey();
for (var dependency : entry.getValue()) {
- var latest = new DependencyResolver(resolution, artifactRetriever(), repositories(), dependency).latestVersion();
- if (latest.compareTo(dependency.version()) > 0) {
- var latest_dependency = new Dependency(dependency.groupId(), dependency.artifactId(), latest,
- dependency.classifier(), dependency.type());
- result.scope(scope).include(latest_dependency);
- }
+ scopes.add(entry.getKey());
+ dependencies.add(dependency);
+ }
+ }
+
+ var latest_versions = new ParallelDependencyResolver(resolution, artifactRetriever(), repositories()).resolveLatestVersions(dependencies);
+
+ var result = new DependencyScopes();
+ for (var i = 0; i < dependencies.size(); ++i) {
+ var dependency = dependencies.get(i);
+ var latest = latest_versions.get(i);
+ if (latest.compareTo(dependency.version()) > 0) {
+ var latest_dependency = new Dependency(dependency.groupId(), dependency.artifactId(), latest,
+ dependency.classifier(), dependency.type());
+ result.scope(scopes.get(i)).include(latest_dependency);
}
}
diff --git a/src/main/java/rife/bld/wrapper/WrapperExtensionResolver.java b/src/main/java/rife/bld/wrapper/WrapperExtensionResolver.java
index af5671a..c87e03d 100644
--- a/src/main/java/rife/bld/wrapper/WrapperExtensionResolver.java
+++ b/src/main/java/rife/bld/wrapper/WrapperExtensionResolver.java
@@ -89,12 +89,13 @@ public class WrapperExtensionResolver {
private Set transferExtensionDependencies() {
var filenames = new HashSet();
- var dependencies = new DependencySet();
+ var roots = new ArrayList();
for (var d : dependencies_) {
if (d != null) {
- dependencies.addAll(new DependencyResolver(resolution_, retriever_, repositories_, d).getAllDependencies(Scope.compile, Scope.runtime));
+ roots.add(d);
}
}
+ var dependencies = new ParallelDependencyResolver(resolution_, retriever_, repositories_).resolveAllDependencies(roots, Scope.compile, Scope.runtime);
if (!dependencies.isEmpty()) {
ensurePrintedHeader();