diff --git a/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeBuilder.java b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeBuilder.java new file mode 100644 index 00000000..f0bbd20a --- /dev/null +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeBuilder.java @@ -0,0 +1,69 @@ +package io.quarkus.domino.inspect; + +import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; +import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; +import java.util.List; +import java.util.Objects; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.collection.CollectRequest; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.util.artifact.JavaScopes; + +public abstract class DependencyTreeBuilder { + + private static final Artifact root = new DefaultArtifact("io.domino", "domino-tree-builder", "pom", "1"); + + public static DependencyTreeBuilder resolvingTreeBuilder(MavenArtifactResolver resolver) { + return new ResolvingDependencyTreeBuilder(resolver); + } + + public static DependencyTreeBuilder nonResolvingTreeBuilder(MavenArtifactResolver resolver) { + return new NonResolvingDependencyTreeBuilder(resolver); + } + + protected final MavenArtifactResolver resolver; + + DependencyTreeBuilder(MavenArtifactResolver resolver) { + this.resolver = Objects.requireNonNull(resolver); + } + + public DependencyNode buildTree(DependencyTreeRequest root) { + var rootNode = doBuildTree(root); + if (root.isDependency()) { + if (rootNode.getChildren().size() != 1) { + throw new RuntimeException("Expected a single child node but got " + rootNode.getChildren()); + } + return rootNode.getChildren().get(0); + } + return rootNode; + } + + public abstract DependencyNode doBuildTree(DependencyTreeRequest root); + + protected CollectRequest createCollectRequest(DependencyTreeRequest root) { + var req = new CollectRequest().setManagedDependencies(root.getConstraints()); + if (root.isPlugin()) { + try { + req.setRepositories(resolver.getMavenContext().getRemotePluginRepositories()); + } catch (BootstrapMavenException e) { + throw new RuntimeException(e); + } + } else { + req.setRepositories(resolver.getRepositories()); + } + var dep = new Dependency( + root.getArtifact(), + JavaScopes.RUNTIME, + false, + root.getExclusions()); + if (root.isDependency()) { + req.setRootArtifact(DependencyTreeBuilder.root) + .setDependencies(List.of(dep)); + } else { + req.setRoot(dep); + } + return req; + } +} diff --git a/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeError.java b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeError.java new file mode 100644 index 00000000..8d1888df --- /dev/null +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeError.java @@ -0,0 +1,20 @@ +package io.quarkus.domino.inspect; + +public class DependencyTreeError { + + private final DependencyTreeRequest request; + private final Throwable error; + + public DependencyTreeError(DependencyTreeRequest request, Throwable error) { + this.request = request; + this.error = error; + } + + public DependencyTreeRequest getRequest() { + return request; + } + + public Throwable getError() { + return error; + } +} diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeProcessor.java b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeInspector.java similarity index 62% rename from domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeProcessor.java rename to domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeInspector.java index 56841d26..c5386d00 100644 --- a/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeProcessor.java +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeInspector.java @@ -1,4 +1,4 @@ -package io.quarkus.domino.tree; +package io.quarkus.domino.inspect; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; @@ -14,10 +14,10 @@ import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.graph.Exclusion; -public class DependencyTreeProcessor { +public class DependencyTreeInspector { - public static DependencyTreeProcessor configure() { - return new DependencyTreeProcessor(); + public static DependencyTreeInspector configure() { + return new DependencyTreeInspector(); } private String settings; @@ -29,55 +29,73 @@ public static DependencyTreeProcessor configure() { private DependencyTreeVisitor treeVisitor; private boolean parallelProcessing; private MessageWriter log; - private List roots = new ArrayList<>(); + private List roots = new ArrayList<>(); - private DependencyTreeProcessor() { + private DependencyTreeInspector() { } - public DependencyTreeProcessor setTreeBuilder(DependencyTreeBuilder treeBuilder) { + public DependencyTreeInspector setTreeBuilder(DependencyTreeBuilder treeBuilder) { this.treeBuilder = treeBuilder; return this; } - public DependencyTreeProcessor setArtifactResolver(MavenArtifactResolver resolver) { + public DependencyTreeInspector setArtifactResolver(MavenArtifactResolver resolver) { this.resolver = resolver; return this; } - public DependencyTreeProcessor setResolveDependencies(boolean resolveDependencies) { + public DependencyTreeInspector setResolveDependencies(boolean resolveDependencies) { this.resolveDependencies = resolveDependencies; return this; } - public DependencyTreeProcessor setTreeVisitor(DependencyTreeVisitor treeVisitor) { + public DependencyTreeInspector setTreeVisitor(DependencyTreeVisitor treeVisitor) { this.treeVisitor = treeVisitor; return this; } - public DependencyTreeProcessor setParallelProcessing(boolean parallelProcessing) { + public DependencyTreeInspector setParallelProcessing(boolean parallelProcessing) { this.parallelProcessing = parallelProcessing; return this; } - public DependencyTreeProcessor setMessageWriter(MessageWriter log) { + public DependencyTreeInspector setMessageWriter(MessageWriter log) { this.log = log; return this; } - public DependencyTreeProcessor addRoot(Artifact artifact) { - return addRoot(artifact, List.of(), List.of()); + public DependencyTreeInspector inspectAsDependency(Artifact artifact) { + return inspectAsDependency(artifact, List.of(), List.of()); } - public DependencyTreeProcessor addRoot(Artifact artifact, List constraints) { - return addRoot(artifact, constraints, List.of()); + public DependencyTreeInspector inspectAsDependency(Artifact artifact, List constraints) { + return inspectAsDependency(artifact, constraints, List.of()); } - public DependencyTreeProcessor addRoot(Artifact artifact, List constraints, Collection exclusions) { - this.roots.add(new DependencyTreeRoot(artifact, constraints, exclusions)); + public DependencyTreeInspector inspectAsDependency(Artifact artifact, List constraints, + Collection exclusions) { + return inspect(DependencyTreeRequest.ofDependency(artifact, constraints, exclusions)); + } + + public DependencyTreeInspector inspectAsRoot(Artifact artifact, List constraints, + Collection exclusions) { + return inspect(DependencyTreeRequest.ofRoot(artifact, constraints, exclusions)); + } + + public DependencyTreeInspector inspectPlugin(Artifact artifact) { + return inspect(DependencyTreeRequest.ofPlugin(artifact)); + } + + public DependencyTreeInspector inspectPlugin(Artifact artifact, Collection exclusions) { + return inspect(DependencyTreeRequest.ofPlugin(artifact, exclusions)); + } + + public DependencyTreeInspector inspect(DependencyTreeRequest request) { + this.roots.add(request); return this; } - public void process() { + public void complete() { if (resolver == null) { var config = BootstrapMavenContext.config() @@ -114,9 +132,9 @@ public void process() { } if (treeVisitor == null) { - treeVisitor = new DependencyTreeVisitor() { + treeVisitor = new DependencyTreeVisitor<>() { @Override - public void visitTree(DependencyTreeVisit ctx) { + public void visit(DependencyTreeVisit ctx) { } @Override @@ -124,17 +142,17 @@ public void onEvent(Object event, MessageWriter log) { } @Override - public void handleResolutionFailures(Collection artifacts) { + public void handleResolutionFailures(Collection requests) { } }; } var scheduler = parallelProcessing ? DependencyTreeVisitScheduler.parallel(treeBuilder, treeVisitor, log, roots.size()) - : DependencyTreeVisitScheduler.sequencial(treeBuilder, treeVisitor, log, roots.size()); + : DependencyTreeVisitScheduler.sequential(treeBuilder, treeVisitor, log, roots.size()); for (var r : roots) { - scheduler.scheduleProcessing(r); + scheduler.process(r); } scheduler.waitForCompletion(); if (!scheduler.getResolutionFailures().isEmpty()) { diff --git a/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeRequest.java b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeRequest.java new file mode 100644 index 00000000..cfb0ab3c --- /dev/null +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeRequest.java @@ -0,0 +1,74 @@ +package io.quarkus.domino.inspect; + +import java.util.Collection; +import java.util.List; +import org.eclipse.aether.artifact.Artifact; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.Exclusion; + +public class DependencyTreeRequest { + + /* @formatter:off */ + private static final byte ROOT = 0b001; + private static final byte DEPENDENCY = 0b010; + private static final byte PLUGIN = 0b100; + /* @formatter:on */ + + public static DependencyTreeRequest ofRoot(Artifact artifact, List constraints, + Collection exclusions) { + return new DependencyTreeRequest(artifact, constraints, exclusions, ROOT); + } + + public static DependencyTreeRequest ofDependency(Artifact artifact, List constraints, + Collection exclusions) { + return new DependencyTreeRequest(artifact, constraints, exclusions, DEPENDENCY); + } + + public static DependencyTreeRequest ofPlugin(Artifact artifact) { + return ofPlugin(artifact, List.of()); + } + + public static DependencyTreeRequest ofPlugin(Artifact artifact, Collection exclusions) { + return new DependencyTreeRequest(artifact, List.of(), exclusions, PLUGIN); + } + + private final Artifact root; + private final List constraints; + private final Collection exclusions; + private final byte type; + + private DependencyTreeRequest(Artifact root, List constraints, Collection exclusions, byte type) { + this.root = root; + this.constraints = constraints; + this.exclusions = exclusions; + this.type = type; + } + + String getId() { + return root.toString(); + } + + public Artifact getArtifact() { + return root; + } + + public List getConstraints() { + return constraints; + } + + public Collection getExclusions() { + return exclusions; + } + + boolean isRoot() { + return type == ROOT; + } + + boolean isDependency() { + return type == DEPENDENCY; + } + + boolean isPlugin() { + return type == PLUGIN; + } +} diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/DefaultTreeProcessingContext.java b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitContext.java similarity index 59% rename from domino/api/src/main/java/io/quarkus/domino/tree/DefaultTreeProcessingContext.java rename to domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitContext.java index 987e95c4..864fd6b4 100644 --- a/domino/api/src/main/java/io/quarkus/domino/tree/DefaultTreeProcessingContext.java +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitContext.java @@ -1,17 +1,17 @@ -package io.quarkus.domino.tree; +package io.quarkus.domino.inspect; import io.quarkus.devtools.messagewriter.MessageWriter; import java.util.Objects; import org.eclipse.aether.graph.DependencyNode; -class DefaultTreeProcessingContext implements DependencyTreeVisitor.DependencyTreeVisit { +class DependencyTreeVisitContext implements DependencyTreeVisitor.DependencyTreeVisit { - private final DependencyTreeVisitor processor; + private final DependencyTreeVisitor visitor; private final MessageWriter log; DependencyNode root; - DefaultTreeProcessingContext(DependencyTreeVisitor processor, MessageWriter log) { - this.processor = processor; + DependencyTreeVisitContext(DependencyTreeVisitor visitor, MessageWriter log) { + this.visitor = visitor; this.log = log; } @@ -28,6 +28,6 @@ public MessageWriter getLog() { @Override public void pushEvent(E event) { Objects.requireNonNull(root, "Dependency tree root node is null"); - processor.onEvent(event, log); + visitor.onEvent(event, log); } } diff --git a/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitScheduler.java b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitScheduler.java new file mode 100644 index 00000000..4c97b3bf --- /dev/null +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitScheduler.java @@ -0,0 +1,28 @@ +package io.quarkus.domino.inspect; + +import io.quarkus.devtools.messagewriter.MessageWriter; +import java.util.Collection; + +public interface DependencyTreeVisitScheduler { + + static DependencyTreeVisitScheduler sequential(DependencyTreeBuilder treeBuilder, + DependencyTreeVisitor visitor, + MessageWriter log, + int treesTotal) { + return new SequentialTreeVisitScheduler<>(visitor, log, treesTotal, treeBuilder); + } + + static DependencyTreeVisitScheduler parallel(DependencyTreeBuilder treeBuilder, + DependencyTreeVisitor visitor, + MessageWriter log, + int treesTotal) { + return new ParallelTreeVisitScheduler<>(visitor, log, treesTotal, treeBuilder); + } + + void process(DependencyTreeRequest root); + + void waitForCompletion(); + + Collection getResolutionFailures(); + +} diff --git a/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitSchedulerBase.java b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitSchedulerBase.java new file mode 100644 index 00000000..3d3f7f42 --- /dev/null +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitSchedulerBase.java @@ -0,0 +1,59 @@ +package io.quarkus.domino.inspect; + +import io.quarkus.devtools.messagewriter.MessageWriter; +import java.util.ArrayList; +import java.util.Formatter; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; +import org.eclipse.aether.artifact.Artifact; + +abstract class DependencyTreeVisitSchedulerBase implements DependencyTreeVisitScheduler { + + private static final String FORMAT_BASE = "[%s/%s %.1f%%] "; + + protected final List errors = new ArrayList<>(); + protected final DependencyTreeVisitContext ctx; + protected final AtomicInteger counter = new AtomicInteger(); + protected final int rootsTotal; + + DependencyTreeVisitSchedulerBase(DependencyTreeVisitor visitor, MessageWriter log, int rootsTotal) { + ctx = new DependencyTreeVisitContext<>(visitor, log); + this.rootsTotal = rootsTotal; + } + + @Override + public List getResolutionFailures() { + return errors; + } + + protected String getResolvedTreeMessage(Artifact a) { + var sb = new StringBuilder(160); + var formatter = new Formatter(sb); + var treeIndex = counter.incrementAndGet(); + final double percents = ((double) treeIndex * 100) / rootsTotal; + + formatter.format(FORMAT_BASE, treeIndex, rootsTotal, percents); + + sb.append(a.getGroupId()).append(':').append(a.getArtifactId()).append(':'); + if (!a.getClassifier().isEmpty()) { + sb.append(a.getClassifier()).append(':'); + } + if (!"jar".equals(a.getExtension())) { + if (a.getClassifier().isEmpty()) { + sb.append(':'); + } + sb.append(a.getExtension()).append(':'); + } + return sb.append(a.getVersion()).toString(); + } + + protected String formatErrorMessage(DependencyTreeRequest request, Exception e) { + var sb = new StringBuilder(); + sb.append("Failed to process dependencies of ").append(request.getArtifact()); + if (e != null) { + var error = e.getLocalizedMessage(); + sb.append(" because ").append(Character.toLowerCase(error.charAt(0))).append(error.substring(1)); + } + return sb.toString(); + } +} diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeVisitor.java b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitor.java similarity index 66% rename from domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeVisitor.java rename to domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitor.java index 6bc8ef3e..0dddcf5e 100644 --- a/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeVisitor.java +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/DependencyTreeVisitor.java @@ -1,8 +1,7 @@ -package io.quarkus.domino.tree; +package io.quarkus.domino.inspect; import io.quarkus.devtools.messagewriter.MessageWriter; import java.util.Collection; -import org.eclipse.aether.artifact.Artifact; import org.eclipse.aether.graph.DependencyNode; public interface DependencyTreeVisitor { @@ -16,9 +15,9 @@ interface DependencyTreeVisit { void pushEvent(E event); } - void visitTree(DependencyTreeVisit ctx); + void visit(DependencyTreeVisit ctx); void onEvent(E event, MessageWriter log); - void handleResolutionFailures(Collection artifacts); + void handleResolutionFailures(Collection errors); } diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/NonResolvingDependencyTreeBuilder.java b/domino/api/src/main/java/io/quarkus/domino/inspect/NonResolvingDependencyTreeBuilder.java similarity index 88% rename from domino/api/src/main/java/io/quarkus/domino/tree/NonResolvingDependencyTreeBuilder.java rename to domino/api/src/main/java/io/quarkus/domino/inspect/NonResolvingDependencyTreeBuilder.java index 4992db3e..0e047fed 100644 --- a/domino/api/src/main/java/io/quarkus/domino/tree/NonResolvingDependencyTreeBuilder.java +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/NonResolvingDependencyTreeBuilder.java @@ -1,4 +1,4 @@ -package io.quarkus.domino.tree; +package io.quarkus.domino.inspect; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import org.eclipse.aether.collection.DependencyCollectionException; @@ -11,7 +11,7 @@ public NonResolvingDependencyTreeBuilder(MavenArtifactResolver resolver) { } @Override - public DependencyNode doBuildTree(DependencyTreeRoot root) { + public DependencyNode doBuildTree(DependencyTreeRequest root) { try { return resolver.getSystem().collectDependencies( resolver.getSession(), diff --git a/domino/api/src/main/java/io/quarkus/domino/inspect/ParallelTreeVisitScheduler.java b/domino/api/src/main/java/io/quarkus/domino/inspect/ParallelTreeVisitScheduler.java new file mode 100644 index 00000000..379930af --- /dev/null +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/ParallelTreeVisitScheduler.java @@ -0,0 +1,73 @@ +package io.quarkus.domino.inspect; + +import io.quarkus.devtools.messagewriter.MessageWriter; +import io.quarkus.domino.processor.ExecutionContext; +import io.quarkus.domino.processor.NodeProcessor; +import io.quarkus.domino.processor.ParallelTreeProcessor; +import io.quarkus.domino.processor.TaskResult; +import java.util.List; +import java.util.function.Function; +import org.eclipse.aether.graph.DependencyNode; + +public class ParallelTreeVisitScheduler extends DependencyTreeVisitSchedulerBase { + + final ParallelTreeProcessor treeProcessor; + private final DependencyTreeVisitor visitor; + private final MessageWriter log; + + public ParallelTreeVisitScheduler(DependencyTreeVisitor visitor, MessageWriter log, int treesTotal, + DependencyTreeBuilder treeBuilder) { + super(visitor, log, treesTotal); + this.visitor = visitor; + this.log = log; + treeProcessor = ParallelTreeProcessor + .with(new NodeProcessor<>() { + + private TaskResult apply( + ExecutionContext execution) { + var request = execution.getNode(); + try { + var node = treeBuilder.buildTree(request); + log.info(getResolvedTreeMessage(request.getArtifact())); + return execution.success(node); + } catch (Exception e) { + return execution.failure(e); + } + } + + @Override + public String getNodeId(DependencyTreeRequest request) { + return request.getId(); + } + + @Override + public Iterable getChildren(DependencyTreeRequest node) { + return List.of(); + } + + @Override + public Function, TaskResult> createFunction() { + return this::apply; + } + }); + } + + @Override + public void process(DependencyTreeRequest root) { + treeProcessor.addRoot(root); + } + + @Override + public void waitForCompletion() { + var results = treeProcessor.schedule().join(); + for (var r : results) { + if (r.isFailure()) { + errors.add(new DependencyTreeError(r.getNode(), r.getException())); + log.error(formatErrorMessage(r.getNode(), r.getException())); + } else { + ctx.root = r.getOutcome(); + visitor.visit(ctx); + } + } + } +} diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/ResolvingDependencyTreeBuilder.java b/domino/api/src/main/java/io/quarkus/domino/inspect/ResolvingDependencyTreeBuilder.java similarity index 89% rename from domino/api/src/main/java/io/quarkus/domino/tree/ResolvingDependencyTreeBuilder.java rename to domino/api/src/main/java/io/quarkus/domino/inspect/ResolvingDependencyTreeBuilder.java index a9d148bd..b8d95305 100644 --- a/domino/api/src/main/java/io/quarkus/domino/tree/ResolvingDependencyTreeBuilder.java +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/ResolvingDependencyTreeBuilder.java @@ -1,4 +1,4 @@ -package io.quarkus.domino.tree; +package io.quarkus.domino.inspect; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import org.eclipse.aether.graph.DependencyNode; @@ -12,7 +12,7 @@ public ResolvingDependencyTreeBuilder(MavenArtifactResolver resolver) { } @Override - public DependencyNode doBuildTree(DependencyTreeRoot root) { + public DependencyNode doBuildTree(DependencyTreeRequest root) { try { return resolver.getSystem().resolveDependencies( resolver.getSession(), diff --git a/domino/api/src/main/java/io/quarkus/domino/inspect/SequentialTreeVisitScheduler.java b/domino/api/src/main/java/io/quarkus/domino/inspect/SequentialTreeVisitScheduler.java new file mode 100644 index 00000000..9b0ff2fc --- /dev/null +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/SequentialTreeVisitScheduler.java @@ -0,0 +1,38 @@ +package io.quarkus.domino.inspect; + +import io.quarkus.devtools.messagewriter.MessageWriter; +import org.eclipse.aether.graph.DependencyNode; + +public class SequentialTreeVisitScheduler extends DependencyTreeVisitSchedulerBase { + + private final DependencyTreeVisitor visitor; + private final MessageWriter log; + private final DependencyTreeBuilder treeBuilder; + + public SequentialTreeVisitScheduler(DependencyTreeVisitor visitor, MessageWriter log, int treesTotal, + DependencyTreeBuilder treeBuilder) { + super(visitor, log, treesTotal); + this.visitor = visitor; + this.log = log; + this.treeBuilder = treeBuilder; + } + + @Override + public void process(DependencyTreeRequest req) { + final DependencyNode rootNode; + try { + rootNode = treeBuilder.buildTree(req); + log.info(getResolvedTreeMessage(rootNode.getArtifact())); + } catch (Exception e) { + errors.add(new DependencyTreeError(req, e)); + log.error(formatErrorMessage(req, e)); + return; + } + ctx.root = rootNode; + visitor.visit(ctx); + } + + @Override + public void waitForCompletion() { + } +} diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/quarkus/QuarkusPlatformInfo.java b/domino/api/src/main/java/io/quarkus/domino/inspect/quarkus/QuarkusPlatformInfo.java similarity index 98% rename from domino/api/src/main/java/io/quarkus/domino/tree/quarkus/QuarkusPlatformInfo.java rename to domino/api/src/main/java/io/quarkus/domino/inspect/quarkus/QuarkusPlatformInfo.java index 9e825774..80bb30d4 100644 --- a/domino/api/src/main/java/io/quarkus/domino/tree/quarkus/QuarkusPlatformInfo.java +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/quarkus/QuarkusPlatformInfo.java @@ -1,4 +1,4 @@ -package io.quarkus.domino.tree.quarkus; +package io.quarkus.domino.inspect.quarkus; import io.quarkus.maven.dependency.ArtifactCoords; import java.util.List; diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/quarkus/QuarkusPlatformInfoReader.java b/domino/api/src/main/java/io/quarkus/domino/inspect/quarkus/QuarkusPlatformInfoReader.java similarity index 99% rename from domino/api/src/main/java/io/quarkus/domino/tree/quarkus/QuarkusPlatformInfoReader.java rename to domino/api/src/main/java/io/quarkus/domino/inspect/quarkus/QuarkusPlatformInfoReader.java index 1e836805..0e303b94 100644 --- a/domino/api/src/main/java/io/quarkus/domino/tree/quarkus/QuarkusPlatformInfoReader.java +++ b/domino/api/src/main/java/io/quarkus/domino/inspect/quarkus/QuarkusPlatformInfoReader.java @@ -1,4 +1,4 @@ -package io.quarkus.domino.tree.quarkus; +package io.quarkus.domino.inspect.quarkus; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/BaseDependencyTreeProcessScheduler.java b/domino/api/src/main/java/io/quarkus/domino/tree/BaseDependencyTreeProcessScheduler.java deleted file mode 100644 index c6e48d02..00000000 --- a/domino/api/src/main/java/io/quarkus/domino/tree/BaseDependencyTreeProcessScheduler.java +++ /dev/null @@ -1,140 +0,0 @@ -package io.quarkus.domino.tree; - -import io.quarkus.devtools.messagewriter.MessageWriter; -import java.util.ArrayList; -import java.util.Formatter; -import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; -import org.eclipse.aether.artifact.Artifact; - -abstract class BaseDependencyTreeProcessScheduler implements DependencyTreeVisitScheduler { - - private static final long ESTIMATE_TIME_AFTER_MS = 60 * 1000; - private static final int ESTIMATE_TIME_AFTER_PERCENTS = 42; - - private static final String FORMAT_BASE = "[%s/%s %.1f%%] "; - private static final String FORMAT_SECONDS_LEFT = "[%s/%s %.1f%%, ~ %ds left] "; - private static final String FORMAT_MINUTES_LEFT = "[%s/%s %.1f%%, ~ %dm %ds left] "; - private static final String FORMAT_HOURS_LEFT = "[%s/%s %.1f%%, ~ %dh %dm %dsec left] "; - - protected final List resolutionFailures = new ArrayList<>(); - protected final DefaultTreeProcessingContext ctx; - protected final AtomicInteger counter = new AtomicInteger(); - protected final int rootsTotal; - private long startTime = -1; - private long totalSecEstimate = -1; - private long firstEstimateStart; - - private final long[] treeTimes; - private final AtomicInteger treeIndex = new AtomicInteger(); - - BaseDependencyTreeProcessScheduler(DependencyTreeVisitor processor, MessageWriter log, int rootsTotal) { - ctx = new DefaultTreeProcessingContext(processor, log); - this.rootsTotal = rootsTotal; - treeTimes = new long[rootsTotal]; - } - - @Override - public List getResolutionFailures() { - return resolutionFailures; - } - - protected String getResolvedTreeMessage(Artifact a) { - var sb = new StringBuilder(160); - var formatter = new Formatter(sb); - var treeIndex = counter.incrementAndGet(); - final double percents = ((double) treeIndex * 100) / rootsTotal; - - boolean estimateTime = false;// percents >= ESTIMATE_TIME_AFTER_PERCENTS && treeIndex > 1; - if (startTime == -1) { - startTime = System.currentTimeMillis(); - estimateTime = false; - } - - if (estimateTime && totalSecEstimate == -1) { - firstEstimateStart = System.currentTimeMillis(); - totalSecEstimate = ((rootsTotal - treeIndex) * (firstEstimateStart - startTime) / (treeIndex - 1)) / 1000; - } - - if (estimateTime) { - final long durationMs = System.currentTimeMillis() - startTime; - if (durationMs > ESTIMATE_TIME_AFTER_MS) { - final long remainingSeconds = Math.round((100 - percents) * totalSecEstimate / 100); - //final long remainingSeconds = ((rootsTotal - treeIndex) * durationMs / (treeIndex - 1)) / 1000; - final long hours = remainingSeconds / 3600; - final long minutes = (remainingSeconds % 3600) / 60; - final long seconds = remainingSeconds % 60; - if (hours > 0) { - formatter.format(FORMAT_HOURS_LEFT, - treeIndex, - rootsTotal, - percents, - hours, - minutes, - seconds); - } else if (minutes > 0) { - formatter.format(FORMAT_MINUTES_LEFT, - treeIndex, - rootsTotal, - percents, - minutes, - seconds); - } else if (seconds > 0) { - formatter.format(FORMAT_SECONDS_LEFT, - treeIndex, - rootsTotal, - percents, - seconds); - } else { - formatter.format(FORMAT_BASE, - treeIndex, - rootsTotal, - percents); - } - } else { - formatter.format(FORMAT_BASE, treeIndex, rootsTotal, percents); - } - } else { - formatter.format(FORMAT_BASE, treeIndex, rootsTotal, percents); - } - - sb.append(a.getGroupId()).append(':').append(a.getArtifactId()).append(':'); - if (!a.getClassifier().isEmpty()) { - sb.append(a.getClassifier()).append(':'); - } - if (!"jar".equals(a.getExtension())) { - if (a.getClassifier().isEmpty()) { - sb.append(':'); - } - sb.append(a.getExtension()).append(':'); - } - /* @formatter:off - if (rootsTotal - 1 == treeIndex) { - long hours = totalSecEstimate / 3600; - long minutes = (totalSecEstimate % 3600) / 60; - long seconds = totalSecEstimate % 60; - - System.out.println("Total estimate was " + hours + ":" + minutes + ":" + seconds); - - var est = (System.currentTimeMillis() - startTime) / 1000; - hours = est / 3600; - minutes = (est % 3600) / 60; - seconds = est % 60; - System.out.println("Actual total is " + hours + ":" + minutes + ":" + seconds); - - est = (firstEstimateStart - startTime) / 1000; - hours = est / 3600; - minutes = (est % 3600) / 60; - seconds = est % 60; - System.out.println("Before first estimate " + hours + ":" + minutes + ":" + seconds); - - est = (System.currentTimeMillis() - firstEstimateStart) / 1000; - hours = est / 3600; - minutes = (est % 3600) / 60; - seconds = est % 60; - System.out.println("Since first estimate " + hours + ":" + minutes + ":" + seconds); - } - @formatter:on */ - return sb.append(a.getVersion()).toString(); - } -} diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeBuilder.java b/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeBuilder.java deleted file mode 100644 index 5ee0fe3f..00000000 --- a/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeBuilder.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.quarkus.domino.tree; - -import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; -import java.util.List; -import java.util.Objects; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.artifact.DefaultArtifact; -import org.eclipse.aether.collection.CollectRequest; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.graph.DependencyNode; -import org.eclipse.aether.util.artifact.JavaScopes; - -public abstract class DependencyTreeBuilder { - - private static final Artifact root = new DefaultArtifact("io.domino", "resolver-root", "pom", "1.0"); - - public static DependencyTreeBuilder resolvingTreeBuilder(MavenArtifactResolver resolver) { - return new ResolvingDependencyTreeBuilder(resolver); - } - - public static DependencyTreeBuilder nonResolvingTreeBuilder(MavenArtifactResolver resolver) { - return new NonResolvingDependencyTreeBuilder(resolver); - } - - protected final MavenArtifactResolver resolver; - - DependencyTreeBuilder(MavenArtifactResolver resolver) { - this.resolver = Objects.requireNonNull(resolver); - } - - public DependencyNode buildTree(DependencyTreeRoot root) { - var rootNode = doBuildTree(root); - if (rootNode.getChildren().size() != 1) { - throw new RuntimeException("Expected a single child node but got " + rootNode.getChildren()); - } - return rootNode.getChildren().get(0); - } - - public abstract DependencyNode doBuildTree(DependencyTreeRoot root); - - protected CollectRequest createCollectRequest(DependencyTreeRoot root) { - return new CollectRequest() - .setRootArtifact(DependencyTreeBuilder.root) - .setDependencies(List.of( - new Dependency( - root.getArtifact(), - JavaScopes.RUNTIME, - false, - root.getExclusions()))) - .setManagedDependencies(root.getConstraints()) - .setRepositories(resolver.getRepositories()); - } -} diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeRoot.java b/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeRoot.java deleted file mode 100644 index 6f16199b..00000000 --- a/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeRoot.java +++ /dev/null @@ -1,36 +0,0 @@ -package io.quarkus.domino.tree; - -import java.util.Collection; -import java.util.List; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.graph.Exclusion; - -public class DependencyTreeRoot { - - private final Artifact root; - private final List constraints; - private final Collection exclusions; - - public DependencyTreeRoot(Artifact root, List constraints, Collection exclusions) { - this.root = root; - this.constraints = constraints; - this.exclusions = exclusions; - } - - String getId() { - return root.toString(); - } - - Artifact getArtifact() { - return root; - } - - List getConstraints() { - return constraints; - } - - Collection getExclusions() { - return exclusions; - } -} diff --git a/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeVisitScheduler.java b/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeVisitScheduler.java deleted file mode 100644 index bd62dc67..00000000 --- a/domino/api/src/main/java/io/quarkus/domino/tree/DependencyTreeVisitScheduler.java +++ /dev/null @@ -1,122 +0,0 @@ -package io.quarkus.domino.tree; - -import io.quarkus.devtools.messagewriter.MessageWriter; -import io.quarkus.domino.processor.ExecutionContext; -import io.quarkus.domino.processor.NodeProcessor; -import io.quarkus.domino.processor.ParallelTreeProcessor; -import io.quarkus.domino.processor.TaskResult; -import java.util.Collection; -import java.util.List; -import java.util.function.Function; -import org.eclipse.aether.artifact.Artifact; -import org.eclipse.aether.graph.Dependency; -import org.eclipse.aether.graph.DependencyNode; -import org.eclipse.aether.graph.Exclusion; - -public interface DependencyTreeVisitScheduler { - - static DependencyTreeVisitScheduler sequencial(DependencyTreeBuilder treeBuilder, - DependencyTreeVisitor processor, - MessageWriter log, - int treesTotal) { - return new BaseDependencyTreeProcessScheduler<>(processor, log, treesTotal) { - - @Override - public void scheduleProcessing(DependencyTreeRoot root) { - final DependencyNode rootNode; - try { - rootNode = treeBuilder.buildTree(root); - log.info(getResolvedTreeMessage(rootNode.getArtifact())); - } catch (Exception e) { - resolutionFailures.add(root.getArtifact()); - log.error(e.getLocalizedMessage()); - return; - } - ctx.root = rootNode; - processor.visitTree(ctx); - } - - @Override - public void waitForCompletion() { - } - }; - } - - static DependencyTreeVisitScheduler parallel(DependencyTreeBuilder treeBuilder, - DependencyTreeVisitor processor, - MessageWriter log, - int treesTotal) { - - return new BaseDependencyTreeProcessScheduler<>(processor, log, treesTotal) { - - final ParallelTreeProcessor treeProcessor = ParallelTreeProcessor - .with(new NodeProcessor<>() { - - @Override - public String getNodeId(DependencyTreeRoot request) { - return request.getId(); - } - - @Override - public Iterable getChildren(DependencyTreeRoot node) { - return List.of(); - } - - @Override - public Function, TaskResult> createFunction() { - return ctx -> { - var request = ctx.getNode(); - try { - var node = treeBuilder.buildTree(request); - log.info(getResolvedTreeMessage(request.getArtifact())); - return ctx.success(node); - } catch (Exception e) { - return ctx.failure(e); - } - }; - } - }); - - int scheduledTotal = 0; - - @Override - public void scheduleProcessing(DependencyTreeRoot root) { - ++scheduledTotal; - treeProcessor.addRoot(root); - } - - @Override - public void waitForCompletion() { - var results = treeProcessor.schedule().join(); - for (var r : results) { - if (r.isFailure()) { - resolutionFailures.add(r.getNode().getArtifact()); - log.error("Failed to resolve dependencies of " + r.getId()); - //if (r.getException() != null) { - // r.getException().printStackTrace(); - //} - } else { - ctx.root = r.getOutcome(); - processor.visitTree(ctx); - } - } - } - }; - } - - default void scheduleProcessing(Artifact rootArtifact, List constraints, Collection exclusions) { - scheduleProcessing(new DependencyTreeRoot(rootArtifact, constraints, exclusions)); - } - - void scheduleProcessing(DependencyTreeRoot root); - - void waitForCompletion(); - - Collection getResolutionFailures(); - - interface TreeProcessingResultHandler { - - void handleResult(R result, MessageWriter log); - } - -} diff --git a/domino/app/src/main/java/io/quarkus/domino/cli/Dependency.java b/domino/app/src/main/java/io/quarkus/domino/cli/Dependency.java index 7c1ac9b4..301a1c11 100644 --- a/domino/app/src/main/java/io/quarkus/domino/cli/Dependency.java +++ b/domino/app/src/main/java/io/quarkus/domino/cli/Dependency.java @@ -6,8 +6,9 @@ import io.quarkus.bootstrap.resolver.maven.options.BootstrapMavenOptions; import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.domino.ArtifactSet; -import io.quarkus.domino.tree.DependencyTreeProcessor; -import io.quarkus.domino.tree.DependencyTreeVisitor; +import io.quarkus.domino.inspect.DependencyTreeError; +import io.quarkus.domino.inspect.DependencyTreeInspector; +import io.quarkus.domino.inspect.DependencyTreeVisitor; import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.util.GlobUtil; import java.io.BufferedWriter; @@ -97,7 +98,7 @@ public Integer call() throws Exception { var treeVisitor = new DependencyTreeVisitor>() { @Override - public void visitTree(DependencyTreeVisit> ctx) { + public void visit(DependencyTreeVisit> ctx) { if (tracePattern != null) { visitNode(ctx, ctx.getRoot(), new ArrayList<>()); } @@ -126,9 +127,10 @@ public void onEvent(List result, MessageWriter log) { } @Override - public void handleResolutionFailures(Collection artifacts) { + public void handleResolutionFailures(Collection errors) { if (invalidArtifactsReport != null) { - for (var a : artifacts) { + for (var e : errors) { + var a = e.getRequest().getArtifact(); var sb = new StringBuilder(); sb.append(a.getGroupId()).append(":").append(a.getArtifactId()).append(":"); if (!a.getClassifier().isEmpty()) { @@ -147,7 +149,7 @@ public void handleResolutionFailures(Collection artifacts) { } }; - var treeProcessor = DependencyTreeProcessor.configure() + var treeProcessor = DependencyTreeInspector.configure() .setArtifactResolver(resolver) .setResolveDependencies(resolve) .setParallelProcessing(parallelProcessing) @@ -171,7 +173,7 @@ public void handleResolutionFailures(Collection artifacts) { for (var d : descriptor.getManagedDependencies()) { var a = d.getArtifact(); if (isVersionSelected(a.getVersion()) && managedRoots.add(d.getArtifact().toString())) { - treeProcessor.addRoot(d.getArtifact(), constraints, d.getExclusions()); + treeProcessor.inspectAsDependency(d.getArtifact(), constraints, d.getExclusions()); } } } else if (this.roots.isEmpty()) { @@ -184,12 +186,12 @@ public void handleResolutionFailures(Collection artifacts) { var a = new DefaultArtifact(coords.getGroupId(), coords.getArtifactId(), coords.getClassifier(), coords.getType(), coords.getVersion()); if (isVersionSelected(a.getVersion())) { - treeProcessor.addRoot(a); + treeProcessor.inspectAsDependency(a); } } } - treeProcessor.process(); + treeProcessor.complete(); if (!invalidArtifacts.isEmpty() && invalidArtifactsReport != null) { var list = new ArrayList<>(invalidArtifacts); diff --git a/domino/app/src/main/java/io/quarkus/domino/cli/Quarkus.java b/domino/app/src/main/java/io/quarkus/domino/cli/Quarkus.java index 330c7207..427e7f26 100644 --- a/domino/app/src/main/java/io/quarkus/domino/cli/Quarkus.java +++ b/domino/app/src/main/java/io/quarkus/domino/cli/Quarkus.java @@ -8,10 +8,11 @@ import io.quarkus.devtools.messagewriter.MessageWriter; import io.quarkus.domino.ArtifactCoordsPattern; import io.quarkus.domino.ArtifactSet; -import io.quarkus.domino.tree.DependencyTreeProcessor; -import io.quarkus.domino.tree.DependencyTreeVisitor; -import io.quarkus.domino.tree.quarkus.QuarkusPlatformInfo; -import io.quarkus.domino.tree.quarkus.QuarkusPlatformInfoReader; +import io.quarkus.domino.inspect.DependencyTreeError; +import io.quarkus.domino.inspect.DependencyTreeInspector; +import io.quarkus.domino.inspect.DependencyTreeVisitor; +import io.quarkus.domino.inspect.quarkus.QuarkusPlatformInfo; +import io.quarkus.domino.inspect.quarkus.QuarkusPlatformInfoReader; import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.paths.PathTree; import io.quarkus.util.GlobUtil; @@ -121,7 +122,7 @@ public Integer call() throws Exception { var treeVisitor = new DependencyTreeVisitor() { @Override - public void visitTree(DependencyTreeVisit ctx) { + public void visit(DependencyTreeVisit ctx) { if (tracePattern != null) { visitNode(ctx, ctx.getRoot(), new DependencyStack()); } @@ -163,11 +164,11 @@ public void onEvent(DependencyStack stack, MessageWriter log) { } @Override - public void handleResolutionFailures(Collection artifacts) { + public void handleResolutionFailures(Collection requests) { } }; - var treeProcessor = DependencyTreeProcessor.configure() + var treeProcessor = DependencyTreeInspector.configure() .setArtifactResolver(resolver) .setResolveDependencies(resolve) .setParallelProcessing(parallelProcessing) @@ -181,7 +182,7 @@ public void handleResolutionFailures(Collection artifacts) { effectiveConstraints = coreConstraints; var pluginCoords = platform.getMavenPlugin(); if (isVersionSelected(pluginCoords.getVersion())) { - treeProcessor.addRoot(getAetherArtifact(pluginCoords)); + treeProcessor.inspectPlugin(getAetherArtifact(pluginCoords)); if (tracePattern != null) { rootsToMembers.computeIfAbsent(pluginCoords, k -> new ArrayList<>(1)).add(m); } @@ -197,7 +198,7 @@ public void handleResolutionFailures(Collection artifacts) { for (var e : m.metadata.getExtensions()) { if (isVersionSelected(e.getVersion())) { var d = m.bomConstraints.get(e); - treeProcessor.addRoot(getAetherArtifact(e), effectiveConstraints, + treeProcessor.inspectAsDependency(getAetherArtifact(e), effectiveConstraints, d == null ? List.of() : d.getExclusions()); if (tracePattern != null) { rootsToMembers.computeIfAbsent(e, k -> new ArrayList<>(1)).add(m); @@ -228,7 +229,7 @@ public void handleResolutionFailures(Collection artifacts) { }); } d = m.bomConstraints.get(deployment); - treeProcessor.addRoot(getAetherArtifact(deployment), effectiveConstraints, + treeProcessor.inspectAsDependency(getAetherArtifact(deployment), effectiveConstraints, d == null ? List.of() : d.getExclusions()); if (tracePattern != null) { rootsToMembers.computeIfAbsent(deployment, k -> new ArrayList<>(1)).add(m); @@ -249,7 +250,7 @@ public void handleResolutionFailures(Collection artifacts) { } } - treeProcessor.process(); + treeProcessor.complete(); int membersWithTraces = 0; for (var report : memberReports) {