Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexey Loubyansky committed Dec 12, 2024
1 parent 5df7b0e commit b5f0683
Show file tree
Hide file tree
Showing 6 changed files with 334 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
import java.util.HashSet;
import java.util.Set;

import org.eclipse.aether.util.artifact.JavaScopes;

import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.bootstrap.resolver.TsArtifact;
import io.quarkus.bootstrap.resolver.TsDependency;
import io.quarkus.bootstrap.resolver.TsQuarkusExt;
import io.quarkus.maven.dependency.ArtifactCoords;
import io.quarkus.maven.dependency.ArtifactDependency;
import io.quarkus.maven.dependency.Dependency;
import io.quarkus.maven.dependency.DependencyFlags;
import io.quarkus.maven.dependency.GACTV;

public class OptionalDepsTest extends BootstrapFromOriginalJarTestBase {

Expand Down Expand Up @@ -70,17 +72,73 @@ protected TsArtifact composeApplication() {
@Override
protected void assertAppModel(ApplicationModel model) throws Exception {
final Set<Dependency> expected = new HashSet<>();
expected.add(new ArtifactDependency(new GACTV("io.quarkus.bootstrap.test", "ext-a-deployment", "1"), "compile",

expected.add(new ArtifactDependency(
ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-a", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.DIRECT,
DependencyFlags.OPTIONAL,
DependencyFlags.RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP));

expected.add(new ArtifactDependency(
ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-a-dep", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.OPTIONAL,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP));

expected.add(new ArtifactDependency(
ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-a-deployment", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.OPTIONAL,
DependencyFlags.DEPLOYMENT_CP));

expected.add(new ArtifactDependency(
ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "app-optional-dep", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.OPTIONAL,
DependencyFlags.DIRECT,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP));
expected.add(new ArtifactDependency(new GACTV("io.quarkus.bootstrap.test", "ext-b-deployment-dep", "1"), "compile",

expected.add(new ArtifactDependency(
ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-b", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.OPTIONAL,
DependencyFlags.RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP));

expected.add(new ArtifactDependency(ArtifactCoords.jar(
TsArtifact.DEFAULT_GROUP_ID, "ext-b-deployment", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.OPTIONAL,
DependencyFlags.DEPLOYMENT_CP));
expected.add(new ArtifactDependency(new GACTV("io.quarkus.bootstrap.test", "ext-b-deployment", "1"), "compile",

expected.add(new ArtifactDependency(
ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-b-deployment-dep", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.OPTIONAL,
DependencyFlags.DEPLOYMENT_CP));
expected.add(new ArtifactDependency(new GACTV("io.quarkus.bootstrap.test", "ext-d-deployment", "1"), "compile",

expected.add(new ArtifactDependency(
ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-d", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.DIRECT,
DependencyFlags.RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP));
assertEquals(expected, getDeploymentOnlyDeps(model));

expected.add(new ArtifactDependency(
ArtifactCoords.jar(TsArtifact.DEFAULT_GROUP_ID, "ext-d-deployment", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.DEPLOYMENT_CP));

assertEquals(expected, getDependenciesWithFlag(model, DependencyFlags.DEPLOYMENT_CP));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ private ApplicationModel buildAppModel(ResolvedDependencyBuilder appArtifact,
if (logTime) {
start = System.currentTimeMillis();
}
if (incubatingModelResolver) {
if (true) {
IncubatingApplicationModelResolver.newInstance()
.setArtifactResolver(mvn)
.setApplicationModelBuilder(appBuilder)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package io.quarkus.bootstrap.resolver.maven;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.aether.graph.DependencyNode;

import io.quarkus.maven.dependency.ArtifactCoords;

class DepNode {

static DepNode of(DependencyNode node) {
return new DepNode(node);
}

final DepNode parent;
final ArtifactCoords coords;
final List<DepNode> deps;

DepNode(DependencyNode node) {
this(null, node);
}

DepNode(DepNode parent, DependencyNode node) {
this.parent = parent;
var a = node.getArtifact();
this.coords = ArtifactCoords.of(a.getGroupId(), a.getArtifactId(), a.getClassifier(), a.getExtension(), a.getVersion());
if (node.getChildren().isEmpty()) {
deps = List.of();
} else {
deps = new ArrayList<>(node.getChildren().size());
for (var d : node.getChildren()) {
deps.add(new DepNode(this, d));
}
}
}

void assertEquals(DepNode other) {
if (!other.coords.equals(coords)) {
throw new RuntimeException();
}
int i = 0;
while (i < deps.size() && i < other.deps.size()) {
deps.get(i).assertEquals(other.deps.get(i));
++i;
}
if (i < deps.size()) {
throw new RuntimeException();
}
if (i < other.deps.size()) {
throw new RuntimeException();
}
}

@Override
public boolean equals(Object o) {
if (o instanceof DepNode other) {
if (!other.coords.equals(coords)) {
return false;
}
return deps.equals(other.deps);
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.function.BiConsumer;
Expand Down Expand Up @@ -251,7 +253,8 @@ public void resolve(CollectRequest collectRtDepsRequest) throws AppModelResolver
if (!runtimeModelOnly) {
injectDeploymentDeps();
}
root = normalize(resolver.getSession(), root);
root = newNormalize(root);
//root = normalize(resolver.getSession(), root);
populateModelBuilder(root);

// clear the reloadable flags
Expand Down Expand Up @@ -476,6 +479,25 @@ private static DependencyNode normalize(RepositorySystemSession session, Depende
}
}

private static DependencyNode newNormalize(DependencyNode root) {
//var start = System.currentTimeMillis();
var visitor = new OrderedDependencyVisitor(root);
visitor.next();// skip the root
final Set<ArtifactKey> visited = new HashSet<>();
while (visitor.hasNext()) {
var node = visitor.next();
if (hasWinner(node)) {
continue;
}
var key = getKey(node.getArtifact());
if (!visited.add(key)) {
visitor.setNearerExists();
}
}
//System.out.println("newNormalize " + (System.currentTimeMillis() - start));
return root;
}

/**
* Resolves a project's runtime dependencies. This is the first step in the Quarkus application model resolution.
* These dependencies do not include Quarkus conditional dependencies.
Expand Down Expand Up @@ -977,6 +999,8 @@ private void collectDeploymentDeps() {
+ "or the artifact does not have any dependencies while at least a dependency on the runtime artifact "
+ info.runtimeArtifact + " is expected");
}
ensureScopeAndOptionality(deploymentNode, runtimeNode.getDependency().getScope(),
runtimeNode.getDependency().isOptional());

replaceRuntimeExtensionNodes(deploymentNode);
if (!presentInTargetGraph) {
Expand All @@ -998,6 +1022,7 @@ private void injectDependencyDependency(DependencyNode parentDeploymentNode) {
}

void replaceRuntimeExtensionNodes(DependencyNode deploymentNode) {
final boolean setOptional = this.runtimeNode.getDependency().isOptional();
var deploymentVisitor = new OrderedDependencyVisitor(deploymentNode);
// skip the root node
deploymentVisitor.next();
Expand Down Expand Up @@ -1058,9 +1083,13 @@ void activate() {
return;
}
activated = true;
final AppDep parent = conditionalDep.parent;
final DependencyNode originalNode = collectDependencies(conditionalDep.node.getArtifact(),
conditionalDep.parent.ext.exclusions,
conditionalDep.parent.node.getRepositories());
parent.ext.exclusions,
parent.node.getRepositories());
ensureScopeAndOptionality(originalNode, parent.ext.runtimeNode.getDependency().getScope(),
parent.ext.runtimeNode.getDependency().isOptional());

final DefaultDependencyNode rtNode = (DefaultDependencyNode) conditionalDep.node;
rtNode.setRepositories(originalNode.getRepositories());
// if this node has conditional dependencies on its own, they may have been activated by this time
Expand All @@ -1077,10 +1106,10 @@ void activate() {
visitRuntimeDeps();
conditionalDep.setFlags(
(byte) (COLLECT_DEPLOYMENT_INJECTION_POINTS | (collectReloadableModules ? COLLECT_RELOADABLE_MODULES : 0)));
if (conditionalDep.parent.resolvedDep != null) {
conditionalDep.parent.resolvedDep.addDependency(conditionalDep.resolvedDep.getArtifactCoords());
if (parent.resolvedDep != null) {
parent.resolvedDep.addDependency(conditionalDep.resolvedDep.getArtifactCoords());
}
conditionalDep.parent.ext.runtimeNode.getChildren().add(rtNode);
parent.ext.runtimeNode.getChildren().add(rtNode);
}

private void visitRuntimeDeps() {
Expand All @@ -1103,6 +1132,23 @@ boolean isSatisfied() {
}
}

private static void ensureScopeAndOptionality(DependencyNode node, String scope, boolean optional) {
var dep = node.getDependency();
if (optional == dep.isOptional() && scope.equals(dep.getScope())) {
return;
}
var visitor = new OrderedDependencyVisitor(node);
while (visitor.hasNext()) {
dep = visitor.next().getDependency();
if (optional != dep.isOptional()) {
visitor.getCurrent().setOptional(optional);
}
if (!scope.equals(dep.getScope())) {
visitor.getCurrent().setScope(scope);
}
}
}

private static boolean isSameKey(Artifact a1, Artifact a2) {
return a2.getArtifactId().equals(a1.getArtifactId())
&& a2.getGroupId().equals(a1.getGroupId())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import java.util.List;
import java.util.NoSuchElementException;

import org.eclipse.aether.graph.DefaultDependencyNode;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.util.graph.transformer.ConflictResolver;

/**
* Walks a dependency tree by visiting dependencies in the order of their priorities
Expand Down Expand Up @@ -102,4 +104,13 @@ DependencyNode next() {
void replaceCurrent(DependencyNode newNode) {
currentList.set(currentIndex, newNode);
}

/**
* Adds a link to a "winning" node, indicating that a nearer dependency on the artifact exists in the graph
*/
void setNearerExists() {
final DependencyNode currentNode = currentList.get(currentIndex);
currentNode.setChildren(List.of());
currentNode.setData(ConflictResolver.NODE_DATA_WINNER, new DefaultDependencyNode(currentNode.getDependency()));
}
}
Loading

0 comments on commit b5f0683

Please sign in to comment.