Skip to content

Commit

Permalink
Merge pull request quarkusio#44666 from aloubyansky/amazon-services-c…
Browse files Browse the repository at this point in the history
…onditional-dep

Fix conditional dependency resolution when runtime-deployment dependencies are not mirrored
  • Loading branch information
aloubyansky authored Nov 25, 2024
2 parents fc548b3 + 5e9bef3 commit 192a870
Show file tree
Hide file tree
Showing 13 changed files with 502 additions and 211 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,23 @@
import java.util.HashMap;

import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.bootstrap.resolver.BootstrapAppModelResolver;
import io.quarkus.bootstrap.resolver.TsArtifact;
import io.quarkus.bootstrap.resolver.TsQuarkusExt;
import io.quarkus.bootstrap.resolver.maven.IncubatingApplicationModelResolver;
import io.quarkus.bootstrap.resolver.maven.workspace.LocalProject;
import io.quarkus.deployment.runnerjar.BootstrapFromOriginalJarTestBase;
import io.quarkus.maven.dependency.ResolvedDependency;

public class DependencyConditionMatchesConditionalDependencyTest extends BootstrapFromOriginalJarTestBase {

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

@Override
protected TsArtifact composeApplication() {

Expand Down
12 changes: 6 additions & 6 deletions docs/src/main/asciidoc/conditional-extension-dependencies.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ A Quarkus extension may declare one or more conditional dependencies on other Qu

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 `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:
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]
----
Expand Down Expand Up @@ -182,7 +182,7 @@ 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.
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:

Expand Down Expand Up @@ -223,11 +223,11 @@ Dev mode-only extension dependencies can be configured in the Quarkus extension
----
<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.
<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.

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).
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).

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).
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).
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.function.Supplier;

import org.apache.maven.model.DependencyManagement;
import org.apache.maven.model.Model;
Expand Down Expand Up @@ -139,6 +138,10 @@ public TsArtifact addDependency(TsArtifact dep) {
return addDependency(new TsDependency(dep));
}

public TsArtifact addDependency(TsArtifact dep, boolean optional) {
return addDependency(new TsDependency(dep, optional));
}

public TsArtifact addDependency(TsArtifact dep, TsArtifact... excludes) {
return addDependency(new TsDependency(dep).exclude(excludes));
}
Expand All @@ -152,23 +155,23 @@ public TsArtifact addDependency(TsQuarkusExt dep, String scope) {
}

public TsArtifact addDependency(TsQuarkusExt dep, boolean optional) {
return addDependency(dep, () -> new TsDependency(dep.getRuntime(), optional));
return addDependency(dep, new TsDependency(dep.getRuntime(), optional));
}

public TsArtifact addDependency(TsQuarkusExt dep, String scope, boolean optional) {
return addDependency(dep, () -> new TsDependency(dep.getRuntime(), scope, optional));
return addDependency(dep, new TsDependency(dep.getRuntime(), scope, optional));
}

public TsArtifact addDependency(TsQuarkusExt dep, TsArtifact... excludes) {
return addDependency(dep, () -> new TsDependency(dep.getRuntime(), false).exclude(excludes));
return addDependency(dep, new TsDependency(dep.getRuntime(), false).exclude(excludes));
}

private TsArtifact addDependency(TsQuarkusExt dep, Supplier<TsDependency> dependencyFactory) {
private TsArtifact addDependency(TsQuarkusExt extDep, TsDependency dep) {
if (extDeps.isEmpty()) {
extDeps = new ArrayList<>(1);
}
extDeps.add(dep);
return addDependency(dependencyFactory.get());
extDeps.add(extDep);
return addDependency(dep);
}

public TsArtifact addDependency(TsDependency dep) {
Expand All @@ -179,6 +182,33 @@ public TsArtifact addDependency(TsDependency dep) {
return this;
}

/**
* Adds a dependency as the first in the list.
*
* @param dep dependency to add
* @return this artifact
*/
public TsArtifact addFirstDependency(TsDependency dep) {
if (deps.isEmpty()) {
deps = new ArrayList<>();
deps.add(dep);
} else {
deps.add(dep);
Collections.rotate(deps, 1);
}
return this;
}

/**
* Adds a dependency as the first in the list.
*
* @param dep dependency to add
* @return this artifact
*/
public TsArtifact addFirstDependency(TsArtifact dep) {
return addFirstDependency(new TsDependency(dep));
}

public TsArtifact addManagedDependency(TsArtifact a) {
return addManagedDependency(new TsDependency(a));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,16 @@ public TsQuarkusExt setDependencyCondition(TsQuarkusExt... exts) {
return setDescriptorProp(BootstrapConstants.DEPENDENCY_CONDITION, buf.toString());
}

public TsQuarkusExt setDependencyCondition(TsArtifact... exts) {
final StringBuilder buf = new StringBuilder();
int i = 0;
buf.append(exts[i++].getKey());
while (i < exts.length) {
buf.append(' ').append(exts[i++].getKey());
}
return setDescriptorProp(BootstrapConstants.DEPENDENCY_CONDITION, buf.toString());
}

public TsQuarkusExt setDescriptorProp(String name, String value) {
rtDescr.set(name, value);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class ConditionalDependenciesDevModelTestCase extends CollectDependencies
@Override
protected BootstrapAppModelResolver newAppModelResolver(LocalProject currentProject) throws Exception {
var resolver = super.newAppModelResolver(currentProject);
resolver.setIncubatingModelResolver(false);
//resolver.setIncubatingModelResolver(false);
return resolver;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
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 ConditionalDependenciesDirectDependencyOnTransitiveDeploymentArtifactTestCase extends CollectDependenciesBase {

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

@Override
protected void setupDependencies() {

final TsQuarkusExt quarkusCore = new TsQuarkusExt("quarkus-core");
install(quarkusCore);

TsArtifact nettyNioClient = TsArtifact.jar("netty-nio-client");

final TsQuarkusExt nettyClientInternalExt = new TsQuarkusExt("netty-client-internal");
nettyClientInternalExt.addDependency(quarkusCore);
nettyClientInternalExt.getRuntime().addDependency(nettyNioClient, true);
nettyClientInternalExt.setDependencyCondition(nettyNioClient);
install(nettyClientInternalExt, false);
addCollectedDep(nettyClientInternalExt.getRuntime(),
DependencyFlags.RUNTIME_CP | DependencyFlags.DEPLOYMENT_CP | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT);
addCollectedDeploymentDep(nettyClientInternalExt.getDeployment());

final TsQuarkusExt commonExt = new TsQuarkusExt("common");
commonExt.addDependency(quarkusCore);
commonExt.getRuntime().addDependency(nettyNioClient, true);
commonExt.getRuntime().addDependency(nettyClientInternalExt.getRuntime(), true);
commonExt.getDeployment().addDependency(nettyClientInternalExt.getDeployment(), true);
commonExt.setConditionalDeps(nettyClientInternalExt);
install(commonExt, false);
addCollectedDep(commonExt.getRuntime(),
DependencyFlags.RUNTIME_CP | DependencyFlags.DEPLOYMENT_CP | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT);
addCollectedDeploymentDep(commonExt.getDeployment());

final TsQuarkusExt sqsExt = new TsQuarkusExt("sqs");
sqsExt.addDependency(quarkusCore);
sqsExt.getRuntime().addDependency(commonExt.getRuntime());
sqsExt.getRuntime().addDependency(nettyNioClient, true);
sqsExt.getDeployment().addFirstDependency(commonExt.getDeployment());
addCollectedDep(sqsExt.getRuntime(),
DependencyFlags.RUNTIME_CP | DependencyFlags.DEPLOYMENT_CP | DependencyFlags.RUNTIME_EXTENSION_ARTIFACT);
addCollectedDeploymentDep(sqsExt.getDeployment());

final TsQuarkusExt messagingSqsExt = new TsQuarkusExt("messaging-sqs");
messagingSqsExt.addDependency(quarkusCore);
messagingSqsExt.addDependency(sqsExt);
messagingSqsExt.getDeployment().addDependency(commonExt.getDeployment()); // this line breaks it

installAsDep(messagingSqsExt);
installAsDep(nettyNioClient);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class ConditionalDependenciesProdModelTestCase extends CollectDependencie
@Override
protected BootstrapAppModelResolver newAppModelResolver(LocalProject currentProject) throws Exception {
var resolver = super.newAppModelResolver(currentProject);
resolver.setIncubatingModelResolver(false);
//resolver.setIncubatingModelResolver(false);
return resolver;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public class ConditionalDependenciesRuntimeOnlyProdModelTestCase extends Collect
@Override
protected BootstrapAppModelResolver newAppModelResolver(LocalProject currentProject) throws Exception {
var resolver = super.newAppModelResolver(currentProject);
resolver.setIncubatingModelResolver(false);
//resolver.setIncubatingModelResolver(false);
resolver.setRuntimeModelOnly(runtimeOnly);
return resolver;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class DevModeConditionalDependencyWithExtraConditionTestCase extends Coll
@Override
protected BootstrapAppModelResolver newAppModelResolver(LocalProject currentProject) throws Exception {
var resolver = super.newAppModelResolver(currentProject);
resolver.setIncubatingModelResolver(false);
//resolver.setIncubatingModelResolver(false);
return resolver;
}

Expand Down
Loading

0 comments on commit 192a870

Please sign in to comment.