diff --git a/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/BootstrapFromOriginalJarTestBase.java b/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/BootstrapFromOriginalJarTestBase.java index d9886d3bdd8e0..b00fb467d212d 100644 --- a/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/BootstrapFromOriginalJarTestBase.java +++ b/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/BootstrapFromOriginalJarTestBase.java @@ -72,8 +72,17 @@ protected QuarkusBootstrap.Builder initBootstrapBuilder() throws Exception { final QuarkusBootstrap.Builder bootstrap = QuarkusBootstrap.builder() .setApplicationRoot(applicationRoot) .setProjectRoot(applicationRoot) - .setAppModelResolver(resolver) - .setTest(isBootstrapForTestMode()); + .setAppModelResolver(resolver); + + switch (getBootstrapMode()) { + case PROD: + break; + case TEST: + bootstrap.setTest(true); + break; + default: + throw new IllegalArgumentException("Not supported bootstrap mode " + getBootstrapMode()); + } if (createWorkspace() || !wsModules.isEmpty()) { System.setProperty("basedir", ws.toAbsolutePath().toString()); diff --git a/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/BootstrapFromWorkspaceModuleTestBase.java b/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/BootstrapFromWorkspaceModuleTestBase.java index 4b02780956a77..6b48998c16cb8 100644 --- a/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/BootstrapFromWorkspaceModuleTestBase.java +++ b/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/BootstrapFromWorkspaceModuleTestBase.java @@ -19,8 +19,16 @@ protected QuarkusBootstrap.Builder initBootstrapBuilder() .setApplicationRoot(applicationRoot) .setProjectRoot(applicationRoot) .setTargetDirectory(appModel.getAppArtifact().getWorkspaceModule().getBuildDir().toPath()) - .setAppModelResolver(resolver) - .setTest(isBootstrapForTestMode()); + .setAppModelResolver(resolver); + switch (getBootstrapMode()) { + case PROD: + break; + case TEST: + bootstrap.setTest(true); + break; + default: + throw new IllegalArgumentException("Not supported bootstrap mode " + getBootstrapMode()); + } return bootstrap; } } diff --git a/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/ProvidedExtensionDepsInTestModeTest.java b/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/ProvidedExtensionDepsInTestModeTest.java index 95c7dcf563b71..cc36dc92e3c34 100644 --- a/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/ProvidedExtensionDepsInTestModeTest.java +++ b/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/ProvidedExtensionDepsInTestModeTest.java @@ -5,6 +5,7 @@ import java.util.HashSet; import java.util.Set; +import io.quarkus.bootstrap.app.QuarkusBootstrap; import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.bootstrap.resolver.TsArtifact; import io.quarkus.bootstrap.resolver.TsDependency; @@ -17,8 +18,8 @@ public class ProvidedExtensionDepsInTestModeTest extends BootstrapFromOriginalJarTestBase { @Override - protected boolean isBootstrapForTestMode() { - return true; + protected QuarkusBootstrap.Mode getBootstrapMode() { + return QuarkusBootstrap.Mode.TEST; } @Override diff --git a/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/ProvidedExtensionDepsTestModeTest.java b/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/ProvidedExtensionDepsTestModeTest.java index 26b8f66d583c2..7f6d175f67e71 100644 --- a/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/ProvidedExtensionDepsTestModeTest.java +++ b/core/deployment/src/test/java/io/quarkus/deployment/runnerjar/ProvidedExtensionDepsTestModeTest.java @@ -7,6 +7,7 @@ import org.eclipse.aether.util.artifact.JavaScopes; +import io.quarkus.bootstrap.app.QuarkusBootstrap; import io.quarkus.bootstrap.model.ApplicationModel; import io.quarkus.bootstrap.resolver.TsArtifact; import io.quarkus.bootstrap.resolver.TsDependency; @@ -19,8 +20,8 @@ public class ProvidedExtensionDepsTestModeTest extends BootstrapFromOriginalJarTestBase { @Override - protected boolean isBootstrapForTestMode() { - return true; + protected QuarkusBootstrap.Mode getBootstrapMode() { + return QuarkusBootstrap.Mode.TEST; } @Override diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java index 523ab4d735cd7..2a6cd65081a99 100644 --- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java +++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ConditionalDependenciesEnabler.java @@ -48,7 +48,7 @@ public ConditionalDependenciesEnabler(Project project, LaunchMode mode, if (!baseRuntimeConfig.getIncoming().getDependencies().isEmpty()) { // Gather all extensions from the full resolved dependency tree - collectConditionalDependencies(baseRuntimeConfig.getResolvedConfiguration().getResolvedArtifacts()); + collectConditionalDependencies(baseRuntimeConfig.getResolvedConfiguration().getResolvedArtifacts(), mode); // If there are any extensions which had unresolved conditional dependencies: while (!unsatisfiedConditionalDeps.isEmpty()) { boolean satisfiedConditionalDeps = false; @@ -58,7 +58,7 @@ public ConditionalDependenciesEnabler(Project project, LaunchMode mode, while (i < unsatisfiedConditionalDeps.size()) { final Dependency conditionalDep = unsatisfiedConditionalDeps.get(i); // Try to resolve it with the latest evolved graph available - if (resolveConditionalDependency(conditionalDep)) { + if (resolveConditionalDependency(conditionalDep, mode)) { // Mark the resolution as a success so we know the graph evolved satisfiedConditionalDeps = true; unsatisfiedConditionalDeps.remove(i); @@ -86,7 +86,7 @@ private void reset() { unsatisfiedConditionalDeps.clear(); } - private void collectConditionalDependencies(Set runtimeArtifacts) { + private void collectConditionalDependencies(Set runtimeArtifacts, LaunchMode mode) { // For every artifact in the dependency graph: for (ResolvedArtifact artifact : runtimeArtifacts) { // Add to master list of artifacts: @@ -96,17 +96,28 @@ private void collectConditionalDependencies(Set runtimeArtifac if (extension != null) { // Add to master list of accepted extensions: allExtensions.put(extension.getExtensionId(), extension); - for (Dependency conditionalDep : extension.getConditionalDependencies()) { - // If the dependency is not present yet in the graph, queue it for resolution later - if (!exists(conditionalDep)) { - queueConditionalDependency(extension, conditionalDep); - } - } + queueConditionalDependencies(extension, mode); } } } - private boolean resolveConditionalDependency(Dependency conditionalDep) { + private void queueConditionalDependencies(ExtensionDependency extension, LaunchMode mode) { + queueConditionalDependencies(extension, extension.getConditionalDependencies()); + if (LaunchMode.DEVELOPMENT.equals(mode)) { + queueConditionalDependencies(extension, extension.getConditionalDevDependencies()); + } + } + + private void queueConditionalDependencies(ExtensionDependency extension, Collection conditionalDeps) { + for (Dependency conditionalDep : conditionalDeps) { + // If the dependency is not present yet in the graph, queue it for resolution later + if (!exists(conditionalDep)) { + queueConditionalDependency(extension, conditionalDep); + } + } + } + + private boolean resolveConditionalDependency(Dependency conditionalDep, LaunchMode mode) { final Configuration conditionalDeps = createConditionalDependenciesConfiguration(project, conditionalDep); Set resolvedArtifacts = conditionalDeps.getResolvedConfiguration().getResolvedArtifacts(); @@ -148,12 +159,7 @@ private boolean resolveConditionalDependency(Dependency conditionalDep) { extensionDependency.setConditional(true); // Add to the master list of accepted extensions allExtensions.put(extensionDependency.getExtensionId(), extensionDependency); - for (Dependency cd : extensionDependency.getConditionalDependencies()) { - // Add any unsatisfied/unresolved conditional dependencies of this dependency to the queue - if (!exists(cd)) { - queueConditionalDependency(extensionDependency, cd); - } - } + queueConditionalDependencies(extensionDependency, mode); } return satisfied; } diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ArtifactExtensionDependency.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ArtifactExtensionDependency.java index a9c48817bb80f..81dc9235382b5 100644 --- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ArtifactExtensionDependency.java +++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ArtifactExtensionDependency.java @@ -12,7 +12,8 @@ public class ArtifactExtensionDependency extends ExtensionDependency conditionalDependencies, + List conditionalDevDeps, List dependencyConditions) { - super(extensionId, deploymentModule, conditionalDependencies, dependencyConditions); + super(extensionId, deploymentModule, conditionalDependencies, conditionalDevDeps, dependencyConditions); } } diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/DependencyUtils.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/DependencyUtils.java index 15682e835114d..5ce79560d9c53 100644 --- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/DependencyUtils.java +++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/DependencyUtils.java @@ -255,7 +255,6 @@ private static ProjectExtensionDependency createExtensionDependency( if (extensionConfiguration != null) { final ListProperty conditionalDependenciesProp = ConfigurationUtils .getConditionalDependencies(extensionConfiguration); - if (conditionalDependenciesProp.isPresent()) { for (String rawDep : conditionalDependenciesProp.get()) { conditionalDependencies.add(create(project.getDependencies(), rawDep)); @@ -272,10 +271,28 @@ private static ProjectExtensionDependency createExtensionDependency( } } - if (extensionDescriptor != null && extensionDescriptor.containsKey(BootstrapConstants.CONDITIONAL_DEPENDENCIES)) { - final String[] deps = BootstrapUtils - .splitByWhitespace(extensionDescriptor.getProperty(BootstrapConstants.CONDITIONAL_DEPENDENCIES)); + final String conditionalDepsStr = extensionDescriptor == null ? null + : extensionDescriptor.getProperty(BootstrapConstants.CONDITIONAL_DEPENDENCIES); + if (conditionalDepsStr != null) { + for (String condDep : BootstrapUtils.splitByWhitespace(conditionalDepsStr)) { + conditionalDependencies.add(create(project.getDependencies(), condDep)); + } + } + List conditionalDevDeps = List.of(); + final String conditionalDevDepsStr = extensionDescriptor == null ? null + : extensionDescriptor.getProperty(BootstrapConstants.CONDITIONAL_DEV_DEPENDENCIES); + if (conditionalDepsStr != null) { + final String[] arr = BootstrapUtils.splitByWhitespace(conditionalDepsStr); + conditionalDevDeps = new ArrayList<>(arr.length); + for (int i = 0; i < arr.length; ++i) { + conditionalDevDeps.add(create(project.getDependencies(), arr[i])); + } + } + + if (extensionDescriptor != null && extensionDescriptor.containsKey(BootstrapConstants.CONDITIONAL_DEV_DEPENDENCIES)) { + final String[] deps = BootstrapUtils + .splitByWhitespace(extensionDescriptor.getProperty(BootstrapConstants.CONDITIONAL_DEV_DEPENDENCIES)); for (String condDep : deps) { conditionalDependencies.add(create(project.getDependencies(), condDep)); } @@ -284,7 +301,6 @@ private static ProjectExtensionDependency createExtensionDependency( if (extensionDescriptor != null && extensionDescriptor.containsKey(BootstrapConstants.DEPENDENCY_CONDITION)) { final ArtifactKey[] conditions = BootstrapUtils .parseDependencyCondition(extensionDescriptor.getProperty(BootstrapConstants.DEPENDENCY_CONDITION)); - dependencyConditions.addAll(Arrays.asList(conditions)); } @@ -293,6 +309,7 @@ private static ProjectExtensionDependency createExtensionDependency( deploymentProject, isIncludedBuild, conditionalDependencies, + conditionalDevDeps, dependencyConditions); } @@ -302,47 +319,42 @@ private static ArtifactExtensionDependency createExtensionDependency( Path descriptorPath) { final Properties extensionProperties = loadLocalExtensionDescriptor(descriptorPath); - final ArtifactCoords deploymentArtifact = GACTV + final ArtifactCoords deploymentArtifact = ArtifactCoords .fromString(extensionProperties.getProperty(BootstrapConstants.PROP_DEPLOYMENT_ARTIFACT)); - final List conditionalDependencies; - if (extensionProperties.containsKey(BootstrapConstants.CONDITIONAL_DEPENDENCIES)) { - final String[] deps = BootstrapUtils - .splitByWhitespace(extensionProperties.getProperty(BootstrapConstants.CONDITIONAL_DEPENDENCIES)); - - if (deps.length > 0) { - conditionalDependencies = new ArrayList<>(deps.length); - for (String condDep : deps) { - conditionalDependencies.add(create(project.getDependencies(), condDep)); - } - } else { - conditionalDependencies = Collections.emptyList(); - } - } else { - conditionalDependencies = Collections.emptyList(); - } - - final List dependencyConditions; + List dependencyConditions = List.of(); if (extensionProperties.containsKey(BootstrapConstants.DEPENDENCY_CONDITION)) { final ArtifactKey[] conditions = BootstrapUtils .parseDependencyCondition(extensionProperties.getProperty(BootstrapConstants.DEPENDENCY_CONDITION)); - if (conditions.length > 0) { dependencyConditions = Arrays.asList(conditions); - } else { - dependencyConditions = Collections.emptyList(); } - } else { - dependencyConditions = Collections.emptyList(); } return new ArtifactExtensionDependency( extensionArtifactId, deploymentArtifact, - conditionalDependencies, + parseConditionalDeps(project, extensionProperties, BootstrapConstants.CONDITIONAL_DEPENDENCIES), + parseConditionalDeps(project, extensionProperties, BootstrapConstants.CONDITIONAL_DEV_DEPENDENCIES), dependencyConditions); } + private static List parseConditionalDeps(Project project, Properties extensionProperties, String propertyName) { + var str = extensionProperties.getProperty(propertyName); + if (str == null) { + return List.of(); + } + final String[] deps = BootstrapUtils.splitByWhitespace(extensionProperties.getProperty(propertyName)); + if (deps.length == 0) { + return List.of(); + } + var list = new ArrayList(deps.length); + for (String condDep : deps) { + list.add(create(project.getDependencies(), condDep)); + } + return list; + } + public static Dependency create(DependencyHandler dependencies, String conditionalDependency) { final ArtifactCoords dependencyCoords = GACTV.fromString(conditionalDependency); return dependencies.create(String.join(":", dependencyCoords.getGroupId(), dependencyCoords.getArtifactId(), diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ExtensionDependency.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ExtensionDependency.java index c10143b695ce7..e8ce16efb50cb 100644 --- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ExtensionDependency.java +++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ExtensionDependency.java @@ -15,15 +15,17 @@ public abstract class ExtensionDependency { private final ModuleVersionIdentifier extensionId; private final T deploymentModule; private final List conditionalDependencies; + private final List conditionalDevDeps; private final List dependencyConditions; private boolean isConditional; public ExtensionDependency(ModuleVersionIdentifier extensionId, T deploymentModule, - List conditionalDependencies, + List conditionalDependencies, List conditionalDevDeps, List dependencyConditions) { this.extensionId = extensionId; this.deploymentModule = deploymentModule; this.conditionalDependencies = conditionalDependencies; + this.conditionalDevDeps = conditionalDevDeps; this.dependencyConditions = dependencyConditions; } @@ -41,7 +43,15 @@ public void importConditionalDependency(DependencyHandler dependencies, ModuleVe } private Dependency findConditionalDependency(ModuleVersionIdentifier capability) { - for (Dependency conditionalDependency : conditionalDependencies) { + final Dependency dep = findConditionalDependency(capability, conditionalDependencies); + if (dep != null) { + return dep; + } + return findConditionalDependency(capability, conditionalDevDeps); + } + + private static Dependency findConditionalDependency(ModuleVersionIdentifier capability, List deps) { + for (Dependency conditionalDependency : deps) { if (conditionalDependency.getGroup().equals(capability.getGroup()) && conditionalDependency.getName().equals(capability.getName())) { return conditionalDependency; @@ -78,6 +88,10 @@ public List getConditionalDependencies() { return conditionalDependencies; } + public List getConditionalDevDependencies() { + return conditionalDevDeps; + } + public T getDeploymentModule() { return deploymentModule; } diff --git a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ProjectExtensionDependency.java b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ProjectExtensionDependency.java index 77ef259b116a0..f362763462d71 100644 --- a/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ProjectExtensionDependency.java +++ b/devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/tooling/dependency/ProjectExtensionDependency.java @@ -16,6 +16,7 @@ public ProjectExtensionDependency( Project deploymentModule, Boolean isIncludedBuild, List conditionalDependencies, + List conditionalDevDeps, List dependencyConditions) { super(DefaultModuleVersionIdentifier.newId( extensionProject.getGroup().toString(), @@ -23,6 +24,7 @@ public ProjectExtensionDependency( extensionProject.getVersion().toString()), deploymentModule, conditionalDependencies, + conditionalDevDeps, dependencyConditions); this.isIncludedBuild = isIncludedBuild; diff --git a/docs/src/main/asciidoc/conditional-extension-dependencies.adoc b/docs/src/main/asciidoc/conditional-extension-dependencies.adoc index 576f4424f484e..d806d20c70254 100644 --- a/docs/src/main/asciidoc/conditional-extension-dependencies.adoc +++ b/docs/src/main/asciidoc/conditional-extension-dependencies.adoc @@ -9,21 +9,21 @@ include::_attributes.adoc[] :summary: Trigger the inclusion on additional extensions based on certain conditions. :topics: extensions -Quarkus extension dependencies are usually configured in the same way as any other project dependencies in the project's build file, e.g. the Maven `pom.xml` or the Gradle build scripts. However, there are dependency types that aren't yet supported out-of-the-box by Maven and Gradle. What we refer here to as "conditional dependencies" is one example. +Quarkus extension dependencies are usually configured in the same way as any other project dependencies in a project's build file, e.g. the Maven `pom.xml` or the Gradle build scripts. However, Quarkus also supports types of dependencies that aren't supported out-of-the-box by Maven and Gradle. Conditional Quarkus extension dependencies falls into that category. == Conditional Dependencies -The idea behind the notion of the conditional dependency is that such a dependency must be activated only if a certain condition is satisfied. If the condition is not satisfied then the dependency **must not** be activated. In that regard, conditional dependencies can be categorized as optional, i.e. they may or may not appear in the resulting set of project dependencies. +A conditional dependency is a dependency that is activated only if a certain condition is satisfied. If the condition is not satisfied then the dependency **must not** be activated. In that regard, conditional dependencies can be categorized as optional, meaning they may or may not appear in the resulting dependency graph. -In which cases could conditional dependencies be useful? A typical example would be a component that should be activated **only** in case all of its required dependencies are available. If one or more of the component's required dependencies aren't available, instead of failing, the component should simply not be activated. +A typical example of a conditional dependency would be a component that should be added to the classpath **only** in case all of its required dependencies are present on the classpath. If one or more of the component's required dependencies aren't available, instead of failing, the component should simply not be added. -== Quarkus Conditional Extension Dependencies +== Conditional Quarkus Extension Dependencies -Quarkus supports conditional extension dependencies. I.e. one Quarkus extension may declare one or more conditional dependencies on other Quarkus extensions. Conditional dependencies on and from non-extension artifacts aren't supported. +A Quarkus extension may declare one or more conditional dependencies on other Quarkus extensions. Conditional dependencies on and from non-extension artifacts aren't supported. -Let's take the following scenario as an example: `quarkus-extension-a` has an optional dependency on `quarkus-extension-b` which should be included in a Quarkus application only if `quarkus-extension-c` is found among its dependencies (direct or transitive). In other words, the presence of `quarkus-extension-c` is the condition which, if satisfied, enables `quarkus-extension-b` during the build of a Quarkus application. +Let's consider the following scenario as an example: `quarkus-extension-a` has an optional dependency on `quarkus-extension-b` which should be included in a Quarkus application only if `quarkus-extension-c` is found among the application dependencies (direct or transitive). In this case, the presence of `quarkus-extension-c` is the condition which, if satisfied, will trigger inclusion of the `quarkus-extension-b` when Quarkus application dependencies are resolved. -The condition which triggers activation of an extension is configured in the extension's descriptor, which is included into the runtime artifact of the extension as `META-INF/quarkus-extension.properties`. Given that extension descriptor is generated by the Quarkus plugin at extension build time, extension developers can add the following configuration to express the condition which would have to be satisfied for the extension to be activated: +The condition which triggers activation of an extension is configured in the extension's `META-INF/quarkus-extension.properties`, which is included in the runtime artifact of the extension.Extension developers can add the following configuration to express the condition which would have to be satisfied for the extension to be activated: [source,xml] ---- @@ -61,20 +61,22 @@ The condition which triggers activation of an extension is configured in the ext ---- -<1> runtime Quarkus extension artifact ID, in our example `quarkus-extension-b`; +<1> runtime Quarkus extension artifact ID; <2> the goal that generates the extension descriptor which every Quarkus runtime extension project should be configured with; -<3> configuration of the condition which will have to be satisfied for this extension to be included into a Quarkus application expressed as a list of artifacts that must be present among the application dependencies; +<3> configuration of the dependency condition which will have to be satisfied for this extension to be added to a Quarkus application expressed as a list of artifacts that must be present among the application dependencies; <4> an artifact key (in the format of `groupId:artifactId[::]` but typically simply `:`) of the artifact that must be present among the application dependencies for the condition to be satisfied. -NOTE: In the example above the `artifact` used in the condition configuration happens to be a runtime Quarkus extension artifact but it could as well be any other artifact. There could also be more than one `artifact` element in the body of `dependencyCondition`. +NOTE: In the example above the `artifact` used in the condition configuration happens to be a runtime Quarkus extension artifact but it could as well be any other artifact. There could also be more than one `artifact` element in the body of the `dependencyCondition`. -Now, having a dependency activating condition in the descriptor of `quarkus-extension-b`, other extensions may declare a conditional dependency on it. +Now, having a dependency condition recorded in the descriptor of the `quarkus-extension-b`, other extensions may declare a conditional dependency on it. -A conditional dependency is configured in the runtime artifact of a Quarkus extension. In our example, it's the `quarkus-extension-a` that has a conditional dependency on `quarkus-extension-b`, which can be expressed in two ways. +NOTE: extensions with dependency conditions present in their metadata could still appear as regular dependencies in Maven `pom.xml` and Gradle build scripts. + +A conditional dependency is configured in the runtime artifact of a Quarkus extension. In this example, the `quarkus-extension-a` will declare a conditional dependency on the `quarkus-extension-b`, which can be done in the following two ways. === Declaring a dependency as `optional` -If an extension was configured with a dependency condition in its descriptor, other extensions may configure a conditional dependency on it by simply adding `true` to the dependency configuration. In our example it would look like this: +If an extension includes a dependency condition in its descriptor, other extensions may configure a conditional dependency on it by simply adding `true` to the dependency configuration. In our example it would look like this: [source,xml] ---- @@ -101,7 +103,9 @@ If an extension was configured with a dependency condition in its descriptor, ot <1> the runtime extension artifact `quarkus-extension-a` <2> declares an optional Maven dependency on the runtime extension artifact `quarkus-extension-b` -IMPORTANT: In general, for every runtime extension artifact dependency on another runtime extension artifact there must be a corresponding deployment extension artifact dependency on the other deployment extension artifact. And if the runtime dependency is declared as optional then the corresponding deployment dependency **must** also be configured as optional. +Given that `quarkus-extension-b` includes a dependency condition, Quarkus will interpret an optional dependency on the `quarkus-extension-b` as conditional. + +IMPORTANT: In general, for every runtime extension artifact dependency on another runtime extension artifact there must be the corresponding deployment extension artifact dependency on the other deployment extension artifact. And if the runtime dependency is declared as optional then the corresponding deployment dependency **must** also be configured as optional. [source,xml] ---- @@ -128,13 +132,11 @@ IMPORTANT: In general, for every runtime extension artifact dependency on anothe <1> the deployment extension artifact `quarkus-extension-a-deployment` <2> declares an optional Maven dependency on the deployment extension artifact `quarkus-extension-b-deployment` -Normally, optional Maven extension dependencies are ignored by the Quarkus dependency resolver at build time. In this case though, the optional dependency `quarkus-extension-b` includes a dependency condition in its extension descriptor, which turns this optional Maven dependency into a Quarkus conditional extension dependency. - -IMPORTANT: If `quarkus-extension-b` wasn't declared as `true` that would make `quarkus-extension-b` a required dependency of `quarkus-extension-a` and its dependency condition would be ignored. +IMPORTANT: If the `quarkus-extension-b` dependency wasn't declared as `true` it would make the `quarkus-extension-b` a required dependency of the `quarkus-extension-a` and its dependency condition would be ignored by the application dependency resolver. === Declaring a conditional dependency in the Quarkus extension descriptor -Conditional dependencies can also be configured in the Quarkus extension descriptor. The conditional dependency configured above could be expressed in the extension descriptor of `quarkus-extension-a` as: +Conditional dependencies can also be configured in the Quarkus extension descriptor directly. Here is an example of how it can be done in the Quarkus extension plugin configuration of the `quarkus-extension-a`: [source,xml] ---- @@ -171,10 +173,61 @@ Conditional dependencies can also be configured in the Quarkus extension descrip ---- +<1> the runtime Quarkus extension artifact ID; +<2> the goal that generates the extension descriptor which every Quarkus runtime extension project should be configured with; +<3> the conditional dependency configuration element; +<4> the artifact coordinates of conditional dependencies on other extensions. + +In this case, the Maven dependency is not at all required in the `pom.xml` file. + +== Dev mode-only extension dependencies + +Extensions can also declare conditional dependencies on other extensions using Dev mode as the condition or one of the conditions for those dependencies to be activated. + +Dev mode-only extension dependencies can be configured in the Quarkus extension plugin in the following way: + +[source,xml] +---- + + + + + quarkus-extension-a <1> + + + + + + + io.quarkus + quarkus-extension-maven-plugin + ${quarkus.version} + + + process-resources + + extension-descriptor <2> + + + <3> + org.acme:quarkus-extension-b:${b.version} <4> + + + + + + + +---- +<1> the runtime Quarkus extension artifact ID; +<2> the goal that generates the extension descriptor which every Quarkus runtime extension project should be configured with; +<3> the Dev mode conditional dependency configuration element; +<4> the artifact coordinates of conditional dependencies on extensions that should be evaluated only if an application is launched in Dev mode. + +The `quarkus-extension-b`, in this example, may or may not define its own condition to be evaluated. -<1> runtime Quarkus extension artifact ID, in our example `quarkus-extension-a` -<2> the goal that generates the extension descriptor which every Quarkus runtime extension project should be configured with -<3> conditional dependency configuration element -<4> artifact coordinates of conditional dependencies on other extensions. +If the `quarkus-extension-b` does not define a dependency condition on its own (there is no dependency condition recorded in its `META-INF/quarkus-extension.properties`), the `quarkus-extension-b` will only be added as a dependency of the `quarkus-extension-a` in Dev mode but not in other modes (prod or test). -In this case, the Maven dependency is not at all required in the `pom.xml`. +If the `quarkus-extension-b` does define a dependency condition on its own (a dependency condition recorded in its `META-INF/quarkus-extension.properties`), the `quarkus-extension-b` will be added as a dependency of the `quarkus-extension-a` in Dev mode only if its condition is satisfied (the artifacts it requires are present in the application dependency graph). \ No newline at end of file diff --git a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/BootstrapConstants.java b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/BootstrapConstants.java index c5c84b316922b..7155decb34766 100644 --- a/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/BootstrapConstants.java +++ b/independent-projects/bootstrap/app-model/src/main/java/io/quarkus/bootstrap/BootstrapConstants.java @@ -10,6 +10,7 @@ public interface BootstrapConstants { String SERIALIZED_TEST_APP_MODEL = "quarkus-internal-test.serialized-app-model.path"; String DESCRIPTOR_FILE_NAME = "quarkus-extension.properties"; String CONDITIONAL_DEPENDENCIES = "conditional-dependencies"; + String CONDITIONAL_DEV_DEPENDENCIES = "conditional-dev-dependencies"; String DEPENDENCY_CONDITION = "dependency-condition"; /** 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 d8861642c2171..e2e54d1c7c1a5 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,6 +18,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; +import io.quarkus.bootstrap.app.QuarkusBootstrap; import io.quarkus.bootstrap.resolver.maven.BootstrapMavenException; import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver; import io.quarkus.bootstrap.resolver.maven.MavenArtifactResolver; @@ -143,15 +144,24 @@ protected boolean cleanWorkDir() { return true; } - protected boolean isBootstrapForTestMode() { - return false; + protected QuarkusBootstrap.Mode getBootstrapMode() { + return QuarkusBootstrap.Mode.PROD; } protected BootstrapAppModelResolver newAppModelResolver(LocalProject currentProject) throws Exception { final BootstrapAppModelResolver appModelResolver = new BootstrapAppModelResolver(newArtifactResolver(currentProject)); appModelResolver.setIncubatingModelResolver(IncubatingApplicationModelResolver.isIncubatingEnabled(null)); - if (isBootstrapForTestMode()) { - appModelResolver.setTest(true); + switch (getBootstrapMode()) { + case PROD: + break; + case TEST: + appModelResolver.setTest(true); + break; + case DEV: + appModelResolver.setDevMode(true); + break; + default: + throw new IllegalArgumentException("Not supported bootstrap mode " + getBootstrapMode()); } return appModelResolver; } diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/TsQuarkusExt.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/TsQuarkusExt.java index f6374e54a47de..e5bc50e9a7489 100644 --- a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/TsQuarkusExt.java +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/TsQuarkusExt.java @@ -44,6 +44,16 @@ public TsQuarkusExt setConditionalDeps(TsQuarkusExt... exts) { return setDescriptorProp(BootstrapConstants.CONDITIONAL_DEPENDENCIES, buf.toString()); } + public TsQuarkusExt setConditionalDevDeps(TsQuarkusExt... exts) { + final StringBuilder buf = new StringBuilder(); + int i = 0; + buf.append(exts[i++].getRuntime().toString()); + while (i < exts.length) { + buf.append(' ').append(exts[i++].getRuntime().toString()); + } + return setDescriptorProp(BootstrapConstants.CONDITIONAL_DEV_DEPENDENCIES, buf.toString()); + } + public TsQuarkusExt setDependencyCondition(TsQuarkusExt... exts) { final StringBuilder buf = new StringBuilder(); int i = 0; diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesDevModelTestCase.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesDevModelTestCase.java new file mode 100644 index 0000000000000..20c22683e39fa --- /dev/null +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesDevModelTestCase.java @@ -0,0 +1,88 @@ +package io.quarkus.bootstrap.resolver.test; + +import io.quarkus.bootstrap.app.QuarkusBootstrap; +import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; +import io.quarkus.bootstrap.resolver.CollectDependenciesBase; +import io.quarkus.bootstrap.resolver.TsArtifact; +import io.quarkus.bootstrap.resolver.TsQuarkusExt; +import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; +import io.quarkus.maven.dependency.DependencyFlags; + +public class ConditionalDependenciesDevModelTestCase extends CollectDependenciesBase { + + @Override + protected BootstrapAppModelResolver newAppModelResolver(LocalProject currentProject) throws Exception { + var resolver = super.newAppModelResolver(currentProject); + resolver.setIncubatingModelResolver(false); + return resolver; + } + + @Override + protected QuarkusBootstrap.Mode getBootstrapMode() { + return QuarkusBootstrap.Mode.DEV; + } + + @Override + protected void setupDependencies() { + + final TsQuarkusExt extA = new TsQuarkusExt("ext-a"); + install(extA, false); + addCollectedDeploymentDep(extA.getDeployment()); + + installAsDep(extA.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + + final TsQuarkusExt extB = new TsQuarkusExt("ext-b"); + install(extB, false); + addCollectedDep(extB.getRuntime(), DependencyFlags.RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extB.getDeployment()); + + final TsQuarkusExt extC = new TsQuarkusExt("ext-c"); + extC.setDependencyCondition(extB); + install(extC, false); + addCollectedDep(extC.getRuntime(), DependencyFlags.RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extC.getDeployment()); + + final TsQuarkusExt extD = new TsQuarkusExt("ext-d"); + install(extD, false); + installAsDep(extD.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extD.getDeployment()); + + final TsArtifact libE = TsArtifact.jar("lib-e"); + install(libE, true); + final TsArtifact libEBuildTIme = TsArtifact.jar("lib-e-build-time"); + install(libEBuildTIme); + addCollectedDeploymentDep(libEBuildTIme); + + final TsQuarkusExt extE = new TsQuarkusExt("ext-e"); + extE.setDependencyCondition(extD); + extE.getRuntime().addDependency(libE); + extE.getDeployment().addDependency(libEBuildTIme); + install(extE, false); + addCollectedDep(extE.getRuntime(), DependencyFlags.RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extE.getDeployment()); + + final TsQuarkusExt extF = new TsQuarkusExt("ext-f"); + extF.setConditionalDeps(extC, extE); + install(extF, false); + installAsDep(extF.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extF.getDeployment()); + + final TsQuarkusExt extG = new TsQuarkusExt("ext-g"); + extG.setConditionalDevDeps(extB); + install(extG, false); + installAsDep(extG.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extG.getDeployment()); + } +} diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesProdModelTestCase.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesProdModelTestCase.java new file mode 100644 index 0000000000000..7a470e4f666cc --- /dev/null +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesProdModelTestCase.java @@ -0,0 +1,78 @@ +package io.quarkus.bootstrap.resolver.test; + +import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; +import io.quarkus.bootstrap.resolver.CollectDependenciesBase; +import io.quarkus.bootstrap.resolver.TsArtifact; +import io.quarkus.bootstrap.resolver.TsQuarkusExt; +import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; +import io.quarkus.maven.dependency.DependencyFlags; + +public class ConditionalDependenciesProdModelTestCase extends CollectDependenciesBase { + + @Override + protected BootstrapAppModelResolver newAppModelResolver(LocalProject currentProject) throws Exception { + var resolver = super.newAppModelResolver(currentProject); + resolver.setIncubatingModelResolver(false); + return resolver; + } + + @Override + protected void setupDependencies() { + + final TsQuarkusExt extA = new TsQuarkusExt("ext-a"); + install(extA, false); + addCollectedDeploymentDep(extA.getDeployment()); + + installAsDep(extA.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + + final TsQuarkusExt extB = new TsQuarkusExt("ext-b"); + install(extB, false); + + final TsQuarkusExt extC = new TsQuarkusExt("ext-c"); + extC.setDependencyCondition(extB); + install(extC, false); + + final TsQuarkusExt extD = new TsQuarkusExt("ext-d"); + install(extD, false); + installAsDep(extD.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extD.getDeployment()); + + final TsArtifact libE = TsArtifact.jar("lib-e"); + install(libE, true); + final TsArtifact libEBuildTIme = TsArtifact.jar("lib-e-build-time"); + install(libEBuildTIme); + addCollectedDeploymentDep(libEBuildTIme); + + final TsQuarkusExt extE = new TsQuarkusExt("ext-e"); + extE.setDependencyCondition(extD); + extE.getRuntime().addDependency(libE); + extE.getDeployment().addDependency(libEBuildTIme); + install(extE, false); + addCollectedDep(extE.getRuntime(), DependencyFlags.RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extE.getDeployment()); + + final TsQuarkusExt extF = new TsQuarkusExt("ext-f"); + extF.setConditionalDeps(extC, extE); + install(extF, false); + installAsDep(extF.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extF.getDeployment()); + + final TsQuarkusExt extG = new TsQuarkusExt("ext-g"); + extG.setConditionalDevDeps(extB); + install(extG, false); + installAsDep(extG.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extG.getDeployment()); + } +} diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/RuntimeOnlyApplicationModelTestCase.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesRuntimeOnlyProdModelTestCase.java similarity index 96% rename from independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/RuntimeOnlyApplicationModelTestCase.java rename to independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesRuntimeOnlyProdModelTestCase.java index f0ddf15c9ede3..cf246b9a85f2f 100644 --- a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/RuntimeOnlyApplicationModelTestCase.java +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/ConditionalDependenciesRuntimeOnlyProdModelTestCase.java @@ -7,7 +7,7 @@ import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; import io.quarkus.maven.dependency.DependencyFlags; -public class RuntimeOnlyApplicationModelTestCase extends CollectDependenciesBase { +public class ConditionalDependenciesRuntimeOnlyProdModelTestCase extends CollectDependenciesBase { private static final boolean runtimeOnly = true; diff --git a/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/DevModeConditionalDependencyWithExtraConditionTestCase.java b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/DevModeConditionalDependencyWithExtraConditionTestCase.java new file mode 100644 index 0000000000000..77ecac97bf92f --- /dev/null +++ b/independent-projects/bootstrap/core/src/test/java/io/quarkus/bootstrap/resolver/test/DevModeConditionalDependencyWithExtraConditionTestCase.java @@ -0,0 +1,63 @@ +package io.quarkus.bootstrap.resolver.test; + +import io.quarkus.bootstrap.app.QuarkusBootstrap; +import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver; +import io.quarkus.bootstrap.resolver.CollectDependenciesBase; +import io.quarkus.bootstrap.resolver.TsQuarkusExt; +import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject; +import io.quarkus.maven.dependency.DependencyFlags; + +public class DevModeConditionalDependencyWithExtraConditionTestCase extends CollectDependenciesBase { + + @Override + protected BootstrapAppModelResolver newAppModelResolver(LocalProject currentProject) throws Exception { + var resolver = super.newAppModelResolver(currentProject); + resolver.setIncubatingModelResolver(false); + return resolver; + } + + @Override + protected QuarkusBootstrap.Mode getBootstrapMode() { + return QuarkusBootstrap.Mode.DEV; + } + + @Override + protected void setupDependencies() { + + final TsQuarkusExt extA = new TsQuarkusExt("ext-a"); + install(extA, false); + addCollectedDeploymentDep(extA.getDeployment()); + + installAsDep(extA.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + + final TsQuarkusExt extB = new TsQuarkusExt("ext-b"); + install(extB, false); + addCollectedDep(extB.getRuntime(), DependencyFlags.RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extB.getDeployment()); + + final TsQuarkusExt extC = new TsQuarkusExt("ext-c"); + extC.setDependencyCondition(extA); + install(extC, false); + addCollectedDep(extC.getRuntime(), DependencyFlags.RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extC.getDeployment()); + + final TsQuarkusExt extD = new TsQuarkusExt("ext-d"); + install(extD, false); + + final TsQuarkusExt extE = new TsQuarkusExt("ext-e"); + extE.setDependencyCondition(extD); + install(extE, false); + + final TsQuarkusExt extG = new TsQuarkusExt("ext-g"); + extG.setConditionalDevDeps(extB, extC, extE); + install(extG, false); + installAsDep(extG.getRuntime(), + DependencyFlags.DIRECT + | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT + | DependencyFlags.TOP_LEVEL_RUNTIME_EXTENSION_ARTIFACT); + addCollectedDeploymentDep(extG.getDeployment()); + } +} 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 d0f1b3a3139f9..2bc13f5a18ccd 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 @@ -378,6 +378,7 @@ private ApplicationModel buildAppModel(ResolvedDependencyBuilder appArtifact, .setCollectCompileOnly(filteredProvidedDeps) .setDependencyLogging(depLogConfig) .setRuntimeModelOnly(runtimeModelOnly) + .setDevMode(devmode) .resolve(collectRtDepsRequest); } else { ApplicationDependencyTreeResolver.newInstance() @@ -387,6 +388,7 @@ private ApplicationModel buildAppModel(ResolvedDependencyBuilder appArtifact, .setCollectCompileOnly(filteredProvidedDeps) .setBuildTreeConsumer(depLogConfig == null ? null : depLogConfig.getMessageConsumer()) .setRuntimeModelOnly(runtimeModelOnly) + .setDevMode(devmode) .resolve(collectRtDepsRequest); } if (logTime) { diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java index e65df264dbdac..6505fab69b4cd 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/ApplicationDependencyTreeResolver.java @@ -2,7 +2,6 @@ import static io.quarkus.bootstrap.util.DependencyUtils.getKey; import static io.quarkus.bootstrap.util.DependencyUtils.newDependencyBuilder; -import static io.quarkus.bootstrap.util.DependencyUtils.toArtifact; import java.io.BufferedReader; import java.io.IOException; @@ -52,10 +51,8 @@ import io.quarkus.bootstrap.BootstrapConstants; import io.quarkus.bootstrap.BootstrapDependencyProcessingException; import io.quarkus.bootstrap.model.ApplicationModelBuilder; -import io.quarkus.bootstrap.model.CapabilityContract; import io.quarkus.bootstrap.model.PlatformImportsImpl; import io.quarkus.bootstrap.resolver.AppModelResolverException; -import io.quarkus.bootstrap.util.BootstrapUtils; import io.quarkus.bootstrap.util.DependencyUtils; import io.quarkus.bootstrap.util.PropertyUtils; import io.quarkus.bootstrap.workspace.WorkspaceModule; @@ -107,6 +104,7 @@ public static Artifact getRuntimeArtifact(DependencyNode dep) { private Consumer buildTreeConsumer; private List collectCompileOnly; private boolean runtimeModelOnly; + private boolean devMode; public ApplicationDependencyTreeResolver setArtifactResolver(MavenArtifactResolver resolver) { this.resolver = resolver; @@ -140,11 +138,28 @@ public ApplicationDependencyTreeResolver setCollectCompileOnly(List return this; } + /** + * Whether to limit the resulting {@link io.quarkus.bootstrap.model.ApplicationModel} to the runtime dependencies. + * + * @param runtimeModelOnly whether to limit the resulting application model to the runtime dependencies + * @return self + */ public ApplicationDependencyTreeResolver setRuntimeModelOnly(boolean runtimeModelOnly) { this.runtimeModelOnly = runtimeModelOnly; return this; } + /** + * Whether an application model is resolved for dev mode + * + * @param devMode whether an application model is resolved for dev mode + * @return self + */ + public ApplicationDependencyTreeResolver setDevMode(boolean devMode) { + this.devMode = devMode; + return this; + } + public void resolve(CollectRequest collectRtDepsRequest) throws AppModelResolverException { this.managedDeps = collectRtDepsRequest.getManagedDependencies(); @@ -473,7 +488,7 @@ private void visitRuntimeDependency(DependencyNode node) { clearWalkingFlag(COLLECT_DIRECT_DEPS); if (extDep != null) { - extDep.info.ensureActivated(); + extDep.info.ensureActivated(appBuilder); visitExtensionDependency(extDep); } visitRuntimeDependencies(node.getChildren()); @@ -584,7 +599,7 @@ private ExtensionInfo getExtensionInfoOrNull(Artifact artifact, List boolean contains(T[] arr, T item) { + for (int i = 0; i < arr.length; ++i) { + if (item.equals(arr[i])) { + return true; + } + } + return false; + } + + private static String toCompactCoords(Artifact a) { + final StringBuilder b = new StringBuilder(); + b.append(a.getGroupId()).append(':').append(a.getArtifactId()).append(':'); + if (!a.getClassifier().isEmpty()) { + b.append(a.getClassifier()).append(':'); + } + if (!ArtifactCoords.TYPE_JAR.equals(a.getExtension())) { + b.append(a.getExtension()).append(':'); + } + b.append(a.getVersion()); + return b.toString(); + } +} diff --git a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java index 747c976b5eda3..95e1a93821119 100644 --- a/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java +++ b/independent-projects/bootstrap/maven-resolver/src/main/java/io/quarkus/bootstrap/resolver/maven/IncubatingApplicationModelResolver.java @@ -5,7 +5,6 @@ import static io.quarkus.bootstrap.util.DependencyUtils.getWinner; import static io.quarkus.bootstrap.util.DependencyUtils.hasWinner; import static io.quarkus.bootstrap.util.DependencyUtils.newDependencyBuilder; -import static io.quarkus.bootstrap.util.DependencyUtils.toArtifact; import java.io.BufferedReader; import java.io.IOException; @@ -51,10 +50,8 @@ import io.quarkus.bootstrap.BootstrapConstants; import io.quarkus.bootstrap.BootstrapDependencyProcessingException; import io.quarkus.bootstrap.model.ApplicationModelBuilder; -import io.quarkus.bootstrap.model.CapabilityContract; import io.quarkus.bootstrap.model.PlatformImportsImpl; import io.quarkus.bootstrap.resolver.AppModelResolverException; -import io.quarkus.bootstrap.util.BootstrapUtils; import io.quarkus.bootstrap.util.DependencyUtils; import io.quarkus.bootstrap.workspace.WorkspaceModule; import io.quarkus.maven.dependency.ArtifactCoords; @@ -140,6 +137,7 @@ public static IncubatingApplicationModelResolver newInstance() { private DependencyLoggingConfig depLogging; private List collectCompileOnly; private boolean runtimeModelOnly; + private boolean devMode; public IncubatingApplicationModelResolver setArtifactResolver(MavenArtifactResolver resolver) { this.resolver = resolver; @@ -173,11 +171,28 @@ public IncubatingApplicationModelResolver setCollectCompileOnly(List return this; } + /** + * Whether to limit the resulting {@link io.quarkus.bootstrap.model.ApplicationModel} to the runtime dependencies. + * + * @param runtimeModelOnly whether to limit the resulting application model to the runtime dependencies + * @return self + */ public IncubatingApplicationModelResolver setRuntimeModelOnly(boolean runtimeModelOnly) { this.runtimeModelOnly = runtimeModelOnly; return this; } + /** + * Whether an application model is resolved for dev mode + * + * @param devMode whether an application model is resolved for dev mode + * @return self + */ + public IncubatingApplicationModelResolver setDevMode(boolean devMode) { + this.devMode = devMode; + return this; + } + public void resolve(CollectRequest collectRtDepsRequest) throws AppModelResolverException { this.managedDeps = collectRtDepsRequest.getManagedDependencies(); // managed dependencies will be a bit augmented with every added extension, so let's load the properties early @@ -610,7 +625,7 @@ void setFlags(byte walkingFlags) { } parentExtDep = parentExtDep.parent; } - ext.info.ensureActivated(); + ext.info.ensureActivated(appBuilder); } var existingDep = appBuilder.getDependency(resolvedDep.getKey()); @@ -758,7 +773,7 @@ private ExtensionInfo getExtensionInfoOrNull(Artifact artifact, List depth = new ArrayList<>(); diff --git a/independent-projects/extension-maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java b/independent-projects/extension-maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java index 3f31cf926c925..27acf1122cb66 100644 --- a/independent-projects/extension-maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java +++ b/independent-projects/extension-maven-plugin/src/main/java/io/quarkus/maven/ExtensionDescriptorMojo.java @@ -220,6 +220,13 @@ public static class RemovedResources { @Parameter private List conditionalDependencies = new ArrayList<>(0); + /** + * Conditional dependencies that should be + * enabled in case an application is launched in dev mode and certain classpath conditions have been satisfied. + */ + @Parameter + private List conditionalDevDependencies = new ArrayList<>(0); + /** * Extension dependency condition that should be * satisfied for this extension to be enabled @@ -469,15 +476,8 @@ private void recordCapabilities(Properties props) { private void recordConditionalDeps(Properties props) { lookForConditionalDeps(); - if (!conditionalDependencies.isEmpty()) { - final StringBuilder buf = new StringBuilder(); - int i = 0; - buf.append(ArtifactCoords.fromString(conditionalDependencies.get(i++))); - while (i < conditionalDependencies.size()) { - buf.append(' ').append(ArtifactCoords.fromString(conditionalDependencies.get(i++))); - } - props.setProperty(BootstrapConstants.CONDITIONAL_DEPENDENCIES, buf.toString()); - } + setConditionalDepsProperty(props, BootstrapConstants.CONDITIONAL_DEPENDENCIES, conditionalDependencies); + setConditionalDepsProperty(props, BootstrapConstants.CONDITIONAL_DEV_DEPENDENCIES, conditionalDevDependencies); if (!dependencyCondition.isEmpty()) { final StringBuilder buf = new StringBuilder(); int i = 0; @@ -486,8 +486,20 @@ private void recordConditionalDeps(Properties props) { buf.append(' ').append(ArtifactKey.fromString(dependencyCondition.get(i++)).toGacString()); } props.setProperty(BootstrapConstants.DEPENDENCY_CONDITION, buf.toString()); + } + } + private void setConditionalDepsProperty(Properties props, String propertyName, List list) { + if (list.isEmpty()) { + return; + } + final StringBuilder buf = new StringBuilder(); + int i = 0; + buf.append(ArtifactCoords.fromString(list.get(i++))); + while (i < list.size()) { + buf.append(' ').append(ArtifactCoords.fromString(list.get(i++))); } + props.setProperty(propertyName, buf.toString()); } private void lookForConditionalDeps() {