diff --git a/core/deployment/src/test/java/io/quarkus/deployment/conditionaldeps/DependencyConditionMatchesConditionalDependencyTest.java b/core/deployment/src/test/java/io/quarkus/deployment/conditionaldeps/DependencyConditionMatchesConditionalDependencyTest.java index 1f993a28bcc42..04435597762f5 100644 --- a/core/deployment/src/test/java/io/quarkus/deployment/conditionaldeps/DependencyConditionMatchesConditionalDependencyTest.java +++ b/core/deployment/src/test/java/io/quarkus/deployment/conditionaldeps/DependencyConditionMatchesConditionalDependencyTest.java @@ -1,8 +1,15 @@ package io.quarkus.deployment.conditionaldeps; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.HashMap; + +import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.bootstrap.resolver.TsArtifact; import io.quarkus.bootstrap.resolver.TsQuarkusExt; +import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; import io.quarkus.deployment.runnerjar.BootstrapFromOriginalJarTestBase; +import io.quarkus.maven.dependency.ResolvedDependency; public class DependencyConditionMatchesConditionalDependencyTest extends BootstrapFromOriginalJarTestBase { @@ -38,6 +45,37 @@ protected TsArtifact composeApplication() { .addDependency(extA); } + @Override + protected void assertAppModel(ApplicationModel appModel) { + var extensions = new HashMap(); + for (var d : appModel.getDependencies()) { + extensions.put(d.getArtifactId(), d); + } + assertThat(extensions).hasSize(8); + + if (IncubatingApplicationModelResolver.isIncubatingEnabled(null)) { + var extA = extensions.get("ext-a"); + assertThat(extA.getDependencies()).isEmpty(); + var extADeployment = extensions.get("ext-a-deployment"); + assertThat(extADeployment.getDependencies()).containsExactly(extA); + + var extB = extensions.get("ext-b"); + assertThat(extB.getDependencies()).isEmpty(); + var extBDeployment = extensions.get("ext-b-deployment"); + assertThat(extBDeployment.getDependencies()).containsExactly(extB); + + var extD = extensions.get("ext-d"); + assertThat(extD.getDependencies()).containsExactly(extB); + var extDDeployment = extensions.get("ext-d-deployment"); + assertThat(extDDeployment.getDependencies()).containsExactlyInAnyOrder(extD, extBDeployment); + + var extC = extensions.get("ext-c"); + assertThat(extC.getDependencies()).containsExactly(extD); + var extCDeployment = extensions.get("ext-c-deployment"); + assertThat(extCDeployment.getDependencies()).containsExactlyInAnyOrder(extC, extDDeployment); + } + } + @Override protected String[] expectedExtensionDependencies() { return new String[] { diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/GradleApplicationModelBuilder.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/GradleApplicationModelBuilder.java index 1b7a09dc783c8..06b61927c99fd 100644 --- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/GradleApplicationModelBuilder.java +++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/GradleApplicationModelBuilder.java @@ -114,7 +114,7 @@ public Object buildAll(String modelName, ModelParameter parameter, Project proje } } - final ResolvedDependency appArtifact = getProjectArtifact(project, workspaceDiscovery); + final ResolvedDependencyBuilder appArtifact = getProjectArtifact(project, workspaceDiscovery); final ApplicationModelBuilder modelBuilder = new ApplicationModelBuilder() .setAppArtifact(appArtifact) .addReloadableWorkspaceModule(appArtifact.getKey()) @@ -159,7 +159,7 @@ private static void addCompileOnly(Project project, ApplicationDeploymentClasspa } } - public static ResolvedDependency getProjectArtifact(Project project, boolean workspaceDiscovery) { + public static ResolvedDependencyBuilder getProjectArtifact(Project project, boolean workspaceDiscovery) { final ResolvedDependencyBuilder appArtifact = ResolvedDependencyBuilder.newInstance() .setGroupId(project.getGroup().toString()) .setArtifactId(project.getName()) @@ -206,7 +206,7 @@ public static ResolvedDependency getProjectArtifact(Project project, boolean wor collectDestinationDirs(mainModule.getMainSources().getSourceDirs(), paths); collectDestinationDirs(mainModule.getMainSources().getResourceDirs(), paths); - return appArtifact.setWorkspaceModule(mainModule).setResolvedPaths(paths.build()).build(); + return appArtifact.setWorkspaceModule(mainModule).setResolvedPaths(paths.build()); } private static void collectDestinationDirs(Collection sources, final PathList.Builder paths) { diff --git a/devtools/maven/src/main/java/io/quarkus/maven/DependencyTreeMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/DependencyTreeMojo.java index 6e027daff769d..38a5e0e5aa588 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/DependencyTreeMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/DependencyTreeMojo.java @@ -22,9 +22,9 @@ import org.eclipse.aether.repository.RemoteRepository; import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; -import io.quarkus.bootstrap.resolver.maven.ApplicationDependencyModelResolver; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; import io.quarkus.bootstrap.resolver.maven.DependencyLoggingConfig; +import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.maven.components.QuarkusWorkspaceProvider; import io.quarkus.maven.dependency.ArtifactCoords; @@ -148,7 +148,7 @@ private void logTree(final Consumer log) throws MojoExecutionException { } } modelResolver.setIncubatingModelResolver( - ApplicationDependencyModelResolver.isIncubatingEnabled(project.getProperties())); + IncubatingApplicationModelResolver.isIncubatingEnabled(project.getProperties())); modelResolver.setDepLogConfig(DependencyLoggingConfig.builder() .setMessageConsumer(log) .setVerbose(verbose) diff --git a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java index 05bd7d3b81622..696742ca1e9da 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/DevMojo.java @@ -96,9 +96,9 @@ import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.bootstrap.model.PathsCollection; import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; -import io.quarkus.bootstrap.resolver.maven.ApplicationDependencyModelResolver; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContextConfig; +import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.bootstrap.util.BootstrapUtils; import io.quarkus.bootstrap.workspace.ArtifactSources; @@ -1361,7 +1361,7 @@ private QuarkusDevModeLauncher newLauncher(Boolean debugPortOk, String bootstrap .setDevMode(true) .setTest(LaunchMode.TEST.equals(getLaunchModeClasspath())) .setCollectReloadableDependencies(!noDeps) - .setIncubatingModelResolver(ApplicationDependencyModelResolver.isIncubatingEnabled(project.getProperties())) + .setIncubatingModelResolver(IncubatingApplicationModelResolver.isIncubatingEnabled(project.getProperties())) .resolveModel(mvnCtx.getCurrentProject().getAppArtifact()); } diff --git a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java index d83cb4fa9f46b..1177a4b2b933b 100644 --- a/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java +++ b/devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java @@ -37,16 +37,16 @@ import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.bootstrap.resolver.AppModelResolverException; import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; -import io.quarkus.bootstrap.resolver.maven.ApplicationDependencyModelResolver; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; +import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.maven.components.ManifestSection; import io.quarkus.maven.components.QuarkusWorkspaceProvider; import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.maven.dependency.ArtifactKey; import io.quarkus.maven.dependency.Dependency; -import io.quarkus.maven.dependency.ResolvedArtifactDependency; +import io.quarkus.maven.dependency.ResolvedDependencyBuilder; import io.quarkus.runtime.LaunchMode; import io.smallrye.common.expression.Expression; @@ -208,12 +208,12 @@ private CuratedApplication doBootstrap(QuarkusBootstrapMojo mojo, LaunchMode mod final BootstrapAppModelResolver modelResolver = new BootstrapAppModelResolver(artifactResolver(mojo, mode)) .setIncubatingModelResolver( - ApplicationDependencyModelResolver.isIncubatingEnabled(mojo.mavenProject().getProperties())) + IncubatingApplicationModelResolver.isIncubatingEnabled(mojo.mavenProject().getProperties())) .setDevMode(mode == LaunchMode.DEVELOPMENT) .setTest(mode == LaunchMode.TEST) .setCollectReloadableDependencies(mode == LaunchMode.DEVELOPMENT || mode == LaunchMode.TEST); - final ArtifactCoords appArtifact = appArtifact(mojo); + final ResolvedDependencyBuilder appArtifact = getApplicationArtifactBuilder(mojo); Set reloadableModules = Set.of(); if (mode == LaunchMode.NORMAL) { // collect reloadable artifacts for remote-dev @@ -367,7 +367,7 @@ protected ArtifactCoords managingProject(QuarkusBootstrapMojo mojo) { artifact.getVersion()); } - private ArtifactCoords appArtifact(QuarkusBootstrapMojo mojo) + private ResolvedDependencyBuilder getApplicationArtifactBuilder(QuarkusBootstrapMojo mojo) throws MojoExecutionException { String appArtifactCoords = mojo.appArtifactCoords(); if (appArtifactCoords == null) { @@ -388,9 +388,13 @@ private ArtifactCoords appArtifact(QuarkusBootstrapMojo mojo) } } } - return new ResolvedArtifactDependency(projectArtifact.getGroupId(), projectArtifact.getArtifactId(), - projectArtifact.getClassifier(), projectArtifact.getArtifactHandler().getExtension(), - projectArtifact.getVersion(), projectFile.toPath()); + return ResolvedDependencyBuilder.newInstance() + .setGroupId(projectArtifact.getGroupId()) + .setArtifactId(projectArtifact.getArtifactId()) + .setClassifier(projectArtifact.getClassifier()) + .setType(projectArtifact.getArtifactHandler().getExtension()) + .setVersion(projectArtifact.getVersion()) + .setResolvedPath(projectFile.toPath()); } final String[] coordsArr = appArtifactCoords.split(":"); @@ -429,7 +433,12 @@ private ArtifactCoords appArtifact(QuarkusBootstrapMojo mojo) } } - return ArtifactCoords.of(groupId, artifactId, classifier, type, version); + return ResolvedDependencyBuilder.newInstance() + .setGroupId(groupId) + .setArtifactId(artifactId) + .setClassifier(classifier) + .setType(type) + .setVersion(version); } @Override diff --git a/devtools/maven/src/test/resources/app-with-conditional-deps-1.jar.prod b/devtools/maven/src/test/resources/app-with-conditional-deps-1.jar.prod index 5780caf8fafca..3a23ee5ac0c15 100644 --- a/devtools/maven/src/test/resources/app-with-conditional-deps-1.jar.prod +++ b/devtools/maven/src/test/resources/app-with-conditional-deps-1.jar.prod @@ -1,15 +1,15 @@ [info] Quarkus application PROD mode build dependency tree: [info] io.quarkus.bootstrap.test:app-with-conditional-deps:pom:1 -[info] ├─ io.quarkus.bootstrap.test:quarkus-tomato-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:quarkus-tomato:jar:1 (compile) -[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:jar:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:quarkus-mozzarella-deployment:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:quarkus-mozzarella:jar:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:quarkus-basil-deployment:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:quarkus-basil:jar:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:quarkus-salad-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:quarkus-salad:jar:1 (compile) -[info] │ │ └─ io.quarkus.bootstrap.test:quarkus-caprese:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:quarkus-caprese-deployment:jar:1 (compile) -[info] └─ io.quarkus.bootstrap.test:quarkus-oil:jar:1 (compile) \ No newline at end of file +[info] ├─ io.quarkus.bootstrap.test:quarkus-tomato-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:quarkus-tomato:1 (compile) +[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:quarkus-mozzarella-deployment:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:quarkus-mozzarella:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:quarkus-basil-deployment:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:quarkus-basil:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:quarkus-salad-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:quarkus-salad:1 (compile) +[info] │ │ └─ io.quarkus.bootstrap.test:quarkus-caprese:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:quarkus-caprese-deployment:1 (compile) +[info] └─ io.quarkus.bootstrap.test:quarkus-oil:1 (compile) \ No newline at end of file diff --git a/devtools/maven/src/test/resources/app-with-conditional-graph-1.jar.prod b/devtools/maven/src/test/resources/app-with-conditional-graph-1.jar.prod index 77508e6965d59..45cee715ba446 100644 --- a/devtools/maven/src/test/resources/app-with-conditional-graph-1.jar.prod +++ b/devtools/maven/src/test/resources/app-with-conditional-graph-1.jar.prod @@ -1,30 +1,30 @@ [info] Quarkus application PROD mode build dependency tree: [info] io.quarkus.bootstrap.test:app-with-conditional-graph:pom:1 -[info] ├─ io.quarkus.bootstrap.test:quarkus-basil::jar:1 (compile) [+] -[info] ├─ io.quarkus.bootstrap.test:quarkus-mozzarella::jar:1 (compile) [+] -[info] ├─ io.quarkus.bootstrap.test:quarkus-salad::jar:1 (compile) [+] -[info] ├─ io.quarkus.bootstrap.test:quarkus-tomato::jar:1 (compile) [+] -[info] ├─ io.quarkus.bootstrap.test:quarkus-tomato-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:quarkus-tomato:jar:1 (compile) -[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-core-ext::jar:1 (compile) [+] -[info] ├─ io.quarkus.bootstrap.test:quarkus-mozzarella-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:test-core-ext-deployment::jar:1 (compile) [+] -[info] │ └─ io.quarkus.bootstrap.test:quarkus-mozzarella:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-core-ext::jar:1 (compile) [+] -[info] ├─ io.quarkus.bootstrap.test:quarkus-basil-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:test-core-ext-deployment::jar:1 (compile) [+] -[info] │ └─ io.quarkus.bootstrap.test:quarkus-basil:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-core-ext::jar:1 (compile) [+] -[info] ├─ io.quarkus.bootstrap.test:quarkus-salad-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:test-core-ext-deployment::jar:1 (compile) [+] -[info] │ ├─ io.quarkus.bootstrap.test:quarkus-salad:jar:1 (compile) -[info] │ │ ├─ io.quarkus.bootstrap.test:test-core-ext::jar:1 (compile) [+] -[info] │ │ └─ io.quarkus.bootstrap.test:quarkus-caprese:jar:1 (compile) -[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext::jar:1 (compile) [+] -[info] │ └─ io.quarkus.bootstrap.test:quarkus-caprese-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:quarkus-caprese::jar:1 (compile) [+] -[info] │ ├─ io.quarkus.bootstrap.test:quarkus-oil::jar:1 (compile) [+] -[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment::jar:1 (compile) [+] -[info] └─ io.quarkus.bootstrap.test:quarkus-oil:jar:1 (compile) \ No newline at end of file +[info] ├─ io.quarkus.bootstrap.test:quarkus-basil:1 (compile) [+] +[info] ├─ io.quarkus.bootstrap.test:quarkus-mozzarella:1 (compile) [+] +[info] ├─ io.quarkus.bootstrap.test:quarkus-salad:1 (compile) [+] +[info] ├─ io.quarkus.bootstrap.test:quarkus-tomato:1 (compile) [+] +[info] ├─ io.quarkus.bootstrap.test:quarkus-tomato-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:quarkus-tomato:1 (compile) +[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-core-ext:1 (compile) [+] +[info] ├─ io.quarkus.bootstrap.test:quarkus-mozzarella-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:test-core-ext-deployment:1 (compile) [+] +[info] │ └─ io.quarkus.bootstrap.test:quarkus-mozzarella:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-core-ext:1 (compile) [+] +[info] ├─ io.quarkus.bootstrap.test:quarkus-basil-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:test-core-ext-deployment:1 (compile) [+] +[info] │ └─ io.quarkus.bootstrap.test:quarkus-basil:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-core-ext:1 (compile) [+] +[info] ├─ io.quarkus.bootstrap.test:quarkus-salad-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:test-core-ext-deployment:1 (compile) [+] +[info] │ ├─ io.quarkus.bootstrap.test:quarkus-salad:1 (compile) +[info] │ │ ├─ io.quarkus.bootstrap.test:test-core-ext:1 (compile) [+] +[info] │ │ └─ io.quarkus.bootstrap.test:quarkus-caprese:1 (compile) +[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:1 (compile) [+] +[info] │ └─ io.quarkus.bootstrap.test:quarkus-caprese-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:quarkus-caprese:1 (compile) [+] +[info] │ ├─ io.quarkus.bootstrap.test:quarkus-oil:1 (compile) [+] +[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:1 (compile) [+] +[info] └─ io.quarkus.bootstrap.test:quarkus-oil:1 (compile) \ No newline at end of file diff --git a/devtools/maven/src/test/resources/test-app-1.jar.dev b/devtools/maven/src/test/resources/test-app-1.jar.dev index d43162a11db94..7c23ed5541ddd 100644 --- a/devtools/maven/src/test/resources/test-app-1.jar.dev +++ b/devtools/maven/src/test/resources/test-app-1.jar.dev @@ -1,14 +1,14 @@ [info] Quarkus application DEV mode build dependency tree: [info] io.quarkus.bootstrap.test:test-app:pom:1 -[info] ├─ io.quarkus.bootstrap.test:artifact-with-classifier:jar:classifier:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:test-ext2-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:test-ext2:jar:1 (compile) -[info] │ │ └─ io.quarkus.bootstrap.test:test-ext1:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-ext1-deployment:jar:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:optional:jar:1 (compile optional) -[info] ├─ io.quarkus.bootstrap.test:test-ext3-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:test-ext3:jar:1 (compile) -[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:jar:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:provided:jar:1 (provided) -[info] └─ io.quarkus.bootstrap.test:runtime:jar:1 (runtime) +[info] ├─ io.quarkus.bootstrap.test:artifact-with-classifier:classifier:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:test-ext2-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:test-ext2:1 (compile) +[info] │ │ └─ io.quarkus.bootstrap.test:test-ext1:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-ext1-deployment:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:optional:1 (compile optional) +[info] ├─ io.quarkus.bootstrap.test:test-ext3-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:test-ext3:1 (compile) +[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:provided:1 (provided) +[info] └─ io.quarkus.bootstrap.test:runtime:1 (runtime) diff --git a/devtools/maven/src/test/resources/test-app-1.jar.prod b/devtools/maven/src/test/resources/test-app-1.jar.prod index bf7d0a9836aae..7a252ceaa05da 100644 --- a/devtools/maven/src/test/resources/test-app-1.jar.prod +++ b/devtools/maven/src/test/resources/test-app-1.jar.prod @@ -1,13 +1,13 @@ [info] Quarkus application PROD mode build dependency tree: [info] io.quarkus.bootstrap.test:test-app:pom:1 -[info] ├─ io.quarkus.bootstrap.test:artifact-with-classifier:jar:classifier:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:test-ext2-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:test-ext2:jar:1 (compile) -[info] │ │ └─ io.quarkus.bootstrap.test:test-ext1:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-ext1-deployment:jar:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:optional:jar:1 (compile optional) -[info] ├─ io.quarkus.bootstrap.test:test-ext3-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:test-ext3:jar:1 (compile) -[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:jar:1 (compile) -[info] └─ io.quarkus.bootstrap.test:runtime:jar:1 (runtime) +[info] ├─ io.quarkus.bootstrap.test:artifact-with-classifier:classifier:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:test-ext2-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:test-ext2:1 (compile) +[info] │ │ └─ io.quarkus.bootstrap.test:test-ext1:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-ext1-deployment:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:optional:1 (compile optional) +[info] ├─ io.quarkus.bootstrap.test:test-ext3-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:test-ext3:1 (compile) +[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:1 (compile) +[info] └─ io.quarkus.bootstrap.test:runtime:1 (runtime) diff --git a/devtools/maven/src/test/resources/test-app-1.jar.test b/devtools/maven/src/test/resources/test-app-1.jar.test index 832397770b902..411f5600b0673 100644 --- a/devtools/maven/src/test/resources/test-app-1.jar.test +++ b/devtools/maven/src/test/resources/test-app-1.jar.test @@ -1,15 +1,15 @@ [info] Quarkus application TEST mode build dependency tree: [info] io.quarkus.bootstrap.test:test-app:pom:1 -[info] ├─ io.quarkus.bootstrap.test:artifact-with-classifier:jar:classifier:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:test-ext2-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:test-ext2:jar:1 (compile) -[info] │ │ └─ io.quarkus.bootstrap.test:test-ext1:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-ext1-deployment:jar:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:optional:jar:1 (compile optional) -[info] ├─ io.quarkus.bootstrap.test:test-ext3-deployment:jar:1 (compile) -[info] │ ├─ io.quarkus.bootstrap.test:test-ext3:jar:1 (compile) -[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:jar:1 (compile) -[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:jar:1 (compile) -[info] ├─ io.quarkus.bootstrap.test:provided:jar:1 (provided) -[info] ├─ io.quarkus.bootstrap.test:runtime:jar:1 (runtime) -[info] └─ io.quarkus.bootstrap.test:test:jar:1 (test) +[info] ├─ io.quarkus.bootstrap.test:artifact-with-classifier:classifier:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:test-ext2-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:test-ext2:1 (compile) +[info] │ │ └─ io.quarkus.bootstrap.test:test-ext1:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-ext1-deployment:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:optional:1 (compile optional) +[info] ├─ io.quarkus.bootstrap.test:test-ext3-deployment:1 (compile) +[info] │ ├─ io.quarkus.bootstrap.test:test-ext3:1 (compile) +[info] │ │ └─ io.quarkus.bootstrap.test:test-core-ext:1 (compile) +[info] │ └─ io.quarkus.bootstrap.test:test-core-ext-deployment:1 (compile) +[info] ├─ io.quarkus.bootstrap.test:provided:1 (provided) +[info] ├─ io.quarkus.bootstrap.test:runtime:1 (runtime) +[info] └─ io.quarkus.bootstrap.test:test:1 (test) diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifact.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifact.java index 23d5751479c88..c52eacf3cdf7f 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifact.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppArtifact.java @@ -2,8 +2,11 @@ import java.io.Serializable; import java.nio.file.Path; +import java.util.Collection; +import java.util.List; import io.quarkus.bootstrap.workspace.WorkspaceModule; +import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.maven.dependency.ResolvedDependency; import io.quarkus.paths.PathCollection; import io.quarkus.paths.PathList; @@ -121,4 +124,9 @@ public String getScope() { public int getFlags() { return flags; } + + @Override + public Collection getDependencies() { + return List.of(); + } } diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppDependency.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppDependency.java index 4c74856d5f9b3..803b09b1df05e 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppDependency.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/AppDependency.java @@ -1,8 +1,11 @@ package io.quarkus.bootstrap.model; import java.io.Serializable; +import java.util.Collection; +import java.util.List; import java.util.Objects; +import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.maven.dependency.ArtifactKey; import io.quarkus.maven.dependency.DependencyFlags; import io.quarkus.maven.dependency.ResolvedDependency; @@ -126,4 +129,9 @@ public ArtifactKey getKey() { public PathCollection getResolvedPaths() { return artifact.getResolvedPaths(); } + + @Override + public Collection getDependencies() { + return List.of(); + } } diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModelBuilder.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModelBuilder.java index 95784e1755be8..c4e0331313581 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModelBuilder.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/ApplicationModelBuilder.java @@ -35,7 +35,7 @@ public class ApplicationModelBuilder { private static final Logger log = Logger.getLogger(ApplicationModelBuilder.class); - ResolvedDependency appArtifact; + ResolvedDependencyBuilder appArtifact; final Map dependencies = new LinkedHashMap<>(); final Collection parentFirstArtifacts = new ConcurrentLinkedDeque<>(); @@ -56,11 +56,15 @@ public ApplicationModelBuilder() { .build()); } - public ApplicationModelBuilder setAppArtifact(ResolvedDependency appArtifact) { + public ApplicationModelBuilder setAppArtifact(ResolvedDependencyBuilder appArtifact) { this.appArtifact = appArtifact; return this; } + public ResolvedDependencyBuilder getApplicationArtifact() { + return appArtifact; + } + public ApplicationModelBuilder setPlatformImports(PlatformImports platformImports) { this.platformImports = platformImports; return this; @@ -77,10 +81,14 @@ public ApplicationModelBuilder addDependency(ResolvedDependencyBuilder dep) { } public ApplicationModelBuilder addDependencies(Collection deps) { - deps.forEach(d -> addDependency(d)); + deps.forEach(this::addDependency); return this; } + public boolean hasDependency(ArtifactKey key) { + return dependencies.containsKey(key); + } + public ResolvedDependencyBuilder getDependency(ArtifactKey key) { return dependencies.get(key); } diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/DefaultApplicationModel.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/DefaultApplicationModel.java index b03ebc134dbcb..1796b1ceff51a 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/DefaultApplicationModel.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/DefaultApplicationModel.java @@ -26,7 +26,7 @@ public class DefaultApplicationModel implements ApplicationModel, Serializable { private final Map> excludedResources; public DefaultApplicationModel(ApplicationModelBuilder builder) { - this.appArtifact = builder.appArtifact; + this.appArtifact = builder.appArtifact.build(); this.dependencies = builder.buildDependencies(); this.platformImports = builder.platformImports; this.capabilityContracts = List.copyOf(builder.extensionCapabilities); diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/MutableJarApplicationModel.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/MutableJarApplicationModel.java index b705dac6dde86..ebceb7d97089f 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/MutableJarApplicationModel.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/model/MutableJarApplicationModel.java @@ -59,7 +59,7 @@ public String getUserProvidersDirectory() { public ApplicationModel getAppModel(Path root) { final ApplicationModelBuilder model = new ApplicationModelBuilder(); - model.setAppArtifact(appArtifact.getDep(root).build()); + model.setAppArtifact(appArtifact.getDep(root)); for (SerializedDep i : dependencies) { model.addDependency(i.getDep(root)); } diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/Dependency.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/Dependency.java index 8fe5601ca64dc..2a95f37474117 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/Dependency.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/Dependency.java @@ -8,15 +8,15 @@ public interface Dependency extends ArtifactCoords { String SCOPE_COMPILE = "compile"; String SCOPE_IMPORT = "import"; - public static Dependency of(String groupId, String artifactId) { + static Dependency of(String groupId, String artifactId) { return new ArtifactDependency(groupId, artifactId, null, ArtifactCoords.TYPE_JAR, null); } - public static Dependency of(String groupId, String artifactId, String version) { + static Dependency of(String groupId, String artifactId, String version) { return new ArtifactDependency(groupId, artifactId, null, ArtifactCoords.TYPE_JAR, version); } - public static Dependency pomImport(String groupId, String artifactId, String version) { + static Dependency pomImport(String groupId, String artifactId, String version) { return new ArtifactDependency(groupId, artifactId, null, ArtifactCoords.TYPE_POM, version, SCOPE_IMPORT, false); } diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedArtifactDependency.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedArtifactDependency.java index e8788cd70f53b..25964852a2b78 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedArtifactDependency.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedArtifactDependency.java @@ -2,6 +2,8 @@ import java.io.Serializable; import java.nio.file.Path; +import java.util.Collection; +import java.util.List; import java.util.Objects; import io.quarkus.bootstrap.workspace.WorkspaceModule; @@ -14,7 +16,8 @@ public class ResolvedArtifactDependency extends ArtifactDependency implements Re private static final long serialVersionUID = 4038042391733012566L; private PathCollection paths; - private WorkspaceModule module; + private final WorkspaceModule module; + private final Collection deps; private volatile transient PathTree contentTree; public ResolvedArtifactDependency(ArtifactCoords coords) { @@ -34,17 +37,22 @@ public ResolvedArtifactDependency(String groupId, String artifactId, String clas PathCollection resolvedPath) { super(groupId, artifactId, classifier, type, version); this.paths = resolvedPath; + this.module = null; + this.deps = List.of(); } public ResolvedArtifactDependency(ArtifactCoords coords, PathCollection resolvedPaths) { super(coords); this.paths = resolvedPaths; + this.module = null; + this.deps = List.of(); } public ResolvedArtifactDependency(ResolvedDependencyBuilder builder) { - super(builder); + super((AbstractDependencyBuilder) builder); this.paths = builder.getResolvedPaths(); this.module = builder.getWorkspaceModule(); + this.deps = builder.getDependencies(); } @Override @@ -66,6 +74,11 @@ public PathTree getContentTree() { return contentTree == null ? contentTree = ResolvableDependency.super.getContentTree() : contentTree; } + @Override + public Collection getDependencies() { + return deps; + } + @Override public int hashCode() { final int prime = 31; diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependency.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependency.java index e22e23a961671..03701e7c46b3e 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependency.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependency.java @@ -1,6 +1,7 @@ package io.quarkus.maven.dependency; import java.nio.file.Path; +import java.util.Collection; import io.quarkus.bootstrap.workspace.ArtifactSources; import io.quarkus.bootstrap.workspace.WorkspaceModule; @@ -15,6 +16,8 @@ public interface ResolvedDependency extends Dependency { PathCollection getResolvedPaths(); + Collection getDependencies(); + default boolean isResolved() { final PathCollection paths = getResolvedPaths(); return paths != null && !paths.isEmpty(); diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependencyBuilder.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependencyBuilder.java index 551898e1f7d8f..1f6d115bcc84a 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependencyBuilder.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/maven/dependency/ResolvedDependencyBuilder.java @@ -1,12 +1,16 @@ package io.quarkus.maven.dependency; import java.nio.file.Path; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; import io.quarkus.bootstrap.workspace.WorkspaceModule; import io.quarkus.paths.PathCollection; import io.quarkus.paths.PathList; -public class ResolvedDependencyBuilder extends AbstractDependencyBuilder { +public class ResolvedDependencyBuilder extends AbstractDependencyBuilder + implements ResolvedDependency { public static ResolvedDependencyBuilder newInstance() { return new ResolvedDependencyBuilder(); @@ -15,7 +19,9 @@ public static ResolvedDependencyBuilder newInstance() { PathCollection resolvedPaths; WorkspaceModule workspaceModule; private volatile ArtifactCoords coords; + private Set deps = Set.of(); + @Override public PathCollection getResolvedPaths() { return resolvedPaths; } @@ -30,6 +36,7 @@ public ResolvedDependencyBuilder setResolvedPaths(PathCollection resolvedPaths) return this; } + @Override public WorkspaceModule getWorkspaceModule() { return workspaceModule; } @@ -46,6 +53,32 @@ public ArtifactCoords getArtifactCoords() { return coords == null ? coords = ArtifactCoords.of(groupId, artifactId, classifier, type, version) : coords; } + public ResolvedDependencyBuilder addDependency(ArtifactCoords coords) { + if (coords != null) { + if (deps.isEmpty()) { + deps = new HashSet<>(); + } + deps.add(coords); + } + return this; + } + + public ResolvedDependencyBuilder addDependencies(Collection deps) { + if (!deps.isEmpty()) { + if (this.deps.isEmpty()) { + this.deps = new HashSet<>(deps); + } else { + this.deps.addAll(deps); + } + } + return this; + } + + @Override + public Collection getDependencies() { + return deps; + } + @Override public ResolvedDependency build() { return new ResolvedArtifactDependency(this); diff --git a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java index e7b1c5a1e4c82..b89b39355fcc0 100644 --- a/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java +++ b/independent-projects/bootstrap/core/src/main/java/io/quarkus/bootstrap/BootstrapAppModelFactory.java @@ -24,6 +24,7 @@ import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContext; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenContextConfig; +import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; import io.quarkus.bootstrap.resolver.maven.workspace.LocalWorkspace; @@ -152,24 +153,34 @@ public AppModelResolver getAppModelResolver() { } else { mvn = mavenArtifactResolver; } - - return bootstrapAppModelResolver = new BootstrapAppModelResolver(mvn) - .setTest(test) - .setDevMode(devMode); + return bootstrapAppModelResolver = initAppModelResolver(mvn); } MavenArtifactResolver mvn = mavenArtifactResolver; if (mvn == null) { mvn = new MavenArtifactResolver(createBootstrapMavenContext()); } - return bootstrapAppModelResolver = new BootstrapAppModelResolver(mvn) - .setTest(test) - .setDevMode(devMode); + return bootstrapAppModelResolver = initAppModelResolver(mvn); } catch (Exception e) { throw new RuntimeException("Failed to create application model resolver for " + projectRoot, e); } } + private BootstrapAppModelResolver initAppModelResolver(MavenArtifactResolver artifactResolver) { + var appModelResolver = new BootstrapAppModelResolver(artifactResolver) + .setTest(test) + .setDevMode(devMode); + var project = artifactResolver.getMavenContext().getCurrentProject(); + if (project != null) { + appModelResolver.setIncubatingModelResolver( + IncubatingApplicationModelResolver.isIncubatingEnabled( + project.getModelBuildingResult() == null + ? project.getRawModel().getProperties() + : project.getModelBuildingResult().getEffectiveModel().getProperties())); + } + return appModelResolver; + } + private BootstrapMavenContext createBootstrapMavenContext() throws AppModelResolverException { if (mvnContext != null) { return mvnContext; diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/ResolverSetupCleanup.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/ResolverSetupCleanup.java index 5a5d2666f48e5..d8861642c2171 100644 --- a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/ResolverSetupCleanup.java +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/ResolverSetupCleanup.java @@ -18,8 +18,8 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import io.quarkus.bootstrap.resolver.maven.ApplicationDependencyModelResolver; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; +import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; import io.quarkus.bootstrap.util.IoUtils; @@ -149,7 +149,7 @@ protected boolean isBootstrapForTestMode() { protected BootstrapAppModelResolver newAppModelResolver(LocalProject currentProject) throws Exception { final BootstrapAppModelResolver appModelResolver = new BootstrapAppModelResolver(newArtifactResolver(currentProject)); - appModelResolver.setIncubatingModelResolver(ApplicationDependencyModelResolver.isIncubatingEnabled(null)); + appModelResolver.setIncubatingModelResolver(IncubatingApplicationModelResolver.isIncubatingEnabled(null)); if (isBootstrapForTestMode()) { appModelResolver.setTest(true); } diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/BootstrapAppModelResolver.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/BootstrapAppModelResolver.java index 037ad003fea3f..050846b40ae72 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/BootstrapAppModelResolver.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/BootstrapAppModelResolver.java @@ -34,10 +34,10 @@ import io.quarkus.bootstrap.BootstrapDependencyProcessingException; import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.bootstrap.model.ApplicationModelBuilder; -import io.quarkus.bootstrap.resolver.maven.ApplicationDependencyModelResolver; import io.quarkus.bootstrap.resolver.maven.ApplicationDependencyTreeResolver; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.DependencyLoggingConfig; +import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; import io.quarkus.bootstrap.util.DependencyUtils; import io.quarkus.bootstrap.workspace.ArtifactSources; @@ -127,8 +127,21 @@ public void relink(ArtifactCoords artifact, Path path) throws AppModelResolverEx } @Override - public ResolvedDependency resolve(ArtifactCoords artifact) throws AppModelResolverException { - return resolve(artifact, toAetherArtifact(artifact), mvn.getRepositories()); + public ResolvedDependency resolve(ArtifactCoords coords) throws AppModelResolverException { + final ResolvedDependency resolvedArtifact = ResolvedDependency.class.isAssignableFrom(coords.getClass()) + ? (ResolvedDependency) coords + : null; + if (resolvedArtifact != null + && (resolvedArtifact.getWorkspaceModule() != null || mvn.getProjectModuleResolver() == null)) { + return resolvedArtifact; + } + final WorkspaceModule resolvedModule = mvn.getProjectModuleResolver() == null ? null + : mvn.getProjectModuleResolver().getProjectModule(coords.getGroupId(), coords.getArtifactId(), + coords.getVersion()); + if (resolvedArtifact != null && resolvedModule == null) { + return resolvedArtifact; + } + return resolve(coords, toAetherArtifact(coords), mvn.getRepositories()).build(); } @Override @@ -215,15 +228,14 @@ public ApplicationModel resolveModel(WorkspaceModule module) final Artifact mainArtifact = new DefaultArtifact(module.getId().getGroupId(), module.getId().getArtifactId(), null, ArtifactCoords.TYPE_JAR, module.getId().getVersion()); - final ResolvedDependency mainDep = ResolvedDependencyBuilder.newInstance() + final ResolvedDependencyBuilder mainDep = ResolvedDependencyBuilder.newInstance() .setGroupId(mainArtifact.getGroupId()) .setArtifactId(mainArtifact.getArtifactId()) .setClassifier(mainArtifact.getClassifier()) .setType(mainArtifact.getExtension()) .setVersion(mainArtifact.getVersion()) .setResolvedPaths(resolvedPaths.build()) - .setWorkspaceModule(module) - .build(); + .setWorkspaceModule(module); final Map managedMap = new HashMap<>(); for (io.quarkus.maven.dependency.Dependency d : module.getDirectDependencyConstraints()) { @@ -276,7 +288,7 @@ private ApplicationModel doResolveModel(ArtifactCoords coords, } List aggregatedRepos = mvn.aggregateRepositories(managedRepos, mvn.getRepositories()); - final ResolvedDependency appArtifact = resolve(coords, mvnArtifact, aggregatedRepos); + final ResolvedDependencyBuilder appArtifact = resolve(coords, mvnArtifact, aggregatedRepos); mvnArtifact = toAetherArtifact(appArtifact); final ArtifactDescriptorResult appArtifactDescr = resolveDescriptor(mvnArtifact, aggregatedRepos); @@ -319,7 +331,7 @@ private Set getExcludedScopes() { return Set.of(JavaScopes.PROVIDED, JavaScopes.TEST); } - private ApplicationModel buildAppModel(ResolvedDependency appArtifact, + private ApplicationModel buildAppModel(ResolvedDependencyBuilder appArtifact, Artifact artifact, List directDeps, List repos, Set reloadableModules, List managedDeps) throws AppModelResolverException { @@ -353,7 +365,7 @@ private ApplicationModel buildAppModel(ResolvedDependency appArtifact, start = System.currentTimeMillis(); } if (incubatingModelResolver) { - ApplicationDependencyModelResolver.newInstance() + IncubatingApplicationModelResolver.newInstance() .setArtifactResolver(mvn) .setApplicationModelBuilder(appBuilder) .setCollectReloadableModules(collectReloadableDeps && reloadableModules.isEmpty()) @@ -382,45 +394,43 @@ private ApplicationModel buildAppModel(ResolvedDependency appArtifact, return appBuilder.build(); } - private io.quarkus.maven.dependency.ResolvedDependency resolve(ArtifactCoords appArtifact, Artifact mvnArtifact, + private io.quarkus.maven.dependency.ResolvedDependencyBuilder resolve(ArtifactCoords coords, Artifact artifact, List aggregatedRepos) throws BootstrapMavenException { - final ResolvedDependency resolvedArtifact = ResolvedDependency.class.isAssignableFrom(appArtifact.getClass()) - ? (ResolvedDependency) appArtifact - : null; - if (resolvedArtifact != null - && (resolvedArtifact.getWorkspaceModule() != null || mvn.getProjectModuleResolver() == null)) { - return resolvedArtifact; + final ResolvedDependencyBuilder depBuilder; + if (ResolvedDependencyBuilder.class.isAssignableFrom(coords.getClass())) { + depBuilder = (ResolvedDependencyBuilder) coords; + } else { + depBuilder = ResolvedDependencyBuilder.newInstance().setCoords(coords); + if (coords instanceof ResolvedDependency resolved) { + depBuilder.setResolvedPaths(resolved.getResolvedPaths()); + } } - final WorkspaceModule resolvedModule = mvn.getProjectModuleResolver() == null ? null - : mvn.getProjectModuleResolver().getProjectModule(appArtifact.getGroupId(), appArtifact.getArtifactId(), - appArtifact.getVersion()); - if (resolvedArtifact != null && resolvedModule == null) { - return resolvedArtifact; + WorkspaceModule wsModule = depBuilder.getWorkspaceModule(); + if (wsModule == null && mvn.getProjectModuleResolver() != null) { + wsModule = mvn.getProjectModuleResolver().getProjectModule(coords.getGroupId(), coords.getArtifactId(), + coords.getVersion()); + depBuilder.setWorkspaceModule(wsModule); } - PathCollection resolvedPaths = null; - if ((devmode || test) && resolvedModule != null) { - final ArtifactSources artifactSources = resolvedModule.getSources(appArtifact.getClassifier()); + PathCollection resolvedPaths = depBuilder.getResolvedPaths(); + if ((devmode || test) && wsModule != null) { + final ArtifactSources artifactSources = wsModule.getSources(coords.getClassifier()); if (artifactSources != null) { final PathList.Builder pathBuilder = PathList.builder(); collectSourceDirs(pathBuilder, artifactSources.getSourceDirs()); collectSourceDirs(pathBuilder, artifactSources.getResourceDirs()); if (!pathBuilder.isEmpty()) { resolvedPaths = pathBuilder.build(); + depBuilder.setResolvedPaths(resolvedPaths); } } } - if (resolvedPaths == null) { - if (resolvedArtifact == null || resolvedArtifact.getResolvedPaths() == null) { - resolvedPaths = PathList.of(resolve(mvnArtifact, aggregatedRepos).getArtifact().getFile().toPath()); - } else { - resolvedPaths = resolvedArtifact.getResolvedPaths(); - } + if (resolvedPaths == null || resolvedPaths.isEmpty()) { + depBuilder.setResolvedPaths(PathList.of(resolve(artifact, aggregatedRepos).getArtifact().getFile().toPath())); } - return ResolvedDependencyBuilder.newInstance().setCoords(appArtifact).setWorkspaceModule(resolvedModule) - .setResolvedPaths(resolvedPaths).build(); + return depBuilder; } private static void collectSourceDirs(final PathList.Builder pathBuilder, Collection resources) { diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BuildDependencyGraphVisitor.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BuildDependencyGraphVisitor.java index 025aa5413c781..2ca34bb6e91c0 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BuildDependencyGraphVisitor.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/BuildDependencyGraphVisitor.java @@ -15,6 +15,7 @@ import org.eclipse.aether.graph.DependencyNode; import io.quarkus.bootstrap.model.ApplicationModelBuilder; +import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.maven.dependency.DependencyFlags; public class BuildDependencyGraphVisitor { @@ -112,7 +113,15 @@ private void consume(DependencyNode node) { buf.append('\u2514').append('\u2500').append(' '); } } - buf.append(node.getArtifact()); + var a = node.getArtifact(); + buf.append(a.getGroupId()).append(":").append(a.getArtifactId()).append(":"); + if (!a.getClassifier().isEmpty()) { + buf.append(a.getClassifier()).append(":"); + } + if (!ArtifactCoords.TYPE_JAR.equals(a.getExtension())) { + buf.append(a.getExtension()).append(":"); + } + buf.append(a.getVersion()); if (!depth.isEmpty()) { buf.append(" (").append(node.getDependency().getScope()); if (node.getDependency().isOptional()) { diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyModelResolver.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java similarity index 82% rename from independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyModelResolver.java rename to independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java index 9a3b9e1855b4e..0cc742766e0c7 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyModelResolver.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java @@ -17,14 +17,13 @@ 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.Properties; -import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedDeque; +import java.util.concurrent.Phaser; import java.util.function.BiConsumer; import org.eclipse.aether.DefaultRepositorySystemSession; @@ -62,12 +61,13 @@ import io.quarkus.maven.dependency.ArtifactCoords; import io.quarkus.maven.dependency.ArtifactKey; import io.quarkus.maven.dependency.DependencyFlags; +import io.quarkus.maven.dependency.ResolvedDependency; import io.quarkus.maven.dependency.ResolvedDependencyBuilder; import io.quarkus.paths.PathTree; -public class ApplicationDependencyModelResolver { +public class IncubatingApplicationModelResolver { - private static final Logger log = Logger.getLogger(ApplicationDependencyModelResolver.class); + private static final Logger log = Logger.getLogger(IncubatingApplicationModelResolver.class); private static final String QUARKUS_RUNTIME_ARTIFACT = "quarkus.runtime"; private static final String QUARKUS_EXTENSION_DEPENDENCY = "quarkus.ext"; @@ -95,8 +95,8 @@ public static boolean isIncubatingEnabled(Properties projectProperties) { return Boolean.parseBoolean(value); } - public static ApplicationDependencyModelResolver newInstance() { - return new ApplicationDependencyModelResolver(); + public static IncubatingApplicationModelResolver newInstance() { + return new IncubatingApplicationModelResolver(); } private final ExtensionInfo EXT_INFO_NONE = new ExtensionInfo(); @@ -105,8 +105,6 @@ public static ApplicationDependencyModelResolver newInstance() { private final Map allExtensions = new ConcurrentHashMap<>(); private List conditionalDepsToProcess = new ArrayList<>(); - private final Map> artifactDeps = new HashMap<>(); - private final Collection errors = new ConcurrentLinkedDeque<>(); private MavenArtifactResolver resolver; @@ -116,22 +114,22 @@ public static ApplicationDependencyModelResolver newInstance() { private DependencyLoggingConfig depLogging; private List collectCompileOnly; - public ApplicationDependencyModelResolver setArtifactResolver(MavenArtifactResolver resolver) { + public IncubatingApplicationModelResolver setArtifactResolver(MavenArtifactResolver resolver) { this.resolver = resolver; return this; } - public ApplicationDependencyModelResolver setApplicationModelBuilder(ApplicationModelBuilder appBuilder) { + public IncubatingApplicationModelResolver setApplicationModelBuilder(ApplicationModelBuilder appBuilder) { this.appBuilder = appBuilder; return this; } - public ApplicationDependencyModelResolver setCollectReloadableModules(boolean collectReloadableModules) { + public IncubatingApplicationModelResolver setCollectReloadableModules(boolean collectReloadableModules) { this.collectReloadableModules = collectReloadableModules; return this; } - public ApplicationDependencyModelResolver setDependencyLogging(DependencyLoggingConfig depLogging) { + public IncubatingApplicationModelResolver setDependencyLogging(DependencyLoggingConfig depLogging) { this.depLogging = depLogging; return this; } @@ -143,7 +141,7 @@ public ApplicationDependencyModelResolver setDependencyLogging(DependencyLogging * @param collectCompileOnly compile-only dependencies to add to the model * @return self */ - public ApplicationDependencyModelResolver setCollectCompileOnly(List collectCompileOnly) { + public IncubatingApplicationModelResolver setCollectCompileOnly(List collectCompileOnly) { this.collectCompileOnly = collectCompileOnly; return this; } @@ -206,13 +204,11 @@ private List activateConditionalDeps() { private void processDeploymentDeps(DependencyNode root) { var app = new AppDep(root); - var futures = new ArrayList>(); - app.scheduleChildVisits(futures, AppDep::scheduleDeploymentVisit); - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); - if (logErrors()) { - throw new RuntimeException( - "Failed to process Quarkus application deployment dependencies, please see the errors logged above for more details."); - } + var phaser = new Phaser(1); + app.scheduleChildVisits(phaser, AppDep::scheduleDeploymentVisit); + phaser.arriveAndAwaitAdvance(); + assertNoErrors(); + appBuilder.getApplicationArtifact().addDependencies(app.allDeps); for (var d : app.children) { d.addToModel(); } @@ -222,74 +218,85 @@ private void processDeploymentDeps(DependencyNode root) { } } - private boolean logErrors() { + private void assertNoErrors() { if (!errors.isEmpty()) { - log.error("The following errors were encountered while processing Quarkus application dependencies:"); + var sb = new StringBuilder( + "The following errors were encountered while processing Quarkus application dependencies:"); + log.error(sb); var i = 1; for (var error : errors) { - log.error(i++ + ")", error); + var prefix = i++ + ")"; + log.error(prefix, error); + sb.append(System.lineSeparator()).append(prefix).append(" ").append(error.getLocalizedMessage()); + for (var e : error.getStackTrace()) { + sb.append(System.lineSeparator()).append(e); + if (e.getClassName().contains("io.quarkus")) { + break; + } + } } - return true; + throw new RuntimeException(sb.toString()); } - return false; } private void injectDeployment(List activatedConditionalDeps) { - final List> futures = new ArrayList<>(topExtensionDeps.size() - + activatedConditionalDeps.size()); - for (ExtensionDependency extDep : topExtensionDeps) { - futures.add(CompletableFuture.supplyAsync(() -> { - var resolvedDep = appBuilder.getDependency(getKey(extDep.info.deploymentArtifact)); - if (resolvedDep == null) { + final ConcurrentLinkedDeque injectQueue = new ConcurrentLinkedDeque<>(); + { + var phaser = new Phaser(1); + for (ExtensionDependency extDep : topExtensionDeps) { + phaser.register(); + CompletableFuture.runAsync(() -> { + var resolvedDep = appBuilder.getDependency(getKey(extDep.info.deploymentArtifact)); try { - extDep.collectDeploymentDeps(); - return () -> extDep.injectDeploymentNode(null); + if (resolvedDep == null) { + extDep.collectDeploymentDeps(); + injectQueue.add(() -> extDep.injectDeploymentNode(null)); + } else { + // if resolvedDep isn't null, it means the deployment artifact is on the runtime classpath + // in which case we also clear the reloadable flag on it, in case it's coming from the workspace + resolvedDep.clearFlag(DependencyFlags.RELOADABLE); + } } catch (BootstrapDependencyProcessingException e) { errors.add(e); + } finally { + phaser.arriveAndDeregister(); } - } else { - // if resolvedDep isn't null, it means the deployment artifact is on the runtime classpath - // in which case we also clear the reloadable flag on it, in case it's coming from the workspace - resolvedDep.clearFlag(DependencyFlags.RELOADABLE); - } - return null; - })); + }); + } + // non-conditional deployment branches should be added before the activated conditional ones to have consistent + // dependency graph structures + phaser.arriveAndAwaitAdvance(); + assertNoErrors(); } - // non-conditional deployment branches should be added before the activated conditional ones to have consistent - // dependency graph structures - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); - if (errors.isEmpty() && !activatedConditionalDeps.isEmpty()) { + if (!activatedConditionalDeps.isEmpty()) { + var phaser = new Phaser(1); for (ConditionalDependency cd : activatedConditionalDeps) { - futures.add(CompletableFuture.supplyAsync(() -> { - var resolvedDep = appBuilder.getDependency(getKey(cd.appDep.ext.info.deploymentArtifact)); - if (resolvedDep == null) { - var extDep = cd.getExtensionDependency(); - try { + phaser.register(); + CompletableFuture.runAsync(() -> { + var resolvedDep = appBuilder.getDependency(getKey(cd.conditionalDep.ext.info.deploymentArtifact)); + try { + if (resolvedDep == null) { + var extDep = cd.getExtensionDependency(); extDep.collectDeploymentDeps(); - return () -> extDep.injectDeploymentNode(cd.appDep.ext.getParentDeploymentNode()); - } catch (BootstrapDependencyProcessingException e) { - errors.add(e); + injectQueue.add(() -> extDep.injectDeploymentNode(cd.conditionalDep.ext.getParentDeploymentNode())); + } else { + // if resolvedDep isn't null, it means the deployment artifact is on the runtime classpath + // in which case we also clear the reloadable flag on it, in case it's coming from the workspace + resolvedDep.clearFlag(DependencyFlags.RELOADABLE); } - } else { - // if resolvedDep isn't null, it means the deployment artifact is on the runtime classpath - // in which case we also clear the reloadable flag on it, in case it's coming from the workspace - resolvedDep.clearFlag(DependencyFlags.RELOADABLE); + } catch (BootstrapDependencyProcessingException e) { + errors.add(e); + } finally { + phaser.arriveAndDeregister(); } - return null; - })); + }); } - } - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); - if (logErrors()) { - throw new RuntimeException( - "Failed to process Quarkus application deployment dependencies, please see the errors logged above for more details."); + phaser.arriveAndAwaitAdvance(); + assertNoErrors(); } - for (var future : futures) { - var ext = future.getNow(null); - if (ext != null) { - ext.run(); - } + for (var inject : injectQueue) { + inject.run(); } } @@ -370,14 +377,15 @@ private void collectPlatformProperties() throws AppModelResolverException { for (Dependency d : managedDeps) { final Artifact artifact = d.getArtifact(); final String extension = artifact.getExtension(); - final String artifactId = artifact.getArtifactId(); if ("json".equals(extension) - && artifactId.endsWith(BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX)) { - platformReleases.addPlatformDescriptor(artifact.getGroupId(), artifactId, artifact.getClassifier(), extension, + && artifact.getArtifactId().endsWith(BootstrapConstants.PLATFORM_DESCRIPTOR_ARTIFACT_ID_SUFFIX)) { + platformReleases.addPlatformDescriptor(artifact.getGroupId(), artifact.getArtifactId(), + artifact.getClassifier(), extension, artifact.getVersion()); } else if ("properties".equals(extension) - && artifactId.endsWith(BootstrapConstants.PLATFORM_PROPERTIES_ARTIFACT_ID_SUFFIX)) { - platformReleases.addPlatformProperties(artifact.getGroupId(), artifactId, artifact.getClassifier(), extension, + && artifact.getArtifactId().endsWith(BootstrapConstants.PLATFORM_PROPERTIES_ARTIFACT_ID_SUFFIX)) { + platformReleases.addPlatformProperties(artifact.getGroupId(), artifact.getArtifactId(), + artifact.getClassifier(), extension, artifact.getVersion(), resolver.resolve(artifact).getArtifact().getFile().toPath()); } } @@ -385,12 +393,12 @@ private void collectPlatformProperties() throws AppModelResolverException { } private void clearReloadableFlag(ResolvedDependencyBuilder dep) { - final Set deps = artifactDeps.get(dep.getArtifactCoords()); - if (deps == null || deps.isEmpty()) { + final Collection deps = dep.getDependencies(); + if (deps.isEmpty()) { return; } - for (ArtifactKey key : deps) { - final ResolvedDependencyBuilder child = appBuilder.getDependency(key); + for (ArtifactCoords coords : deps) { + final ResolvedDependencyBuilder child = appBuilder.getDependency(coords.getKey()); if (child == null || child.isFlagSet(DependencyFlags.VISITED)) { continue; } @@ -444,20 +452,18 @@ private boolean isRuntimeArtifact(ArtifactKey key) { } private void processRuntimeDeps(DependencyNode root) { - final AppDep app = new AppDep(root); - app.walkingFlags = COLLECT_TOP_EXTENSION_RUNTIME_NODES | COLLECT_DIRECT_DEPS; + final AppDep appRoot = new AppDep(root); + appRoot.walkingFlags = COLLECT_TOP_EXTENSION_RUNTIME_NODES | COLLECT_DIRECT_DEPS; if (collectReloadableModules) { - app.walkingFlags |= COLLECT_RELOADABLE_MODULES; + appRoot.walkingFlags |= COLLECT_RELOADABLE_MODULES; } - var futures = new ArrayList>(); - app.scheduleChildVisits(futures, AppDep::scheduleRuntimeVisit); - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); - if (logErrors()) { - throw new RuntimeException( - "Failed to process Quarkus application runtime dependencies, please see the errors logged above for more details."); - } - app.setChildFlags(); + final Phaser phaser = new Phaser(1); + appRoot.scheduleChildVisits(phaser, AppDep::scheduleRuntimeVisit); + phaser.arriveAndAwaitAdvance(); + assertNoErrors(); + appBuilder.getApplicationArtifact().addDependencies(appRoot.allDeps); + appRoot.setChildFlags(); } private class AppDep { @@ -467,17 +473,20 @@ private class AppDep { byte walkingFlags; ResolvedDependencyBuilder resolvedDep; final List children; + final List allDeps; AppDep(DependencyNode node) { this.parent = null; this.node = node; this.children = new ArrayList<>(node.getChildren().size()); + this.allDeps = new ArrayList<>(node.getChildren().size()); } AppDep(AppDep parent, DependencyNode node) { this.parent = parent; this.node = node; this.children = new ArrayList<>(node.getChildren().size()); + this.allDeps = new ArrayList<>(node.getChildren().size()); } void addToModel() { @@ -486,41 +495,48 @@ void addToModel() { } // this node is added after its children to stay compatible with the legacy impl if (resolvedDep != null) { + resolvedDep.addDependencies(allDeps); appBuilder.addDependency(resolvedDep); } } - void scheduleDeploymentVisit(List> futures) { - futures.add(CompletableFuture.runAsync(() -> { + void scheduleDeploymentVisit(Phaser phaser) { + phaser.register(); + CompletableFuture.runAsync(() -> { try { visitDeploymentDependency(); } catch (Throwable e) { errors.add(e); + } finally { + phaser.arriveAndDeregister(); } - })); - scheduleChildVisits(futures, AppDep::scheduleDeploymentVisit); + }); + scheduleChildVisits(phaser, AppDep::scheduleDeploymentVisit); } void visitDeploymentDependency() { - var dep = appBuilder.getDependency(getKey(node.getArtifact())); - if (dep == null) { + if (!appBuilder.hasDependency(getKey(node.getArtifact()))) { try { - resolvedDep = newDependencyBuilder(node, resolver).setFlags(DependencyFlags.DEPLOYMENT_CP); + resolvedDep = newDependencyBuilder(node, resolver) + .setFlags(DependencyFlags.DEPLOYMENT_CP); } catch (BootstrapMavenException e) { throw new RuntimeException(e); } } } - void scheduleRuntimeVisit(List> futures) { - futures.add(CompletableFuture.runAsync(() -> { + void scheduleRuntimeVisit(Phaser phaser) { + phaser.register(); + CompletableFuture.runAsync(() -> { try { visitRuntimeDependency(); } catch (Throwable t) { errors.add(t); + } finally { + phaser.arriveAndDeregister(); } - })); - scheduleChildVisits(futures, AppDep::scheduleRuntimeVisit); + }); + scheduleChildVisits(phaser, AppDep::scheduleRuntimeVisit); } void visitRuntimeDependency() { @@ -558,23 +574,21 @@ void visitRuntimeDependency() { } } - void scheduleChildVisits(List> futures, - BiConsumer>> childVisitor) { + void scheduleChildVisits(Phaser phaser, BiConsumer childVisitor) { var childNodes = node.getChildren(); List filtered = null; - var depKeys = artifactDeps.computeIfAbsent(getCoords(node.getArtifact()), key -> new HashSet<>(childNodes.size())); for (int i = 0; i < childNodes.size(); ++i) { var childNode = childNodes.get(i); var winner = getWinner(childNode); if (winner == null) { - depKeys.add(getKey(childNode.getArtifact())); + allDeps.add(getCoords(childNode.getArtifact())); var child = new AppDep(this, childNode); children.add(child); if (filtered != null) { filtered.add(childNode); } } else { - depKeys.add(getKey(winner.getArtifact())); + allDeps.add(getCoords(winner.getArtifact())); if (filtered == null) { filtered = new ArrayList<>(childNodes.size()); for (int j = 0; j < i; ++j) { @@ -587,7 +601,7 @@ void scheduleChildVisits(List> futures, node.setChildren(filtered); } for (var child : children) { - childVisitor.accept(child, futures); + childVisitor.accept(child, phaser); } } @@ -599,6 +613,7 @@ void setChildFlags() { void setFlags(byte walkingFlags) { + resolvedDep.addDependencies(allDeps); if (ext != null) { var parentExtDep = parent; while (parentExtDep != null) { @@ -611,11 +626,14 @@ void setFlags(byte walkingFlags) { ext.info.ensureActivated(); } - if (appBuilder.getDependency(resolvedDep.getKey()) == null) { + var existingDep = appBuilder.getDependency(resolvedDep.getKey()); + if (existingDep == null) { appBuilder.addDependency(resolvedDep); if (ext != null) { managedDeps.add(new Dependency(ext.info.deploymentArtifact, JavaScopes.COMPILE)); } + } else if (existingDep != resolvedDep) { + throw new IllegalStateException(node.getArtifact() + " is already in the model"); } this.walkingFlags = walkingFlags; @@ -635,7 +653,6 @@ void setFlags(byte walkingFlags) { } clearWalkingFlag(COLLECT_DIRECT_DEPS); - setChildFlags(); } @@ -723,7 +740,7 @@ private void collectConditionalDependencies() } final ConditionalDependency conditionalDep = new ConditionalDependency(conditionalInfo, this); conditionalDepsToProcess.add(conditionalDep); - conditionalDep.appDep.collectConditionalDependencies(); + conditionalDep.conditionalDep.collectConditionalDependencies(); } } } @@ -1019,7 +1036,7 @@ private boolean replaceDirectDepBranch(DependencyNode parentNode, boolean replac private class ConditionalDependency { - final AppDep appDep; + final AppDep conditionalDep; private boolean activated; private ConditionalDependency(ExtensionInfo info, AppDep parent) { @@ -1030,12 +1047,12 @@ private ConditionalDependency(ExtensionInfo info, AppDep parent) { new BootstrapArtifactVersion(info.runtimeArtifact.getVersion()))); rtNode.setRepositories(parent.ext.runtimeNode.getRepositories()); - appDep = new AppDep(parent, rtNode); - appDep.ext = new ExtensionDependency(info, rtNode, parent.ext.exclusions); + conditionalDep = new AppDep(parent, rtNode); + conditionalDep.ext = new ExtensionDependency(info, rtNode, parent.ext.exclusions); } ExtensionDependency getExtensionDependency() { - return appDep.ext; + return conditionalDep.ext; } void activate() { @@ -1044,7 +1061,7 @@ void activate() { } activated = true; final ExtensionDependency extDep = getExtensionDependency(); - final DependencyNode originalNode = collectDependencies(appDep.ext.info.runtimeArtifact, extDep.exclusions, + final DependencyNode originalNode = collectDependencies(conditionalDep.ext.info.runtimeArtifact, extDep.exclusions, extDep.runtimeNode.getRepositories()); final DefaultDependencyNode rtNode = (DefaultDependencyNode) extDep.runtimeNode; rtNode.setRepositories(originalNode.getRepositories()); @@ -1057,39 +1074,28 @@ void activate() { currentChildren.addAll(originalNode.getChildren()); } - appDep.walkingFlags = COLLECT_DIRECT_DEPS; + conditionalDep.walkingFlags = COLLECT_DIRECT_DEPS; if (collectReloadableModules) { - appDep.walkingFlags |= COLLECT_RELOADABLE_MODULES; + conditionalDep.walkingFlags |= COLLECT_RELOADABLE_MODULES; } - var futures = new ArrayList>(); - appDep.scheduleRuntimeVisit(futures); - CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); - if (logErrors()) { - throw new RuntimeException( - "Failed to process Quarkus application conditional dependencies, please see the errors logged above for more details."); - } - - appDep.setFlags(appDep.walkingFlags); - - var parentExtDep = appDep.parent; - parentExtDep.children.add(appDep); - while (parentExtDep != null) { - if (parentExtDep.ext != null) { - parentExtDep.ext.addExtensionDependency(appDep.ext); - break; - } - parentExtDep = parentExtDep.parent; + var phaser = new Phaser(1); + conditionalDep.scheduleRuntimeVisit(phaser); + phaser.arriveAndAwaitAdvance(); + assertNoErrors(); + conditionalDep.setFlags(conditionalDep.walkingFlags); + if (conditionalDep.parent.resolvedDep == null) { + conditionalDep.parent.allDeps.add(conditionalDep.resolvedDep.getArtifactCoords()); + } else { + conditionalDep.parent.resolvedDep.addDependency(conditionalDep.resolvedDep.getArtifactCoords()); } - appDep.ext.info.ensureActivated(); - - appDep.parent.ext.runtimeNode.getChildren().add(rtNode); + conditionalDep.parent.ext.runtimeNode.getChildren().add(rtNode); } boolean isSatisfied() { - if (appDep.ext.info.dependencyCondition == null) { + if (conditionalDep.ext.info.dependencyCondition == null) { return true; } - for (ArtifactKey key : appDep.ext.info.dependencyCondition) { + for (ArtifactKey key : conditionalDep.ext.info.dependencyCondition) { if (!isRuntimeArtifact(key)) { return false; } @@ -1125,19 +1131,18 @@ private class AppDepLogger { private AppDepLogger() { } - void log(AppDep root) { - logInternal(root); - - final int childrenTotal = root.children.size(); + void log(AppDep dep) { + logInternal(dep); + final int childrenTotal = dep.node.getChildren().size(); if (childrenTotal > 0) { if (childrenTotal == 1) { depth.add(false); - log(root.children.get(0)); + log(dep.children.get(0)); } else { depth.add(true); int i = 0; while (i < childrenTotal) { - log(root.children.get(i++)); + log(dep.children.get(i++)); if (i == childrenTotal - 1) { depth.set(depth.size() - 1, false); } @@ -1166,25 +1171,26 @@ private void logInternal(AppDep dep) { buf.append('\u2514').append('\u2500').append(' '); } } - buf.append(dep.node.getArtifact()); + var resolvedDep = getResolvedDependency(getKey(dep.node.getArtifact())); + buf.append(resolvedDep.toCompactCoords()); if (!depth.isEmpty()) { - appendFlags(buf, getResolvedDependency(getKey(dep.node.getArtifact()))); + appendFlags(buf, resolvedDep); } depLogging.getMessageConsumer().accept(buf.toString()); if (depLogging.isGraph()) { - var depKeys = artifactDeps.get(getCoords(dep.node.getArtifact())); - if (depKeys != null && !depKeys.isEmpty() && depKeys.size() != dep.children.size()) { - final Map versions = new HashMap<>(dep.children.size()); + var deps = resolvedDep.getDependencies(); + if (!deps.isEmpty() && deps.size() != dep.children.size()) { + final Map versions = new HashMap<>(dep.children.size()); for (var c : dep.children) { - versions.put(getKey(c.node.getArtifact()), c.node.getArtifact().getVersion()); + versions.put(getCoords(c.node.getArtifact()), null); } - var list = new ArrayList(depKeys.size() - dep.children.size()); - for (var key : depKeys) { - if (!versions.containsKey(key)) { - var d = getResolvedDependency(key); - var sb = new StringBuilder().append(d.toGACTVString()); - appendFlags(sb, d); + var list = new ArrayList(deps.size() - dep.children.size()); + for (var coords : deps) { + if (!versions.containsKey(coords)) { + var childDep = getResolvedDependency(coords.getKey()); + var sb = new StringBuilder().append(childDep.toCompactCoords()); + appendFlags(sb, childDep); list.add(sb.append(" [+]").toString()); } } @@ -1225,7 +1231,7 @@ private void logInternal(AppDep dep) { } } - private void appendFlags(StringBuilder sb, ResolvedDependencyBuilder d) { + private void appendFlags(StringBuilder sb, ResolvedDependency d) { sb.append(" (").append(d.getScope()); if (d.isFlagSet(DependencyFlags.OPTIONAL)) { sb.append(" optional"); @@ -1247,11 +1253,14 @@ private void appendFlags(StringBuilder sb, ResolvedDependencyBuilder d) { } private ResolvedDependencyBuilder getResolvedDependency(ArtifactKey key) { - var d = appBuilder.getDependency(key); - if (d == null) { - throw new IllegalArgumentException(key + " is not found among application dependencies"); + var resolvedDep = appBuilder.getDependency(key); + if (resolvedDep == null) { + if (appBuilder.getApplicationArtifact().getKey().equals(key)) { + return appBuilder.getApplicationArtifact(); + } + throw new IllegalArgumentException("Failed to locate " + key + " among application dependencies"); } - return d; + return resolvedDep; } } }