Skip to content

Commit 75b80ed

Browse files
committed
Manually enforce platform constraints for conditional dependencies in QuarkusComponentVariants
Addresses #49743
1 parent debb4cf commit 75b80ed

File tree

3 files changed

+140
-15
lines changed

3 files changed

+140
-15
lines changed

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

Lines changed: 22 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;
@@ -93,13 +94,14 @@ public static void initConfigurations(Project project) {
9394
final ConfigurationContainer configContainer = project.getConfigurations();
9495

9596
// 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-
});
97+
configContainer
98+
.register(ToolingUtils.DEV_MODE_CONFIGURATION_NAME, config -> {
99+
config.extendsFrom(configContainer.getByName(JavaPlugin.IMPLEMENTATION_CONFIGURATION_NAME));
100+
config.setCanBeConsumed(false);
101+
if (!isDisableComponentVariants(project)) {
102+
QuarkusComponentVariants.setConditionalAttributes(config, project, LaunchMode.DEVELOPMENT);
103+
}
104+
});
103105

104106
// Base runtime configurations for every launch mode
105107
configContainer
@@ -178,6 +180,7 @@ private static Configuration[] getOriginalRuntimeClasspaths(Project project, Lau
178180
private final String platformImportName;
179181

180182
private final List<Dependency> platformDataDeps = new ArrayList<>();
183+
private final Set<ManualPlatformSpec.Constraint> platformConstraints = new HashSet<>();
181184

182185
public ApplicationDeploymentClasspathBuilder(Project project, LaunchMode mode,
183186
TaskDependencyFactory taskDependencyFactory) {
@@ -239,6 +242,9 @@ private void setUpPlatformConfiguration() {
239242
break;
240243
}
241244
}
245+
} else {
246+
platformConstraints.add(new ManualPlatformSpec.Constraint(d.getTarget().getGroup(), name,
247+
d.getTarget().getVersion()));
242248
}
243249
});
244250
});
@@ -276,14 +282,22 @@ private List<Dependency> resolvePlatformDependencies() {
276282
return platformDataDeps;
277283
}
278284

285+
private ManualPlatformSpec resolvePlatformSpec() {
286+
getPlatformConfiguration().resolve();
287+
return new ManualPlatformSpec(platformConstraints, getPlatformConfiguration().getExcludeRules());
288+
}
289+
279290
private void setUpRuntimeConfiguration() {
280291
if (!project.getConfigurations().getNames().contains(this.runtimeConfigurationName)) {
281292
final String baseConfig;
282293
final boolean disableComponentVariants = isDisableComponentVariants(project);
283294
if (disableComponentVariants) {
284295
baseConfig = ApplicationDeploymentClasspathBuilder.getBaseRuntimeConfigName(mode);
285296
} else {
286-
QuarkusComponentVariants.addVariants(project, mode);
297+
Property<ManualPlatformSpec> platformSpecProperty = project.getObjects()
298+
.property(ManualPlatformSpec.class);
299+
QuarkusComponentVariants.addVariants(project, mode,
300+
platformSpecProperty.value(project.provider(this::resolvePlatformSpec)));
287301
baseConfig = QuarkusComponentVariants.getConditionalConfigurationName(mode);
288302
}
289303
project.getConfigurations().register(this.runtimeConfigurationName, configuration -> {
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package io.quarkus.gradle.dependency;
2+
3+
import java.util.Set;
4+
5+
import org.gradle.api.artifacts.Dependency;
6+
import org.gradle.api.artifacts.ExcludeRule;
7+
8+
class ManualPlatformSpec {
9+
private final Set<Constraint> constraints;
10+
private final Set<ExcludeRule> exclusions;
11+
12+
public ManualPlatformSpec(Set<Constraint> constraints, Set<ExcludeRule> exclusions) {
13+
this.constraints = constraints;
14+
this.exclusions = exclusions;
15+
}
16+
17+
public Set<Constraint> getConstraints() {
18+
return constraints;
19+
}
20+
21+
public Set<ExcludeRule> getExclusions() {
22+
return exclusions;
23+
}
24+
25+
static class Constraint {
26+
private final String groupId;
27+
private final String artifactId;
28+
private final String version;
29+
30+
public Constraint(String groupId, String artifactId, String version) {
31+
this.groupId = groupId;
32+
this.artifactId = artifactId;
33+
this.version = version;
34+
}
35+
36+
public String getGroupId() {
37+
return groupId;
38+
}
39+
40+
public String getArtifactId() {
41+
return artifactId;
42+
}
43+
44+
public String getVersion() {
45+
return version;
46+
}
47+
48+
public boolean matches(Dependency dependency) {
49+
return groupId.equals(dependency.getGroup())
50+
&& artifactId.equals(dependency.getName());
51+
}
52+
}
53+
}

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

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import org.gradle.api.attributes.java.TargetJvmEnvironment;
2929
import org.gradle.api.model.ObjectFactory;
3030
import org.gradle.api.provider.ListProperty;
31+
import org.gradle.api.provider.Property;
3132

3233
import io.quarkus.gradle.tooling.dependency.DependencyUtils;
3334
import io.quarkus.gradle.tooling.dependency.ExtensionDependency;
@@ -169,22 +170,26 @@ public static void setCommonAttributes(AttributeContainer attrs, ObjectFactory o
169170
* @param project project
170171
* @param mode launch mode
171172
*/
172-
public static void addVariants(Project project, LaunchMode mode) {
173-
new QuarkusComponentVariants(project, mode).configureAndAddVariants();
173+
public static void addVariants(Project project, LaunchMode mode,
174+
Property<ManualPlatformSpec> manualPlatformConfig) {
175+
new QuarkusComponentVariants(project, mode, manualPlatformConfig).configureAndAddVariants();
174176
}
175177

176178
private final Attribute<String> quarkusDepAttr;
177179
private final Project project;
180+
private final Property<ManualPlatformSpec> manualPlatformConfig;
178181
private final Map<ArtifactKey, ProcessedDependency> processedDeps = new HashMap<>();
179182
private final Map<ArtifactKey, ConditionalDependency> allConditionalDeps = new HashMap<>();
180183
private final List<ConditionalDependencyVariant> dependencyVariantQueue = new ArrayList<>();
181184
private final Map<String, SatisfiedExtensionDeps> satisfiedExtensionDeps = new HashMap<>();
182185
private final LaunchMode mode;
183186
private final AtomicInteger configCopyCounter = new AtomicInteger();
184187

185-
private QuarkusComponentVariants(Project project, LaunchMode mode) {
188+
private QuarkusComponentVariants(Project project, LaunchMode mode,
189+
Property<ManualPlatformSpec> manualPlatformConfig) {
186190
this.project = project;
187191
this.mode = mode;
192+
this.manualPlatformConfig = manualPlatformConfig;
188193
this.quarkusDepAttr = getConditionalDependencyAttribute(project.getName(), mode);
189194
project.getDependencies().getAttributesSchema().attribute(quarkusDepAttr);
190195
project.getDependencies().getAttributesSchema().attribute(getDeploymentDependencyAttribute(project.getName(), mode));
@@ -407,7 +412,10 @@ private void processDependency(ProcessedDependency parent,
407412
}
408413

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

413421
private ConditionalDependency getOrCreateConditionalDep(Dependency dep) {
@@ -417,7 +425,7 @@ private ConditionalDependency getOrCreateConditionalDep(Dependency dep) {
417425
}
418426

419427
private ResolvedArtifact tryResolvingRelocationArtifact(Dependency dep) {
420-
final Configuration configForRelocated = project.getConfigurations().detachedConfiguration(dep).setTransitive(true);
428+
final Configuration configForRelocated = getDetachedWithExclusions(dep).setTransitive(true);
421429
setConditionalAttributes(configForRelocated, project, mode);
422430

423431
var firstLevelDeps = configForRelocated.getResolvedConfiguration().getFirstLevelModuleDependencies();
@@ -447,8 +455,11 @@ private ResolvedArtifact tryResolvingRelocationArtifact(Dependency dep) {
447455
return artifact;
448456
}
449457

450-
private ConditionalDependency newConditionalDep(Dependency dep) {
451-
final Configuration config = project.getConfigurations().detachedConfiguration(dep).setTransitive(false);
458+
private ConditionalDependency newConditionalDep(Dependency originalDep) {
459+
var manualConfig = manualPlatformConfig.get();
460+
var dep = getConstrainedDep(originalDep, manualConfig.getConstraints());
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,48 @@ private ConditionalDependency newConditionalDep(Dependency dep) {
474490

475491
}
476492

493+
private boolean isExplicitlyExcluded(Dependency dep) {
494+
return manualPlatformConfig.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+
manualPlatformConfig.get().getExclusions().forEach(rule -> {
507+
Map<String, String> excludeProperties = new HashMap<>();
508+
excludeProperties.put("group", rule.getGroup());
509+
excludeProperties.put("module", rule.getModule());
510+
c.exclude(excludeProperties);
511+
});
512+
return c;
513+
}
514+
515+
private Dependency getConstrainedDep(Dependency dep, Set<ManualPlatformSpec.Constraint> constraints) {
516+
if (constraints == null || constraints.isEmpty()) {
517+
return dep;
518+
}
519+
520+
var matchingConstraints = constraints.stream().filter(c -> c.matches(dep)).toList();
521+
522+
if (matchingConstraints.isEmpty()) {
523+
return dep;
524+
}
525+
526+
if (matchingConstraints.size() > 1) {
527+
throw new RuntimeException("Multiple matching constraints for " + dep + ": " + matchingConstraints);
528+
}
529+
530+
var c = matchingConstraints.get(0);
531+
return project.getDependencies().create(
532+
dep.getGroup() + ":" + dep.getName() + ":" + c.getVersion());
533+
}
534+
477535
private class ProcessedDependency {
478536
private final ResolvedArtifact artifact;
479537
private final ExtensionDependency<?> extension;

0 commit comments

Comments
 (0)