Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Alexey Loubyansky committed Dec 11, 2024
1 parent 177a3fa commit d378086
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,28 @@
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.BootstrapAppModelResolver;
import io.quarkus.bootstrap.resolver.TsArtifact;
import io.quarkus.bootstrap.resolver.TsDependency;
import io.quarkus.bootstrap.resolver.TsQuarkusExt;
import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject;
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 {

@Override
protected BootstrapAppModelResolver newAppModelResolver(LocalProject currentProject) throws Exception {
var resolver = super.newAppModelResolver(currentProject);
//resolver.setIncubatingModelResolver(true);
return resolver;
}

@Override
protected TsArtifact composeApplication() {

Expand Down Expand Up @@ -70,16 +81,24 @@ 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-deployment", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.OPTIONAL,
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-deployment-dep", 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", 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-deployment", TsArtifact.DEFAULT_VERSION),
JavaScopes.COMPILE,
DependencyFlags.DEPLOYMENT_CP));
assertEquals(expected, getDeploymentOnlyDeps(model));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ private ApplicationModel buildAppModel(ResolvedDependencyBuilder appArtifact,
var collectRtDepsRequest = MavenArtifactResolver.newCollectRequest(artifact, directDeps, managedDeps, List.of(), repos);
try {
long start = 0;
boolean logTime = false;
boolean logTime = true;
if (logTime) {
start = System.currentTimeMillis();
}
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,24 @@ private static DependencyNode normalize(RepositorySystemSession session, Depende
}
}

private static DependencyNode newNormalize(DependencyNode root) {
//var start = System.currentTimeMillis();
var visitor = new OrderedDependencyVisitor(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
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()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.eclipse.aether.artifact.DefaultArtifact;
import org.eclipse.aether.graph.DefaultDependencyNode;
import org.eclipse.aether.graph.DependencyNode;
import org.eclipse.aether.util.graph.transformer.ConflictResolver;
import org.junit.jupiter.api.Test;

public class OrderedDependencyVisitorTest {
Expand Down Expand Up @@ -133,6 +134,146 @@ public void main() {
assertThat(visitor.hasNext()).isFalse();
}

@Test
public void testRemove() {

var root = newNode("root");

// direct dependencies
var colors = newNode("colors");
var pets = newNode("pets");
var trees = newNode("trees");
root.setChildren(List.of(colors, pets, trees));

// colors
var red = newNode("red");
var green = newNode("green");
var blue = newNode("blue");
colors.setChildren(List.of(red, green, blue));

// pets
var dog = newNode("dog");
var cat = newNode("cat");
pets.setChildren(List.of(dog, cat));
// pets, puppy
var puppy = newNode("puppy");
dog.setChildren(List.of(puppy));

// trees
var pine = newNode("pine");
trees.setChildren(Arrays.asList(pine)); // List.of() can't be used for replace
var oak = newNode("oak");
// oak, acorn
var acorn = newNode("acorn");
oak.setChildren(List.of(acorn));

// create a visitor
var visitor = new OrderedDependencyVisitor(root);

// assertions
assertThat(visitor.hasNext()).isTrue();

// distance 0
assertThat(visitor.next()).isSameAs(root);
assertThat(visitor.getCurrent()).isSameAs(root);
assertThat(visitor.getCurrentDistance()).isEqualTo(0);
assertThat(visitor.hasNext()).isTrue();

// distance 1, colors
assertThat(visitor.next()).isSameAs(colors);
assertThat(visitor.getCurrent()).isSameAs(colors);
assertThat(visitor.getCurrentDistance()).isEqualTo(1);
assertThat(visitor.hasNext()).isTrue();
visitor.setNearerExists();
assertThat(visitor.hasNext()).isTrue();

// distance 1, pets
assertThat(visitor.next()).isSameAs(pets);
assertThat(visitor.getCurrent()).isSameAs(pets);
assertThat(visitor.getCurrentDistance()).isEqualTo(1);
assertThat(visitor.hasNext()).isTrue();

// distance 1, trees
var node = visitor.next();
assertThat(node).isSameAs(trees);
assertThat(visitor.getCurrent()).isSameAs(trees);
assertThat(visitor.getCurrentDistance()).isEqualTo(1);
assertThat(visitor.hasNext()).isTrue();
assertThat(node.getData().get(ConflictResolver.NODE_DATA_WINNER)).isNull();
visitor.setNearerExists();
assertThat(node.getData().get(ConflictResolver.NODE_DATA_WINNER)).isNotNull();
assertThat(visitor.hasNext()).isTrue();

// distance 2, pets, dog
assertThat(visitor.next()).isSameAs(dog);
assertThat(visitor.getCurrent()).isSameAs(dog);
assertThat(visitor.getCurrentDistance()).isEqualTo(2);
assertThat(visitor.hasNext()).isTrue();

// distance 2, pets, cat
assertThat(visitor.next()).isSameAs(cat);
assertThat(visitor.getCurrent()).isSameAs(cat);
assertThat(visitor.getCurrentDistance()).isEqualTo(2);
assertThat(visitor.hasNext()).isTrue();

// distance 3, pets, dog, puppy
assertThat(visitor.next()).isSameAs(puppy);
assertThat(visitor.getCurrent()).isSameAs(puppy);
assertThat(visitor.getCurrentDistance()).isEqualTo(3);
assertThat(visitor.hasNext()).isFalse();

// re-iterate to make sure the changes applied on the first visit were applied

visitor = new OrderedDependencyVisitor(root);
assertThat(visitor.hasNext()).isTrue();

// distance 0
assertThat(visitor.next()).isSameAs(root);
assertThat(visitor.getCurrent()).isSameAs(root);
assertThat(visitor.getCurrentDistance()).isEqualTo(0);
assertThat(visitor.hasNext()).isTrue();

// distance 1, colors
node = visitor.next();
assertThat(node.getData().get(ConflictResolver.NODE_DATA_WINNER)).isNotNull();
assertThat(node).isSameAs(colors);
assertThat(visitor.getCurrent()).isSameAs(colors);
assertThat(visitor.getCurrentDistance()).isEqualTo(1);
assertThat(visitor.hasNext()).isTrue();

// distance 1, pets
assertThat(visitor.next()).isSameAs(pets);
assertThat(visitor.getCurrent()).isSameAs(pets);
assertThat(visitor.getCurrentDistance()).isEqualTo(1);
assertThat(visitor.hasNext()).isTrue();

// distance 1, trees
node = visitor.next();
assertThat(node.getData().get(ConflictResolver.NODE_DATA_WINNER)).isNotNull();
assertThat(node).isSameAs(trees);
assertThat(visitor.getCurrent()).isSameAs(trees);
assertThat(visitor.getCurrentDistance()).isEqualTo(1);
assertThat(visitor.hasNext()).isTrue();

// distance 2, pets, dog
assertThat(visitor.next()).isSameAs(dog);
assertThat(visitor.getCurrent()).isSameAs(dog);
assertThat(visitor.getCurrentDistance()).isEqualTo(2);
assertThat(visitor.hasNext()).isTrue();

// distance 2, pets, cat
assertThat(visitor.next()).isSameAs(cat);
assertThat(visitor.getCurrent()).isSameAs(cat);
assertThat(visitor.getCurrentDistance()).isEqualTo(2);
assertThat(visitor.hasNext()).isTrue();

// distance 3, pets, dog, puppy
assertThat(visitor.next()).isSameAs(puppy);
assertThat(visitor.getCurrent()).isSameAs(puppy);
assertThat(visitor.getCurrentDistance()).isEqualTo(3);
assertThat(visitor.hasNext()).isFalse();
}

private static DependencyNode newNode(String artifactId) {
return new DefaultDependencyNode(new DefaultArtifact(ORG_ACME, artifactId, JAR, VERSION));
}
Expand Down

0 comments on commit d378086

Please sign in to comment.