Skip to content

Commit 7354ca8

Browse files
committed
Implement allVariantsMatching method
A method that allows you to match variants by attribute rather than name only.
1 parent 1836853 commit 7354ca8

File tree

4 files changed

+177
-20
lines changed

4 files changed

+177
-20
lines changed

src/main/java/org/gradlex/jvm/dependency/conflict/resolution/rules/ReduceToCompileOnlyApiDependencyMetadataRule.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,17 @@
1616

1717
package org.gradlex.jvm.dependency.conflict.resolution.rules;
1818

19-
import org.gradle.api.Action;
2019
import org.gradle.api.artifacts.CacheableRule;
2120
import org.gradle.api.artifacts.ComponentMetadataContext;
22-
import org.gradle.api.artifacts.ComponentMetadataDetails;
2321
import org.gradle.api.artifacts.ComponentMetadataRule;
24-
import org.gradle.api.artifacts.VariantMetadata;
25-
import org.gradle.api.attributes.Attribute;
2622
import org.gradle.api.attributes.Category;
2723
import org.gradle.api.attributes.Usage;
2824

2925
import javax.inject.Inject;
30-
import java.util.Objects;
3126
import java.util.stream.Collectors;
3227

28+
import static org.gradlex.jvm.dependency.conflict.resolution.rules.VariantSelection.allVariantsMatching;
29+
3330
/**
3431
* See:
3532
* <a href="https://docs.gradle.org/current/userguide/component_metadata_rules.html#fixing_wrong_dependency_details">
@@ -47,18 +44,8 @@ public ReduceToCompileOnlyApiDependencyMetadataRule(String dependency) {
4744

4845
@Override
4946
public void execute(ComponentMetadataContext context) {
50-
withVariants(context.getDetails(), Usage.JAVA_RUNTIME, v -> v.withDependencies(d -> d.removeAll(d.stream().filter(it -> dependency.equals(it.getModule().toString())).collect(Collectors.toList()))));
51-
}
52-
53-
private void withVariants(ComponentMetadataDetails details, String expectedUsage, Action<VariantMetadata> action) {
54-
details.allVariants(v -> {
55-
v.attributes(attributeContainer -> {
56-
String usage = attributeContainer.getAttributes().getAttribute(Attribute.of(Usage.USAGE_ATTRIBUTE.getName(), String.class));
57-
String category = attributeContainer.getAttributes().getAttribute(Attribute.of(Category.CATEGORY_ATTRIBUTE.getName(), String.class));
58-
if (Objects.equals(usage, expectedUsage) && Objects.equals(category, Category.LIBRARY)) {
59-
action.execute(v);
60-
}
61-
});
62-
});
47+
allVariantsMatching(context,
48+
id -> id.matches(Usage.USAGE_ATTRIBUTE, Usage.JAVA_RUNTIME) && id.matches(Category.CATEGORY_ATTRIBUTE, Category.LIBRARY),
49+
v -> v.withDependencies(d -> d.removeAll(d.stream().filter(it -> dependency.equals(it.getModule().toString())).collect(Collectors.toList()))));
6350
}
6451
}

src/main/java/org/gradlex/jvm/dependency/conflict/resolution/rules/ReduceToRuntimeOnlyDependencyMetadataRule.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,14 @@
1919
import org.gradle.api.artifacts.CacheableRule;
2020
import org.gradle.api.artifacts.ComponentMetadataContext;
2121
import org.gradle.api.artifacts.ComponentMetadataRule;
22+
import org.gradle.api.attributes.Category;
23+
import org.gradle.api.attributes.Usage;
2224

2325
import javax.inject.Inject;
2426
import java.util.stream.Collectors;
2527

28+
import static org.gradlex.jvm.dependency.conflict.resolution.rules.VariantSelection.allVariantsMatching;
29+
2630
/**
2731
* See:
2832
* <a href="https://docs.gradle.org/current/userguide/component_metadata_rules.html#fixing_wrong_dependency_details">
@@ -40,7 +44,8 @@ public ReduceToRuntimeOnlyDependencyMetadataRule(String dependency) {
4044

4145
@Override
4246
public void execute(ComponentMetadataContext context) {
43-
context.getDetails().withVariant("compile", v -> v.withDependencies(d -> d.removeAll(d.stream().filter(it -> dependency.equals(it.getModule().toString())).collect(Collectors.toList())))); // .pom
44-
context.getDetails().withVariant("apiElements", v -> v.withDependencies(d -> d.removeAll(d.stream().filter(it -> dependency.equals(it.getModule().toString())).collect(Collectors.toList())))); // .module
47+
allVariantsMatching(context,
48+
id -> id.matches(Usage.USAGE_ATTRIBUTE, Usage.JAVA_API) && id.matches(Category.CATEGORY_ATTRIBUTE, Category.LIBRARY),
49+
v -> v.withDependencies(d -> d.removeAll(d.stream().filter(it -> dependency.equals(it.getModule().toString())).collect(Collectors.toList())))); // .module
4550
}
4651
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright the GradleX team.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.gradlex.jvm.dependency.conflict.resolution.rules;
18+
19+
import org.gradle.api.Named;
20+
import org.gradle.api.attributes.Attribute;
21+
22+
import java.util.Map;
23+
import java.util.Objects;
24+
25+
class VariantIdentification {
26+
27+
private final Map<String, String> attributes;
28+
29+
VariantIdentification(Map<String, String> attributes) {
30+
this.attributes = attributes;
31+
}
32+
33+
boolean matches(Attribute<? extends Named> attribute, String value) {
34+
return matches(attribute.getName(), value);
35+
}
36+
37+
boolean matches(String attribute, String value) {
38+
return Objects.equals(attributes.get(attribute), value);
39+
}
40+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright the GradleX team.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.gradlex.jvm.dependency.conflict.resolution.rules;
18+
19+
import org.gradle.api.Action;
20+
import org.gradle.api.artifacts.ComponentMetadataContext;
21+
import org.gradle.api.artifacts.VariantMetadata;
22+
import org.gradle.api.attributes.Attribute;
23+
import org.gradle.api.attributes.AttributeContainer;
24+
import org.gradle.api.attributes.Category;
25+
import org.gradle.api.attributes.LibraryElements;
26+
import org.gradle.api.attributes.Usage;
27+
import org.gradle.internal.component.external.model.ModuleComponentResolveMetadata;
28+
import org.gradle.internal.component.model.VariantResolveMetadata;
29+
30+
import java.lang.reflect.Field;
31+
import java.lang.reflect.Method;
32+
import java.util.HashMap;
33+
import java.util.List;
34+
import java.util.Map;
35+
import java.util.function.Predicate;
36+
import java.util.stream.Collectors;
37+
import java.util.stream.Stream;
38+
39+
import static java.util.Objects.requireNonNull;
40+
41+
final class VariantSelection {
42+
43+
static class MavenVariant {
44+
String name;
45+
Map<String, String> attributes = new HashMap<>();
46+
47+
MavenVariant(String name) {
48+
this.name = name;
49+
}
50+
51+
MavenVariant attribute(String name, String value) {
52+
attributes.put(name, value);
53+
return this;
54+
}
55+
}
56+
57+
static final MavenVariant MAVEN_RUNTIME_VARIANT = new MavenVariant("runtime")
58+
.attribute(Usage.USAGE_ATTRIBUTE.getName(), Usage.JAVA_RUNTIME)
59+
.attribute(Category.CATEGORY_ATTRIBUTE.getName(), Category.LIBRARY)
60+
.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE.getName(), LibraryElements.JAR);
61+
static final MavenVariant MAVEN_COMPILE_VARIANT = new MavenVariant("compile")
62+
.attribute(Usage.USAGE_ATTRIBUTE.getName(), Usage.JAVA_API)
63+
.attribute(Category.CATEGORY_ATTRIBUTE.getName(), Category.LIBRARY)
64+
.attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE.getName(), LibraryElements.JAR);
65+
66+
67+
private VariantSelection() { }
68+
69+
static void allVariantsMatching(ComponentMetadataContext context, Predicate<VariantIdentification> id, Action<? super VariantMetadata> action) {
70+
List<String> variantNames = discoverNames(context, id);
71+
variantNames.forEach(variantName -> context.getDetails().withVariant(variantName, action));
72+
}
73+
74+
private static List<String> discoverNames(ComponentMetadataContext context, Predicate<VariantIdentification> id) {
75+
ModuleComponentResolveMetadata metadata = extractMetadataFromContext(context);
76+
List<VariantResolveMetadata> variants = getVariants(metadata);
77+
78+
if (variants.isEmpty()) {
79+
return Stream.of(MAVEN_RUNTIME_VARIANT, MAVEN_COMPILE_VARIANT)
80+
.filter(v -> id.test(new VariantIdentification(v.attributes)))
81+
.map(v -> v.name)
82+
.collect(Collectors.toList());
83+
} else {
84+
return variants.stream()
85+
.filter(v -> id.test(new VariantIdentification(toMap(getAttributes(v)))))
86+
.map(VariantResolveMetadata::getName)
87+
.collect(Collectors.toList());
88+
}
89+
}
90+
91+
private static Map<String, String> toMap(AttributeContainer attributes) {
92+
return attributes.keySet().stream().collect(Collectors
93+
.toMap(Attribute::getName, k -> requireNonNull(attributes.getAttribute(k)).toString()));
94+
}
95+
96+
private static AttributeContainer getAttributes(VariantResolveMetadata metadata) {
97+
try {
98+
Method getVariants = VariantResolveMetadata.class.getDeclaredMethod("getAttributes");
99+
return (AttributeContainer) getVariants.invoke(metadata);
100+
} catch (ReflectiveOperationException e) {
101+
throw new RuntimeException(e);
102+
}
103+
}
104+
105+
private static List<VariantResolveMetadata> getVariants(ModuleComponentResolveMetadata metadata) {
106+
try {
107+
Method getVariants = ModuleComponentResolveMetadata.class.getDeclaredMethod("getVariants");
108+
@SuppressWarnings("unchecked")
109+
List<VariantResolveMetadata> variants = (List<VariantResolveMetadata>) getVariants.invoke(metadata);
110+
return variants;
111+
} catch (ReflectiveOperationException e) {
112+
throw new RuntimeException(e);
113+
}
114+
}
115+
116+
private static ModuleComponentResolveMetadata extractMetadataFromContext(ComponentMetadataContext context) {
117+
try {
118+
Field metadataField = context.getClass().getDeclaredField("metadata");
119+
metadataField.setAccessible(true);
120+
return (ModuleComponentResolveMetadata) metadataField.get(context);
121+
} catch (ReflectiveOperationException e) {
122+
throw new RuntimeException(e);
123+
}
124+
}
125+
}

0 commit comments

Comments
 (0)