Skip to content

Commit

Permalink
Include compile-only dependencies in the ApplicationModel
Browse files Browse the repository at this point in the history
  • Loading branch information
aloubyansky committed Sep 24, 2023
1 parent f7da1d7 commit 48c1028
Show file tree
Hide file tree
Showing 9 changed files with 239 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
Expand Down Expand Up @@ -115,7 +114,17 @@ public Path getPath(Path workDir) throws IOException {

public static Collection<Dependency> getDeploymentOnlyDeps(ApplicationModel model) {
return model.getDependencies().stream().filter(d -> d.isDeploymentCp() && !d.isRuntimeCp())
.map(d -> new ArtifactDependency(d)).collect(Collectors.toSet());
.map(ArtifactDependency::new).collect(Collectors.toSet());
}

public static Collection<Dependency> getDependenciesWithFlag(ApplicationModel model, int flag) {
var set = new HashSet<Dependency>();
for (var d : model.getDependencies(flag)) {
if (d.isFlagSet(flag)) {
set.add(new ArtifactDependency(d));
}
}
return set;
}

@Override
Expand Down Expand Up @@ -159,7 +168,7 @@ protected void testBootstrap(QuarkusBootstrap creator) throws Exception {
}
}

List<String> missingEntries = Collections.emptyList();
List<String> missingEntries = List.of();
for (String entry : expectedLib) {
if (!actualMainLib.remove(entry)) {
if (missingEntries.isEmpty()) {
Expand Down
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 ProvidedExtensionDepsTest extends BootstrapFromOriginalJarTestBase {

Expand Down Expand Up @@ -51,11 +53,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",
Set<Dependency> expected = new HashSet<>();
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-deployment", "1"),
DependencyFlags.DEPLOYMENT_CP));
expected.add(new ArtifactDependency(new GACTV("io.quarkus.bootstrap.test", "ext-a-deployment-dep", "1"), "compile",
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-deployment-dep", "1"),
DependencyFlags.DEPLOYMENT_CP));
assertEquals(expected, getDeploymentOnlyDeps(model));

expected = new HashSet<>();
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b", "1"),
JavaScopes.PROVIDED,
DependencyFlags.RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.DIRECT,
DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.COMPILE_ONLY));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "some-provided-dep", "1"),
JavaScopes.PROVIDED,
DependencyFlags.DIRECT,
DependencyFlags.COMPILE_ONLY));
assertEquals(expected, getDependenciesWithFlag(model, DependencyFlags.COMPILE_ONLY));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package io.quarkus.deployment.runnerjar;

import static org.junit.jupiter.api.Assertions.assertEquals;

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;

public class ProvidedExtensionDepsTestModeTest extends BootstrapFromOriginalJarTestBase {

@Override
protected boolean isBootstrapForTestMode() {
return true;
}

@Override
protected TsArtifact composeApplication() {

final TsArtifact extADep = TsArtifact.jar("ext-a-dep");
addToExpectedLib(extADep);

final TsArtifact extAProvidedDep = TsArtifact.jar("ext-a-provided-dep");

final TsArtifact extADeploymentDep = TsArtifact.jar("ext-a-deployment-dep");
final TsArtifact extAOptionalDeploymentDep = TsArtifact.jar("ext-a-provided-deployment-dep");

final TsQuarkusExt extA = new TsQuarkusExt("ext-a");
addToExpectedLib(extA.getRuntime());
extA.getRuntime()
.addDependency(new TsDependency(extADep))
.addDependency(new TsDependency(extAProvidedDep, "provided"));
extA.getDeployment()
.addDependency(new TsDependency(extADeploymentDep))
.addDependency(new TsDependency(extAOptionalDeploymentDep, "provided"));

final TsQuarkusExt extB = new TsQuarkusExt("ext-b");
this.install(extB);
addToExpectedLib(extB.getRuntime()); // test mode enabled

final TsArtifact someProvidedDep = TsArtifact.jar("some-provided-dep");
addToExpectedLib(someProvidedDep); // test mode enabled

return TsArtifact.jar("app")
.addManagedDependency(platformDescriptor())
.addManagedDependency(platformProperties())
.addDependency(extA)
.addDependency(extB, "provided")
.addDependency(new TsDependency(someProvidedDep, "provided"));
}

@Override
protected void assertAppModel(ApplicationModel model) throws Exception {

final Set<Dependency> compileOnly = new HashSet<>();
compileOnly.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b", "1"),
JavaScopes.PROVIDED,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.DIRECT,
DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.COMPILE_ONLY));
compileOnly.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "some-provided-dep", "1"),
JavaScopes.PROVIDED,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.DIRECT,
DependencyFlags.COMPILE_ONLY));
assertEquals(compileOnly, getDependenciesWithFlag(model, DependencyFlags.COMPILE_ONLY));

Set<Dependency> expected = new HashSet<>();
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-deployment", "1"),
DependencyFlags.DEPLOYMENT_CP));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-deployment-dep", "1"),
DependencyFlags.DEPLOYMENT_CP));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-b-deployment", "1"),
JavaScopes.PROVIDED,
DependencyFlags.DEPLOYMENT_CP));

assertEquals(expected, getDeploymentOnlyDeps(model));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,25 @@ public interface ApplicationModel {
ResolvedDependency getAppArtifact();

/**
* All the dependencies of an application including runtime and build time dependencies.
* Returns application dependencies that are included into the runtime and augmentation (Quarkus build time)
* classpath.
* <p>
* Note: in production bootstrap mode, {@link io.quarkus.maven.dependency.DependencyFlags#COMPILE_ONLY} dependencies
* will not be included in the result. However, they could still be queries by calling {@link #getDependencies(int)}
* passing in {@link io.quarkus.maven.dependency.DependencyFlags#COMPILE_ONLY} flag as an argument.
*
* @return application runtime and build time dependencies
*/
Collection<ResolvedDependency> getDependencies();

/**
* Returns application dependencies with the requested flags set.
*
* @param flags dependency flags that must be set for a dependency to be included in the result
* @return application dependencies that have requested flags set
*/
Iterable<ResolvedDependency> getDependencies(int flags);

/**
* Runtime dependencies of an application
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package io.quarkus.bootstrap.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.Collectors;

Expand Down Expand Up @@ -39,7 +42,50 @@ public ResolvedDependency getAppArtifact() {

@Override
public Collection<ResolvedDependency> getDependencies() {
return dependencies;
var result = new ArrayList<ResolvedDependency>(dependencies.size());
for (var d : getDependencies(DependencyFlags.DEPLOYMENT_CP)) {
result.add(d);
}
return result;
}

@Override
public Iterable<ResolvedDependency> getDependencies(int flags) {
return () -> new Iterator<>() {

final Iterator<ResolvedDependency> i = dependencies.iterator();
ResolvedDependency next;

{
moveOn();
}

@Override
public boolean hasNext() {
return next != null;
}

@Override
public ResolvedDependency next() {
if (next == null) {
throw new NoSuchElementException();
}
var current = next;
moveOn();
return current;
}

private void moveOn() {
next = null;
while (i.hasNext()) {
var d = i.next();
if ((d.getFlags() & flags) == flags) {
next = d;
break;
}
}
}
};
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,44 @@
public interface DependencyFlags {

/* @formatter:off */
public static final int OPTIONAL = 0b000000000001;
public static final int DIRECT = 0b000000000010;
public static final int RUNTIME_CP = 0b000000000100;
public static final int DEPLOYMENT_CP = 0b000000001000;
public static final int RUNTIME_EXTENSION_ARTIFACT = 0b000000010000;
public static final int WORKSPACE_MODULE = 0b000000100000;
public static final int RELOADABLE = 0b000001000000;
public static final int OPTIONAL = 0b0000000000001;
public static final int DIRECT = 0b0000000000010;
public static final int RUNTIME_CP = 0b0000000000100;
public static final int DEPLOYMENT_CP = 0b0000000001000;
public static final int RUNTIME_EXTENSION_ARTIFACT = 0b0000000010000;
public static final int WORKSPACE_MODULE = 0b0000000100000;
public static final int RELOADABLE = 0b0000001000000;
// A top-level runtime extension artifact is either a direct
// dependency or a first extension dependency on the branch
// navigating from the root to leaves
public static final int TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT = 0b000010000000;
public static final int CLASSLOADER_PARENT_FIRST = 0b000100000000;
public static final int CLASSLOADER_RUNNER_PARENT_FIRST = 0b001000000000;
public static final int CLASSLOADER_LESSER_PRIORITY = 0b010000000000;
public static final int TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT = 0b0000010000000;
public static final int CLASSLOADER_PARENT_FIRST = 0b0000100000000;
public static final int CLASSLOADER_RUNNER_PARENT_FIRST = 0b0001000000000;
public static final int CLASSLOADER_LESSER_PRIORITY = 0b0010000000000;
// General purpose flag that could be re-used for various
// kinds of processing indicating that a dependency has been
// visited. This flag is meant to be cleared for all the nodes
// once the processing of the whole tree has completed.
public static final int VISITED = 0b100000000000;
public static final int VISITED = 0b0100000000000;

/**
* Compile-only dependencies are those that are configured in the project
* to be included only in the compile phase ({@code provided} dependency scope in Maven,
* {@code compileOnly} configuration in Gradle).
* <p>
* These dependencies will not be present on the Quarkus application runtime or
* augmentation (deployment) classpath when the application is bootstrapped in production mode
* (io.quarkus.runtime.LaunchMode.NORMAL).
* <p>
* Compile-only dependencies will be present on both the runtime and the augmentation classpath
* of a Quarkus application launched in test and dev modes.
* <p>
* In any case though, these dependencies will be available during augmentation for processing
* using {@link io.quarkus.bootstrap.model.ApplicationModel#getDependencies(int)} by passing
* this flag as an argument.
*/
public static final int COMPILE_ONLY = 0b1000000000000;

/* @formatter:on */

}
Original file line number Diff line number Diff line change
Expand Up @@ -289,13 +289,7 @@ private ApplicationModel doResolveModel(ArtifactCoords coords,
}

private Set<String> getExcludedScopes() {
if (test) {
return Set.of();
}
if (devmode) {
return Set.of(JavaScopes.TEST);
}
return Set.of(JavaScopes.PROVIDED, JavaScopes.TEST);
return test ? Set.of() : Set.of(JavaScopes.TEST);
}

private ApplicationModel buildAppModel(ResolvedDependency appArtifact, CollectRequest collectRtDepsRequest,
Expand All @@ -318,6 +312,7 @@ private ApplicationModel buildAppModel(ResolvedDependency appArtifact, CollectRe
.setApplicationModelBuilder(appBuilder)
.setCollectReloadableModules(collectReloadableDeps && reloadableModules.isEmpty())
.setBuildTreeConsumer(buildTreeConsumer)
.setIncludeCompileOnly(test || devmode)
.resolve(collectRtDepsRequest);
} catch (BootstrapDependencyProcessingException e) {
throw new AppModelResolverException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public static Artifact getRuntimeArtifact(DependencyNode dep) {
private ApplicationModelBuilder appBuilder;
private boolean collectReloadableModules;
private Consumer<String> buildTreeConsumer;
private boolean includeCompileOnly;

public ApplicationDependencyTreeResolver setArtifactResolver(MavenArtifactResolver resolver) {
this.resolver = resolver;
Expand Down Expand Up @@ -130,6 +131,11 @@ public ApplicationDependencyTreeResolver setBuildTreeConsumer(Consumer<String> b
return this;
}

public ApplicationDependencyTreeResolver setIncludeCompileOnly(boolean includeCompileOnly) {
this.includeCompileOnly = includeCompileOnly;
return this;
}

public void resolve(CollectRequest collectRtDepsRequest) throws AppModelResolverException {

DependencyNode root = resolveRuntimeDeps(collectRtDepsRequest);
Expand Down Expand Up @@ -206,7 +212,7 @@ public void resolve(CollectRequest collectRtDepsRequest) throws AppModelResolver
root = normalize(originalSession, root);

final BuildDependencyGraphVisitor buildDepsVisitor = new BuildDependencyGraphVisitor(originalResolver, appBuilder,
buildTreeConsumer);
buildTreeConsumer, includeCompileOnly);
buildDepsVisitor.visit(root);

if (!CONVERGED_TREE_ONLY && collectReloadableModules) {
Expand Down Expand Up @@ -354,11 +360,17 @@ private void visitRuntimeDependency(DependencyNode node) {
artifact.getArtifactId(), artifact.getVersion());
}
dep = toAppArtifact(artifact, module)
.setRuntimeCp()
.setDeploymentCp()
.setOptional(node.getDependency().isOptional())
.setScope(node.getDependency().getScope())
.setDirect(isWalkingFlagOn(COLLECT_DIRECT_DEPS));
if (JavaScopes.PROVIDED.equals(dep.getScope())) {
dep.setFlags(DependencyFlags.COMPILE_ONLY);
if (includeCompileOnly) {
dep.setRuntimeCp().setDeploymentCp();
}
} else {
dep.setRuntimeCp().setDeploymentCp();
}
if (extDep != null) {
dep.setRuntimeExtensionArtifact();
if (isWalkingFlagOn(COLLECT_TOP_EXTENSION_RUNTIME_NODES)) {
Expand Down
Loading

0 comments on commit 48c1028

Please sign in to comment.