Skip to content

Commit 9bba02a

Browse files
committed
Manually enforce platform constraints for conditional dependencies in QuarkusComponentVariants
Addresses #49743
1 parent c3944a9 commit 9bba02a

File tree

31 files changed

+781
-42
lines changed

31 files changed

+781
-42
lines changed

devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/ApplicationDeploymentClasspathBuilder.java

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.gradle.api.internal.tasks.TaskDependencyFactory;
3030
import org.gradle.api.plugins.JavaPlugin;
3131
import org.gradle.api.provider.ListProperty;
32+
import org.gradle.api.provider.Property;
3233

3334
import io.quarkus.bootstrap.BootstrapConstants;
3435
import io.quarkus.bootstrap.model.PlatformImports;
@@ -38,6 +39,7 @@
3839
import io.quarkus.gradle.tooling.dependency.DependencyUtils;
3940
import io.quarkus.gradle.tooling.dependency.ExtensionDependency;
4041
import io.quarkus.maven.dependency.ArtifactCoords;
42+
import io.quarkus.maven.dependency.ArtifactKey;
4143
import io.quarkus.runtime.LaunchMode;
4244

4345
public class ApplicationDeploymentClasspathBuilder {
@@ -93,13 +95,14 @@ public static void initConfigurations(Project project) {
9395
final ConfigurationContainer configContainer = project.getConfigurations();
9496

9597
// Custom configuration for dev mode
96-
configContainer.register(ToolingUtils.DEV_MODE_CONFIGURATION_NAME, config -> {
97-
config.extendsFrom(configContainer.getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME));
98-
config.setCanBeConsumed(false);
99-
if (!isDisableComponentVariants(project)) {
100-
QuarkusComponentVariants.setConditionalAttributes(config, project, LaunchMode.DEVELOPMENT);
101-
}
102-
});
98+
configContainer
99+
.register(ToolingUtils.DEV_MODE_CONFIGURATION_NAME, config -> {
100+
config.extendsFrom(configContainer.getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME));
101+
config.setCanBeConsumed(false);
102+
if (!isDisableComponentVariants(project)) {
103+
QuarkusComponentVariants.setConditionalAttributes(config, project, LaunchMode.DEVELOPMENT);
104+
}
105+
});
103106

104107
// Base runtime configurations for every launch mode
105108
configContainer
@@ -178,6 +181,7 @@ private static Configuration[] getOriginalRuntimeClasspaths(Project project, Lau
178181
private final String platformImportName;
179182

180183
private final List<Dependency> platformDataDeps = new ArrayList<>();
184+
private final Map<ArtifactKey, PlatformSpec.Constraint> platformConstraints = new HashMap<>();
181185

182186
public ApplicationDeploymentClasspathBuilder(Project project, LaunchMode mode,
183187
TaskDependencyFactory taskDependencyFactory) {
@@ -239,6 +243,13 @@ private void setUpPlatformConfiguration() {
239243
break;
240244
}
241245
}
246+
} else {
247+
ArtifactKey artifactKey = ArtifactKey.ga(d.getTarget().getGroup(), name);
248+
platformConstraints.computeIfAbsent(artifactKey,
249+
k -> new PlatformSpec.Constraint(
250+
d.getTarget().getGroup(),
251+
name,
252+
d.getTarget().getVersion()));
242253
}
243254
});
244255
});
@@ -276,14 +287,22 @@ private List<Dependency> resolvePlatformDependencies() {
276287
return platformDataDeps;
277288
}
278289

290+
private PlatformSpec resolvePlatformSpec() {
291+
getPlatformConfiguration().resolve();
292+
return new PlatformSpec(platformConstraints, getPlatformConfiguration().getExcludeRules());
293+
}
294+
279295
private void setUpRuntimeConfiguration() {
280296
if (!project.getConfigurations().getNames().contains(this.runtimeConfigurationName)) {
281297
final String baseConfig;
282298
final boolean disableComponentVariants = isDisableComponentVariants(project);
283299
if (disableComponentVariants) {
284300
baseConfig = ApplicationDeploymentClasspathBuilder.getBaseRuntimeConfigName(mode);
285301
} else {
286-
QuarkusComponentVariants.addVariants(project, mode);
302+
Property<PlatformSpec> platformSpecProperty = project.getObjects()
303+
.property(PlatformSpec.class);
304+
QuarkusComponentVariants.addVariants(project, mode,
305+
platformSpecProperty.value(project.provider(this::resolvePlatformSpec)));
287306
baseConfig = QuarkusComponentVariants.getConditionalConfigurationName(mode);
288307
}
289308
project.getConfigurations().register(this.runtimeConfigurationName, configuration -> {
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package io.quarkus.gradle.dependency;
2+
3+
import java.util.Map;
4+
import java.util.Set;
5+
6+
import org.gradle.api.artifacts.ExcludeRule;
7+
8+
import io.quarkus.maven.dependency.ArtifactKey;
9+
10+
class PlatformSpec {
11+
private final Map<ArtifactKey, Constraint> constraints;
12+
private final Set<ExcludeRule> exclusions;
13+
14+
public PlatformSpec(Map<ArtifactKey, Constraint> constraints, Set<ExcludeRule> exclusions) {
15+
this.constraints = constraints;
16+
this.exclusions = exclusions;
17+
}
18+
19+
public Map<ArtifactKey, Constraint> getConstraints() {
20+
return constraints;
21+
}
22+
23+
public Set<ExcludeRule> getExclusions() {
24+
return exclusions;
25+
}
26+
27+
static class Constraint {
28+
private final String groupId;
29+
private final String artifactId;
30+
private final String version;
31+
32+
public Constraint(String groupId, String artifactId, String version) {
33+
this.groupId = groupId;
34+
this.artifactId = artifactId;
35+
this.version = version;
36+
}
37+
38+
public String getGroupId() {
39+
return groupId;
40+
}
41+
42+
public String getArtifactId() {
43+
return artifactId;
44+
}
45+
46+
public String getVersion() {
47+
return version;
48+
}
49+
}
50+
}

devtools/gradle/gradle-model/src/main/java/io/quarkus/gradle/dependency/QuarkusComponentVariants.java

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import java.util.HashSet;
99
import java.util.List;
1010
import java.util.Map;
11+
import java.util.Optional;
1112
import java.util.Set;
1213
import java.util.concurrent.atomic.AtomicInteger;
1314

@@ -28,6 +29,7 @@
2829
import org.gradle.api.attributes.java.TargetJvmEnvironment;
2930
import org.gradle.api.model.ObjectFactory;
3031
import org.gradle.api.provider.ListProperty;
32+
import org.gradle.api.provider.Property;
3133

3234
import io.quarkus.gradle.tooling.dependency.DependencyUtils;
3335
import io.quarkus.gradle.tooling.dependency.ExtensionDependency;
@@ -169,22 +171,26 @@ public static void setCommonAttributes(AttributeContainer attrs, ObjectFactory o
169171
* @param project project
170172
* @param mode launch mode
171173
*/
172-
public static void addVariants(Project project, LaunchMode mode) {
173-
new QuarkusComponentVariants(project, mode).configureAndAddVariants();
174+
public static void addVariants(Project project, LaunchMode mode,
175+
Property<PlatformSpec> platformSpecProperty) {
176+
new QuarkusComponentVariants(project, mode, platformSpecProperty).configureAndAddVariants();
174177
}
175178

176179
private final Attribute<String> quarkusDepAttr;
177180
private final Project project;
181+
private final Property<PlatformSpec> platformSpecProperty;
178182
private final Map<ArtifactKey, ProcessedDependency> processedDeps = new HashMap<>();
179183
private final Map<ArtifactKey, ConditionalDependency> allConditionalDeps = new HashMap<>();
180184
private final List<ConditionalDependencyVariant> dependencyVariantQueue = new ArrayList<>();
181185
private final Map<String, SatisfiedExtensionDeps> satisfiedExtensionDeps = new HashMap<>();
182186
private final LaunchMode mode;
183187
private final AtomicInteger configCopyCounter = new AtomicInteger();
184188

185-
private QuarkusComponentVariants(Project project, LaunchMode mode) {
189+
private QuarkusComponentVariants(Project project, LaunchMode mode,
190+
Property<PlatformSpec> platformSpecProperty) {
186191
this.project = project;
187192
this.mode = mode;
193+
this.platformSpecProperty = platformSpecProperty;
188194
this.quarkusDepAttr = getConditionalDependencyAttribute(project.getName(), mode);
189195
project.getDependencies().getAttributesSchema().attribute(quarkusDepAttr);
190196
project.getDependencies().getAttributesSchema().attribute(getDeploymentDependencyAttribute(project.getName(), mode));
@@ -407,7 +413,10 @@ private void processDependency(ProcessedDependency parent,
407413
}
408414

409415
private void queueConditionalDependency(ProcessedDependency parent, Dependency dep) {
410-
dependencyVariantQueue.add(new ConditionalDependencyVariant(parent.extension, getOrCreateConditionalDep(dep)));
416+
var conditionalDep = getOrCreateConditionalDep(dep);
417+
if (conditionalDep != null) {
418+
dependencyVariantQueue.add(new ConditionalDependencyVariant(parent.extension, conditionalDep));
419+
}
411420
}
412421

413422
private ConditionalDependency getOrCreateConditionalDep(Dependency dep) {
@@ -417,7 +426,7 @@ private ConditionalDependency getOrCreateConditionalDep(Dependency dep) {
417426
}
418427

419428
private ResolvedArtifact tryResolvingRelocationArtifact(Dependency dep) {
420-
final Configuration configForRelocated = project.getConfigurations().detachedConfiguration(dep).setTransitive(true);
429+
final Configuration configForRelocated = getDetachedWithExclusions(dep).setTransitive(true);
421430
setConditionalAttributes(configForRelocated, project, mode);
422431

423432
var firstLevelDeps = configForRelocated.getResolvedConfiguration().getFirstLevelModuleDependencies();
@@ -447,8 +456,10 @@ private ResolvedArtifact tryResolvingRelocationArtifact(Dependency dep) {
447456
return artifact;
448457
}
449458

450-
private ConditionalDependency newConditionalDep(Dependency dep) {
451-
final Configuration config = project.getConfigurations().detachedConfiguration(dep).setTransitive(false);
459+
private ConditionalDependency newConditionalDep(Dependency originalDep) {
460+
var dep = getConstrainedDep(originalDep);
461+
final Configuration config = getDetachedWithExclusions(dep).setTransitive(false);
462+
452463
setConditionalAttributes(config, project, mode);
453464
ResolvedArtifact resolvedArtifact = null;
454465

@@ -464,6 +475,11 @@ private ConditionalDependency newConditionalDep(Dependency dep) {
464475
}
465476

466477
if (resolvedArtifact == null) {
478+
// check if that's due to exclude rules, and if yes, ignore
479+
if (isExplicitlyExcluded(dep)) {
480+
project.getLogger().info("Conditional dependency {} ignored due to exclusion rule", dep);
481+
return null;
482+
}
467483
throw new RuntimeException(dep + " did not resolve to any artifacts");
468484
}
469485

@@ -474,6 +490,42 @@ private ConditionalDependency newConditionalDep(Dependency dep) {
474490

475491
}
476492

493+
private boolean isExplicitlyExcluded(Dependency dep) {
494+
return platformSpecProperty.get().getExclusions().stream().anyMatch(rule -> {
495+
rule.getGroup();
496+
if (!rule.getGroup().equals(dep.getGroup())) {
497+
return false;
498+
}
499+
rule.getModule();
500+
return rule.getModule().equals(dep.getName());
501+
});
502+
}
503+
504+
private Configuration getDetachedWithExclusions(Dependency dep) {
505+
var c = project.getConfigurations().detachedConfiguration(dep);
506+
PlatformSpec platformSpec = platformSpecProperty.get();
507+
platformSpec.getExclusions().forEach(rule -> {
508+
Map<String, String> excludeProperties = new HashMap<>();
509+
excludeProperties.put("group", rule.getGroup());
510+
excludeProperties.put("module", rule.getModule());
511+
c.exclude(excludeProperties);
512+
});
513+
return c;
514+
}
515+
516+
private Dependency getConstrainedDep(Dependency dep) {
517+
return findMatchingConstraint(dep).map(c -> project.getDependencies().create(
518+
dep.getGroup() + ":" + dep.getName() + ":" + c.getVersion())).orElse(dep);
519+
}
520+
521+
private Optional<PlatformSpec.Constraint> findMatchingConstraint(Dependency dep) {
522+
PlatformSpec platformSpec = platformSpecProperty.get();
523+
Map<ArtifactKey, PlatformSpec.Constraint> constraints = platformSpec.getConstraints();
524+
PlatformSpec.Constraint matchingConstraint = constraints
525+
.get(ArtifactKey.ga(dep.getGroup(), dep.getName()));
526+
return Optional.ofNullable(matchingConstraint);
527+
}
528+
477529
private class ProcessedDependency {
478530
private final ResolvedArtifact artifact;
479531
private final ExtensionDependency<?> extension;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
quarkusPlatformArtifactId=quarkus-bom
2+
quarkusPlatformGroupId=io.quarkus
3+
org.gradle.logging.level=INFO
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
plugins {
2+
id 'java'
3+
id 'io.quarkus'
4+
}
5+
6+
repositories {
7+
mavenLocal {
8+
content {
9+
includeGroup 'org.enforcing.conditional' // for dependencies built in this test
10+
includeGroupByRegex 'io.quarkus.*'
11+
includeGroup 'org.hibernate.orm'
12+
}
13+
}
14+
mavenCentral()
15+
}
16+
17+
dependencies {
18+
implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
19+
implementation enforcedPlatform("org.enforcing.conditional:test-bom:1.0.0")
20+
implementation 'io.quarkus:quarkus-rest'
21+
implementation 'org.enforcing.conditional:ext-a:1.0-SNAPSHOT'
22+
testImplementation 'io.quarkus:quarkus-junit5'
23+
testImplementation 'io.rest-assured:rest-assured'
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.acme;
2+
3+
import org.eclipse.microprofile.config.inject.ConfigProperty;
4+
5+
import jakarta.inject.Inject;
6+
import jakarta.ws.rs.GET;
7+
import jakarta.ws.rs.Path;
8+
import jakarta.ws.rs.Produces;
9+
import jakarta.ws.rs.core.MediaType;
10+
import java.io.IOException;
11+
import java.net.URL;
12+
import java.util.Enumeration;
13+
14+
@Path("/hello")
15+
public class HelloResource {
16+
17+
@GET
18+
@Produces(MediaType.TEXT_PLAIN)
19+
public String hello() {
20+
return "hello";
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
plugins {
2+
id 'java'
3+
id 'io.quarkus'
4+
}
5+
6+
repositories {
7+
mavenLocal {
8+
content {
9+
includeGroup 'org.enforcing.conditional' // for dependencies built in this test
10+
includeGroupByRegex 'io.quarkus.*'
11+
includeGroup 'org.hibernate.orm'
12+
}
13+
}
14+
mavenCentral()
15+
}
16+
17+
dependencies {
18+
implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
19+
implementation enforcedPlatform("org.enforcing.conditional:test-bom:1.0.0")
20+
implementation 'io.quarkus:quarkus-rest'
21+
implementation 'org.enforcing.conditional:ext-a:1.0-SNAPSHOT'
22+
testImplementation 'io.quarkus:quarkus-junit5'
23+
testImplementation 'io.rest-assured:rest-assured'
24+
}
25+
26+
configurations {
27+
configureEach {
28+
exclude group: 'org.enforcing.conditional', module: 'dev-mode-only-lib'
29+
}
30+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.acme;
2+
3+
import org.eclipse.microprofile.config.inject.ConfigProperty;
4+
5+
import jakarta.inject.Inject;
6+
import jakarta.ws.rs.GET;
7+
import jakarta.ws.rs.Path;
8+
import jakarta.ws.rs.Produces;
9+
import jakarta.ws.rs.core.MediaType;
10+
import java.io.IOException;
11+
import java.net.URL;
12+
import java.util.Enumeration;
13+
14+
@Path("/hello")
15+
public class HelloResource {
16+
17+
@GET
18+
@Produces(MediaType.TEXT_PLAIN)
19+
public String hello() {
20+
return "hello";
21+
}
22+
}

0 commit comments

Comments
 (0)