Skip to content

Commit 7c8412a

Browse files
committed
Add configuration option for 'versionsProvidingConfiguration'
This way, a build setup can be created with a Configuration available in ALL projects that resolves to the same version of every module used. Then the metadata input to the transform, to process 'requireAllDefinedDependencies', is the same for a certain Jar independent of the classpath it is used on.
1 parent 4c83a98 commit 7c8412a

File tree

4 files changed

+94
-43
lines changed

4 files changed

+94
-43
lines changed

src/main/java/org/gradlex/javamodule/moduleinfo/ExtraJavaModuleInfoPlugin.java

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@
5353
import java.util.Properties;
5454
import java.util.Set;
5555
import java.util.stream.Collectors;
56-
import java.util.stream.Stream;
5756

5857
import static org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE;
5958
import static org.gradle.api.attributes.Category.LIBRARY;
@@ -195,16 +194,9 @@ private void registerTransform(String fileExtension, Project project, ExtraJavaM
195194
p.getMergeJarIds().set(artifacts.map(new IdExtractor()));
196195
p.getMergeJars().set(artifacts.map(new FileExtractor(project.getLayout())));
197196

198-
p.getRequiresFromMetadata().set(project.provider(() -> sourceSets.stream().flatMap(s -> Stream.of(
199-
s.getRuntimeClasspathConfigurationName(),
200-
s.getCompileClasspathConfigurationName(),
201-
s.getAnnotationProcessorConfigurationName()
202-
))
203-
.flatMap(resolvable -> existingComponentsOfInterest(configurations.getByName(resolvable), extension))
204-
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (k1, k2) -> k1)).entrySet().stream()
205-
.collect(Collectors.toMap(Map.Entry::getKey, c -> new PublishedMetadata(c.getKey(), c.getValue(), project)))
206-
));
207-
197+
Provider<Set<String>> componentsOfInterest = componentsOfInterest(extension);
198+
p.getRequiresFromMetadata().set(componentsOfInterest.map(gaSet -> gaSet.stream()
199+
.collect(Collectors.toMap(ga -> ga, ga -> new PublishedMetadata(ga, project, extension)))));
208200
p.getAdditionalKnownModules().set(extractFromModuleDependenciesPlugin(project));
209201
});
210202
t.getFrom().attribute(artifactType, fileExtension).attribute(javaModule, false);
@@ -238,22 +230,11 @@ private Provider<Map<String, String>> extractFromModuleDependenciesPlugin(Projec
238230
});
239231
}
240232

241-
private Stream<Map.Entry<String, Configuration>> existingComponentsOfInterest(Configuration resolvable, ExtraJavaModuleInfoPluginExtension extension) {
242-
Set<String> componentsOfInterest = componentsOfInterest(extension);
243-
if (componentsOfInterest.isEmpty()) {
244-
return Stream.empty();
245-
}
246-
247-
return resolvable.getIncoming().getResolutionResult().getAllComponents().stream()
248-
.filter(c -> componentsOfInterest.contains(ga(c.getId())))
249-
.collect(Collectors.toMap(c -> c.getId().toString(), c -> resolvable)).entrySet().stream();
250-
}
251-
252-
private static Set<String> componentsOfInterest(ExtraJavaModuleInfoPluginExtension extension) {
253-
return extension.getModuleSpecs().get().values().stream()
233+
private static Provider<Set<String>> componentsOfInterest(ExtraJavaModuleInfoPluginExtension extension) {
234+
return extension.getModuleSpecs().map(specs -> specs.values().stream()
254235
.filter(ExtraJavaModuleInfoPlugin::needsDependencies)
255236
.map(ModuleSpec::getIdentifier)
256-
.collect(Collectors.toSet());
237+
.collect(Collectors.toSet()));
257238
}
258239

259240
private static boolean needsDependencies(ModuleSpec moduleSpec) {

src/main/java/org/gradlex/javamodule/moduleinfo/ExtraJavaModuleInfoPluginExtension.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ public abstract class ExtraJavaModuleInfoPluginExtension {
4141
public abstract Property<Boolean> getFailOnMissingModuleInfo();
4242
public abstract Property<Boolean> getFailOnAutomaticModules();
4343
public abstract Property<Boolean> getDeriveAutomaticModuleNamesFromFileNames();
44+
public abstract Property<String> getVersionsProvidingConfiguration();
4445

4546
/**
4647
* Add full module information for a given Jar file.

src/main/java/org/gradlex/javamodule/moduleinfo/ExtraJavaModuleInfoTransform.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -367,14 +367,19 @@ private byte[] addModuleInfo(ModuleInfo moduleInfo, Map<String, List<String>> pr
367367
moduleVisitor.visitRequire("java.base", 0, null);
368368

369369
if (moduleInfo.requireAllDefinedDependencies) {
370-
String fullIdentifier = moduleInfo.getIdentifier() + ":" + version;
371-
PublishedMetadata requires = getParameters().getRequiresFromMetadata().get().get(fullIdentifier);
370+
String identifier = moduleInfo.getIdentifier();
371+
PublishedMetadata requires = getParameters().getRequiresFromMetadata().get().get(identifier);
372372

373373
if (requires == null) {
374374
throw new RuntimeException("[requires directives from metadata] " +
375375
"Cannot find dependencies for '" + moduleInfo.getModuleName() + "'. " +
376376
"Are '" + moduleInfo.getIdentifier() + "' the correct component coordinates?");
377377
}
378+
if (requires.getErrorMessage() != null) {
379+
throw new RuntimeException("[requires directives from metadata] " +
380+
"Cannot read metadata for '" + moduleInfo.getModuleName() + "': " +
381+
requires.getErrorMessage());
382+
}
378383

379384
for (String ga : requires.getRequires()) {
380385
String depModuleName = gaToModuleName(ga);

src/main/java/org/gradlex/javamodule/moduleinfo/PublishedMetadata.java

Lines changed: 80 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,36 +18,49 @@
1818

1919
import org.gradle.api.Project;
2020
import org.gradle.api.artifacts.Configuration;
21+
import org.gradle.api.artifacts.ConfigurationContainer;
2122
import org.gradle.api.artifacts.result.DependencyResult;
22-
import org.gradle.api.artifacts.result.ResolvedComponentResult;
2323
import org.gradle.api.artifacts.result.ResolvedDependencyResult;
24+
import org.gradle.api.artifacts.result.UnresolvedDependencyResult;
2425
import org.gradle.api.attributes.Attribute;
26+
import org.gradle.api.attributes.Bundling;
2527
import org.gradle.api.attributes.Category;
28+
import org.gradle.api.attributes.LibraryElements;
2629
import org.gradle.api.attributes.Usage;
30+
import org.gradle.api.attributes.java.TargetJvmEnvironment;
31+
import org.gradle.api.model.ObjectFactory;
32+
import org.gradle.api.provider.Provider;
33+
import org.gradle.api.tasks.SourceSet;
34+
import org.gradle.api.tasks.SourceSetContainer;
35+
import org.gradle.util.GradleVersion;
2736

2837
import java.io.Serializable;
2938
import java.util.ArrayList;
3039
import java.util.List;
3140
import java.util.stream.Collectors;
3241
import java.util.stream.Stream;
3342

43+
import static java.util.Collections.emptyList;
3444
import static java.util.Objects.requireNonNull;
3545
import static org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE;
3646
import static org.gradle.api.attributes.Category.LIBRARY;
3747
import static org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE;
3848

3949
public class PublishedMetadata implements Serializable {
4050
private static final Attribute<String> CATEGORY_ATTRIBUTE_UNTYPED = Attribute.of(CATEGORY_ATTRIBUTE.getName(), String.class);
51+
private static final String DEFAULT_VERSION_SOURCE_CONFIGURATION = "definedDependenciesVersions";
4152

4253
private final String gav;
4354
private final List<String> requires = new ArrayList<>();
4455
private final List<String> requiresTransitive = new ArrayList<>();
4556
private final List<String> requiresStaticTransitive = new ArrayList<>();
57+
private String errorMessage = null;
4658

47-
PublishedMetadata(String gav, Configuration origin, Project project) {
59+
PublishedMetadata(String gav, Project project, ExtraJavaModuleInfoPluginExtension extension) {
4860
this.gav = gav;
49-
List<String> compileDependencies = componentVariant(origin, project, Usage.JAVA_API);
50-
List<String> runtimeDependencies = componentVariant(origin, project, Usage.JAVA_RUNTIME);
61+
62+
List<String> compileDependencies = componentVariant(extension.getVersionsProvidingConfiguration(), project, Usage.JAVA_API);
63+
List<String> runtimeDependencies = componentVariant(extension.getVersionsProvidingConfiguration(), project, Usage.JAVA_RUNTIME);
5164

5265
Stream.concat(compileDependencies.stream(), runtimeDependencies.stream()).distinct().forEach(ga -> {
5366
if (compileDependencies.contains(ga) && runtimeDependencies.contains(ga)) {
@@ -60,26 +73,73 @@ public class PublishedMetadata implements Serializable {
6073
});
6174
}
6275

63-
private List<String> componentVariant(Configuration origin, Project project, String usage) {
76+
private List<String> componentVariant(Provider<String> versionsProvidingConfiguration, Project project, String usage) {
77+
Configuration versionsSource;
78+
if (versionsProvidingConfiguration.isPresent()) {
79+
versionsSource = project.getConfigurations().getByName(versionsProvidingConfiguration.get());
80+
} else {
81+
// version provider is not configured, create on adhoc based on ALL classpaths of the project
82+
versionsSource = maybeCreateDefaultVersionSourcConfiguration(project.getConfigurations(), project.getObjects(),
83+
project.getExtensions().findByType(SourceSetContainer.class));
84+
}
85+
6486
Configuration singleComponentVariantResolver = project.getConfigurations().detachedConfiguration(project.getDependencies().create(gav));
6587
singleComponentVariantResolver.setCanBeConsumed(false);
66-
singleComponentVariantResolver.shouldResolveConsistentlyWith(origin);
67-
origin.getAttributes().keySet().forEach(a -> {
88+
singleComponentVariantResolver.shouldResolveConsistentlyWith(versionsSource);
89+
versionsSource.getAttributes().keySet().forEach(a -> {
6890
@SuppressWarnings("rawtypes") Attribute untypedAttributeKey = a;
6991
//noinspection unchecked
70-
singleComponentVariantResolver.getAttributes().attribute(untypedAttributeKey, requireNonNull(origin.getAttributes().getAttribute(a)));
92+
singleComponentVariantResolver.getAttributes().attribute(untypedAttributeKey, requireNonNull(versionsSource.getAttributes().getAttribute(a)));
7193
});
7294
singleComponentVariantResolver.getAttributes().attribute(USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, usage));
73-
return firstAndOnlyComponent(singleComponentVariantResolver).getDependencies().stream()
74-
.filter(PublishedMetadata::filterComponentDependencies)
75-
.map(PublishedMetadata::ga)
76-
.collect(Collectors.toList());
95+
return firstAndOnlyComponentDependencies(singleComponentVariantResolver);
96+
}
97+
98+
private Configuration maybeCreateDefaultVersionSourcConfiguration(ConfigurationContainer configurations, ObjectFactory objects, SourceSetContainer sourceSets) {
99+
String name = DEFAULT_VERSION_SOURCE_CONFIGURATION;
100+
Configuration existing = configurations.findByName(name);
101+
if (existing != null) {
102+
return existing;
103+
}
104+
105+
return configurations.create(name, c -> {
106+
c.setCanBeResolved(true);
107+
c.setCanBeConsumed(false);
108+
c.getAttributes().attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.class, Usage.JAVA_RUNTIME));
109+
c.getAttributes().attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.class, Category.LIBRARY));
110+
c.getAttributes().attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.class, LibraryElements.JAR));
111+
c.getAttributes().attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.class, Bundling.EXTERNAL));
112+
if (GradleVersion.current().compareTo(GradleVersion.version("7.0")) >= 0) {
113+
c.getAttributes().attribute(TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
114+
objects.named(TargetJvmEnvironment.class, TargetJvmEnvironment.STANDARD_JVM));
115+
}
116+
117+
if (sourceSets != null) {
118+
for (SourceSet sourceSet : sourceSets) {
119+
Configuration implementation = configurations.getByName(sourceSet.getImplementationConfigurationName());
120+
Configuration compileOnly = configurations.getByName(sourceSet.getCompileOnlyConfigurationName());
121+
Configuration runtimeOnly = configurations.getByName(sourceSet.getRuntimeOnlyConfigurationName());
122+
Configuration annotationProcessor = configurations.getByName(sourceSet.getAnnotationProcessorConfigurationName());
123+
c.extendsFrom(implementation, compileOnly, runtimeOnly, annotationProcessor);
124+
}
125+
}
126+
});
77127
}
78128

79-
private ResolvedComponentResult firstAndOnlyComponent(Configuration singleComponentVariantResolver) {
80-
ResolvedDependencyResult onlyResult = (ResolvedDependencyResult) singleComponentVariantResolver.getIncoming().getResolutionResult()
81-
.getRoot().getDependencies().iterator().next();
82-
return onlyResult.getSelected();
129+
private List<String> firstAndOnlyComponentDependencies(Configuration singleComponentVariantResolver) {
130+
DependencyResult result = singleComponentVariantResolver
131+
.getIncoming().getResolutionResult().getRoot()
132+
.getDependencies().iterator().next();
133+
134+
if (result instanceof UnresolvedDependencyResult) {
135+
errorMessage = ((UnresolvedDependencyResult) result).getFailure().getMessage();
136+
return emptyList();
137+
} else {
138+
return ((ResolvedDependencyResult) result).getSelected().getDependencies().stream()
139+
.filter(PublishedMetadata::filterComponentDependencies)
140+
.map(PublishedMetadata::ga)
141+
.collect(Collectors.toList());
142+
}
83143
}
84144

85145
private static boolean filterComponentDependencies(DependencyResult d) {
@@ -113,4 +173,8 @@ public List<String> getRequiresTransitive() {
113173
public List<String> getRequiresStaticTransitive() {
114174
return requiresStaticTransitive;
115175
}
176+
177+
public String getErrorMessage() {
178+
return errorMessage;
179+
}
116180
}

0 commit comments

Comments
 (0)