Skip to content

Commit

Permalink
Collect and expose compile-only dependencies through ApplicationModel
Browse files Browse the repository at this point in the history
with DependencyFlag.COMPILE_ONLY flag set (Maven provided scope)
  • Loading branch information
aloubyansky committed Dec 14, 2023
1 parent 08bff7a commit d058bec
Show file tree
Hide file tree
Showing 7 changed files with 448 additions and 158 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
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;
Expand Down Expand Up @@ -35,25 +37,29 @@ protected TsArtifact composeApplication() {
addToExpectedLib(extA.getRuntime());
extA.getRuntime()
.addDependency(extADep)
.addDependency(new TsDependency(extAProvidedDep, "provided"));
.addDependency(new TsDependency(extAProvidedDep, JavaScopes.PROVIDED));
extA.getDeployment()
.addDependency(extADeploymentDep)
.addDependency(new TsDependency(extAOptionalDeploymentDep, "provided"));
.addDependency(new TsDependency(extAOptionalDeploymentDep, JavaScopes.PROVIDED));

final TsQuarkusExt extB = new TsQuarkusExt("ext-b");
this.install(extB);

final TsArtifact directProvidedDep = TsArtifact.jar("direct-provided-dep");

final TsArtifact depC2 = TsArtifact.jar("dep-c", "2");
// make sure provided dependencies don't override compile/runtime dependencies
directProvidedDep.addDependency(depC2);

final TsArtifact transitiveProvidedDep = TsArtifact.jar("transitive-provided-dep");
directProvidedDep.addDependency(transitiveProvidedDep);

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

@Override
Expand All @@ -64,5 +70,36 @@ protected void assertAppModel(ApplicationModel model) throws Exception {
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-a", "1"),
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.DIRECT,
DependencyFlags.RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-dep", "1"),
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "dep-c", "1"),
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP));
assertEquals(expected, getDependenciesWithFlag(model, DependencyFlags.RUNTIME_CP));

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", "direct-provided-dep", "1"),
JavaScopes.PROVIDED,
DependencyFlags.DIRECT,
DependencyFlags.COMPILE_ONLY));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "transitive-provided-dep", "1"),
JavaScopes.PROVIDED,
DependencyFlags.COMPILE_ONLY));
assertEquals(expected, getDependenciesWithFlag(model, DependencyFlags.COMPILE_ONLY));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
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 depC1 = TsArtifact.jar("dep-c");
//addToExpectedLib(depC1);
extADep.addDependency(depC1);

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(extADep)
.addDependency(new TsDependency(extAProvidedDep, JavaScopes.PROVIDED));
extA.getDeployment()
.addDependency(extADeploymentDep)
.addDependency(new TsDependency(extAOptionalDeploymentDep, JavaScopes.PROVIDED));

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

final TsArtifact directProvidedDep = TsArtifact.jar("direct-provided-dep");
addToExpectedLib(directProvidedDep);

final TsArtifact depC2 = TsArtifact.jar("dep-c", "2");
// here provided dependencies will override compile/runtime ones during version convergence
addToExpectedLib(depC2);
directProvidedDep.addDependency(depC2);

final TsArtifact transitiveProvidedDep = TsArtifact.jar("transitive-provided-dep");
addToExpectedLib(transitiveProvidedDep);
directProvidedDep.addDependency(transitiveProvidedDep);

return TsArtifact.jar("app")
.addManagedDependency(platformDescriptor())
.addManagedDependency(platformProperties())
.addDependency(extA)
.addDependency(extB, JavaScopes.PROVIDED)
.addDependency(new TsDependency(directProvidedDep, JavaScopes.PROVIDED));
}

@Override
protected void assertAppModel(ApplicationModel model) throws Exception {
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));

expected = new HashSet<>();
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a", "1"),
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.DIRECT,
DependencyFlags.RUNTIME_EXTENSION_ARTIFACT,
DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "ext-a-dep", "1"),
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "dep-c", "2"),
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP));
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.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.COMPILE_ONLY));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "direct-provided-dep", "1"),
JavaScopes.PROVIDED,
DependencyFlags.DIRECT,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.COMPILE_ONLY));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "transitive-provided-dep", "1"),
JavaScopes.PROVIDED,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.COMPILE_ONLY));
assertEquals(expected, getDependenciesWithFlag(model, DependencyFlags.RUNTIME_CP));

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.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.COMPILE_ONLY));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "direct-provided-dep", "1"),
JavaScopes.PROVIDED,
DependencyFlags.DIRECT,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.COMPILE_ONLY));
expected.add(new ArtifactDependency(ArtifactCoords.jar("io.quarkus.bootstrap.test", "transitive-provided-dep", "1"),
JavaScopes.PROVIDED,
DependencyFlags.RUNTIME_CP,
DependencyFlags.DEPLOYMENT_CP,
DependencyFlags.COMPILE_ONLY));
assertEquals(expected, getDependenciesWithFlag(model, DependencyFlags.COMPILE_ONLY));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,23 @@ public interface DependencyFlags {
// once the processing of the whole tree has completed.
int VISITED = 0b00100000000000;

/**
* 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
* ({@code 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.
*/
int COMPILE_ONLY = 0b01000000000000;
/* @formatter:on */

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package io.quarkus.bootstrap.resolver;

import static io.quarkus.bootstrap.util.DependencyUtils.getKey;
import static io.quarkus.bootstrap.util.DependencyUtils.toAppArtifact;

import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
Expand All @@ -12,7 +15,6 @@

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.graph.DependencyVisitor;
Expand Down Expand Up @@ -134,7 +136,8 @@ public boolean visitEnter(DependencyNode node) {
public boolean visitLeave(DependencyNode node) {
final Dependency dep = node.getDependency();
if (dep != null) {
result.add(toAppArtifact(dep.getArtifact()).setScope(dep.getScope()).setOptional(dep.isOptional()).build());
result.add(toAppArtifact(dep.getArtifact(), null).setScope(dep.getScope()).setOptional(dep.isOptional())
.build());
}
return true;
}
Expand Down Expand Up @@ -231,9 +234,8 @@ public ApplicationModel resolveModel(WorkspaceModule module)
final List<Dependency> constraints = managedMap.isEmpty() ? List.of() : new ArrayList<>(managedMap.values());

return buildAppModel(mainDep,
MavenArtifactResolver.newCollectRequest(mainArtifact, directDeps, constraints, List.of(),
mvn.getRepositories()),
Set.of(), constraints, List.of());
mainArtifact, directDeps, mvn.getRepositories(),
Set.of(), constraints);
}

private ApplicationModel doResolveModel(ArtifactCoords coords,
Expand All @@ -244,7 +246,7 @@ private ApplicationModel doResolveModel(ArtifactCoords coords,
if (coords == null) {
throw new IllegalArgumentException("Application artifact is null");
}
final Artifact mvnArtifact = toAetherArtifact(coords);
Artifact mvnArtifact = toAetherArtifact(coords);

List<Dependency> managedDeps = List.of();
List<RemoteRepository> managedRepos = List.of();
Expand All @@ -256,11 +258,12 @@ private ApplicationModel doResolveModel(ArtifactCoords coords,

List<RemoteRepository> aggregatedRepos = mvn.aggregateRepositories(managedRepos, mvn.getRepositories());
final ResolvedDependency appArtifact = resolve(coords, mvnArtifact, aggregatedRepos);
final ArtifactDescriptorResult appArtifactDescr = resolveDescriptor(toAetherArtifact(appArtifact), aggregatedRepos);
mvnArtifact = toAetherArtifact(appArtifact);
final ArtifactDescriptorResult appArtifactDescr = resolveDescriptor(mvnArtifact, aggregatedRepos);

Map<ArtifactKey, String> managedVersions = Map.of();
if (!managedDeps.isEmpty()) {
final List<Dependency> mergedManagedDeps = new ArrayList<Dependency>(
final List<Dependency> mergedManagedDeps = new ArrayList<>(
managedDeps.size() + appArtifactDescr.getManagedDependencies().size());
managedVersions = new HashMap<>(managedDeps.size());
for (Dependency dep : managedDeps) {
Expand All @@ -278,14 +281,13 @@ private ApplicationModel doResolveModel(ArtifactCoords coords,
managedDeps = appArtifactDescr.getManagedDependencies();
}

directMvnDeps = DependencyUtils.mergeDeps(directMvnDeps, appArtifactDescr.getDependencies(), managedVersions,
getExcludedScopes());
directMvnDeps = DependencyUtils.mergeDeps(directMvnDeps, appArtifactDescr.getDependencies(), managedVersions, Set.of());
aggregatedRepos = mvn.aggregateRepositories(aggregatedRepos,
mvn.newResolutionRepositories(appArtifactDescr.getRepositories()));

return buildAppModel(appArtifact,
MavenArtifactResolver.newCollectRequest(mvnArtifact, directMvnDeps, managedDeps, List.of(), aggregatedRepos),
reloadableModules, managedDeps, aggregatedRepos);
mvnArtifact, directMvnDeps, aggregatedRepos,
reloadableModules, managedDeps);
}

private Set<String> getExcludedScopes() {
Expand All @@ -298,9 +300,10 @@ private Set<String> getExcludedScopes() {
return Set.of(JavaScopes.PROVIDED, JavaScopes.TEST);
}

private ApplicationModel buildAppModel(ResolvedDependency appArtifact, CollectRequest collectRtDepsRequest,
Set<ArtifactKey> reloadableModules, List<Dependency> managedDeps, List<RemoteRepository> repos)
throws AppModelResolverException, BootstrapMavenException {
private ApplicationModel buildAppModel(ResolvedDependency appArtifact,
Artifact artifact, List<Dependency> directDeps, List<RemoteRepository> repos,
Set<ArtifactKey> reloadableModules, List<Dependency> managedDeps)
throws AppModelResolverException {

final ApplicationModelBuilder appBuilder = new ApplicationModelBuilder().setAppArtifact(appArtifact);
if (appArtifact.getWorkspaceModule() != null) {
Expand All @@ -310,13 +313,26 @@ private ApplicationModel buildAppModel(ResolvedDependency appArtifact, CollectRe
appBuilder.addReloadableWorkspaceModules(reloadableModules);
}

var filteredProvidedDeps = new ArrayList<Dependency>(0);
var excludedScopes = getExcludedScopes();
if (!excludedScopes.isEmpty()) {
var filtered = new ArrayList<Dependency>(directDeps.size());
for (var d : directDeps) {
if (!excludedScopes.contains(d.getScope())) {
filtered.add(d);
} else if (JavaScopes.PROVIDED.equals(d.getScope())) {
filteredProvidedDeps.add(d);
}
}
directDeps = filtered;
}
var collectRtDepsRequest = MavenArtifactResolver.newCollectRequest(artifact, directDeps, managedDeps, List.of(), repos);
try {
ApplicationDependencyTreeResolver.newInstance()
.setArtifactResolver(mvn)
.setManagedDependencies(managedDeps)
.setMainRepositories(repos)
.setApplicationModelBuilder(appBuilder)
.setCollectReloadableModules(collectReloadableDeps && reloadableModules.isEmpty())
.setCollectCompileOnly(filteredProvidedDeps)
.setBuildTreeConsumer(buildTreeConsumer)
.resolve(collectRtDepsRequest);
} catch (BootstrapDependencyProcessingException e) {
Expand Down Expand Up @@ -482,18 +498,6 @@ private static Artifact toAetherArtifact(ArtifactCoords artifact) {
artifact.getClassifier(), artifact.getType(), artifact.getVersion());
}

private ResolvedDependencyBuilder toAppArtifact(Artifact artifact) {
return toAppArtifact(artifact, null);
}

private ResolvedDependencyBuilder toAppArtifact(Artifact artifact, WorkspaceModule module) {
return ApplicationDependencyTreeResolver.toAppArtifact(artifact, module);
}

private static ArtifactKey getKey(Artifact artifact) {
return DependencyUtils.getKey(artifact);
}

private static List<Dependency> toAetherDeps(Collection<io.quarkus.maven.dependency.Dependency> directDeps) {
if (directDeps.isEmpty()) {
return List.of();
Expand Down
Loading

0 comments on commit d058bec

Please sign in to comment.