Skip to content

Commit 98c8394

Browse files
committed
Add ReachabilityMetadataCopyTask to Gradle Plugin
Update the gradle plugin with a new `ReachabilityMetadataCopyTask` class that can be used to copy hints obtained from the metadata repository.
1 parent f7729a1 commit 98c8394

File tree

8 files changed

+334
-23
lines changed

8 files changed

+334
-23
lines changed

docs/src/docs/asciidoc/gradle-plugin.adoc

+22
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,28 @@ include::../snippets/gradle/groovy/build.gradle[tags=specify-metadata-version-fo
411411
include::../snippets/gradle/kotlin/build.gradle.kts[tags=specify-metadata-version-for-library]
412412
----
413413

414+
=== Including metadata repository files
415+
416+
By default, repository metadata will be used only when your native image is generated.
417+
In some situations, you may want a copy the metadata to use directly.
418+
419+
For example, copying the metadata into your jar can be useful when some other process is responsible for converting your jar into a native image.
420+
You might be generating a shaded jar and using a https://paketo.io/[Paketo buildpack] to convert it to a native image.
421+
422+
To include metadata repository inside your jar you can use the `ReachabilityMetadataCopyTask`.
423+
Typically the task will be declared and linked to the `from` section of the `jar`:
424+
425+
.Including metadata repository files
426+
[source, groovy, role="multi-language-sample"]
427+
----
428+
include::../snippets/gradle/groovy/build.gradle[tags=include-metadata]
429+
----
430+
431+
[source, kotlin, role="multi-language-sample"]
432+
----
433+
include::../snippets/gradle/kotlin/build.gradle.kts[tags=include-metadata]
434+
----
435+
414436
[[plugin-configurations]]
415437
== Configurations defined by the plugin
416438

docs/src/docs/snippets/gradle/groovy/build.gradle

+8
Original file line numberDiff line numberDiff line change
@@ -207,3 +207,11 @@ graalvmNative {
207207
}
208208
}
209209
// end::specify-metadata-version-for-library[]
210+
211+
// tag::include-metadata[]
212+
task reachabilityMetadata(type: org.graalvm.buildtools.gradle.tasks.ReachabilityMetadataCopyTask)
213+
214+
jar {
215+
from reachabilityMetadata
216+
}
217+
// end::include-metadata[]

docs/src/docs/snippets/gradle/kotlin/build.gradle.kts

+8
Original file line numberDiff line numberDiff line change
@@ -221,3 +221,11 @@ graalvmNative {
221221
}
222222
}
223223
// end::specify-metadata-version-for-library[]
224+
225+
// tag::include-metadata[]
226+
var reachabilityMetadata = tasks.register<org.graalvm.buildtools.gradle.tasks.ReachabilityMetadataCopyTask>("reachabilityMetadata")
227+
228+
tasks.withType<Jar> {
229+
from(reachabilityMetadata)
230+
}
231+
// end::include-metadata[]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
42+
package org.graalvm.buildtools.gradle
43+
44+
import org.graalvm.buildtools.gradle.fixtures.AbstractFunctionalTest
45+
import org.gradle.api.logging.LogLevel
46+
import spock.lang.Unroll
47+
48+
class ReachabilityMetadataCopyTaskTest extends AbstractFunctionalTest {
49+
50+
def "the application runs when using the official metadata repository"() {
51+
given:
52+
withSample("metadata-repo-integration")
53+
54+
when:
55+
run 'jar', "-D${NativeImagePlugin.CONFIG_REPO_LOGLEVEL}=${LogLevel.LIFECYCLE}"
56+
57+
then:
58+
tasks {
59+
succeeded ':jar', ':reachabilityMetadata'
60+
}
61+
62+
and: "has copied metadata file"
63+
file("build/native-reachability-metadata/META-INF/native-image/com.h2database/h2/2.1.210/resource-config.json").text.trim() == '''{
64+
"bundles": [],
65+
"resources": {
66+
"includes": [
67+
{
68+
"condition": {
69+
"typeReachable": "org.h2.util.Utils"
70+
},
71+
"pattern": "\\\\Qorg/h2/util/data.zip\\\\E"
72+
}
73+
]
74+
}
75+
}'''
76+
}
77+
78+
}

native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/NativeImagePlugin.java

+40-23
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import org.graalvm.buildtools.gradle.tasks.GenerateResourcesConfigFile;
6363
import org.graalvm.buildtools.gradle.tasks.MetadataCopyTask;
6464
import org.graalvm.buildtools.gradle.tasks.NativeRunTask;
65+
import org.graalvm.buildtools.gradle.tasks.ReachabilityMetadataCopyTask;
6566
import org.graalvm.buildtools.gradle.tasks.actions.CleanupAgentFilesAction;
6667
import org.graalvm.buildtools.gradle.tasks.actions.MergeAgentFilesAction;
6768
import org.graalvm.buildtools.gradle.tasks.actions.ProcessGeneratedGraalResourceFilesAction;
@@ -99,6 +100,7 @@
99100
import org.gradle.api.tasks.OutputDirectory;
100101
import org.gradle.api.tasks.SourceSet;
101102
import org.gradle.api.tasks.SourceSetContainer;
103+
import org.gradle.api.tasks.TaskCollection;
102104
import org.gradle.api.tasks.TaskContainer;
103105
import org.gradle.api.tasks.TaskProvider;
104106
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
@@ -271,6 +273,21 @@ private void configureJavaProject(Project project, Provider<NativeImageService>
271273
task.getMergeWithExisting().set(graalExtension.getAgent().getMetadataCopy().getMergeWithExisting());
272274
task.getToolchainDetection().set(graalExtension.getToolchainDetection());
273275
});
276+
277+
GraalVMReachabilityMetadataRepositoryExtension metadataRepositoryExtension = reachabilityExtensionOn(graalExtension);
278+
TaskCollection<ReachabilityMetadataCopyTask> reachabilityMetadataCopyTasks = project.getTasks()
279+
.withType(ReachabilityMetadataCopyTask.class);
280+
reachabilityMetadataCopyTasks.configureEach(task -> {
281+
Provider<GraalVMReachabilityMetadataService> reachabilityMetadataService = graalVMReachabilityMetadataService(
282+
project, metadataRepositoryExtension);
283+
task.getMetadataService().set(reachabilityMetadataService);
284+
task.usesService(reachabilityMetadataService);
285+
task.getUri().convention(task.getVersion().map(this::getReachabilityMetadataRepositoryUrlForVersion)
286+
.orElse(metadataRepositoryExtension.getUri()));
287+
task.getExcludedModules().convention(metadataRepositoryExtension.getExcludedModules());
288+
task.getModuleToConfigVersion().convention(metadataRepositoryExtension.getModuleToConfigVersion());
289+
task.getInto().convention(project.getLayout().getBuildDirectory().dir("native-reachability-metadata"));
290+
});
274291
}
275292

276293
private void configureAutomaticTaskCreation(Project project,
@@ -320,14 +337,7 @@ private void configureAutomaticTaskCreation(Project project,
320337

321338
private void configureJvmReachabilityConfigurationDirectories(Project project, GraalVMExtension graalExtension, NativeImageOptions options, SourceSet sourceSet) {
322339
GraalVMReachabilityMetadataRepositoryExtension repositoryExtension = reachabilityExtensionOn(graalExtension);
323-
Provider<GraalVMReachabilityMetadataService> serviceProvider = project.getGradle()
324-
.getSharedServices()
325-
.registerIfAbsent("nativeConfigurationService", GraalVMReachabilityMetadataService.class, spec -> {
326-
LogLevel logLevel = determineLogLevel();
327-
spec.getParameters().getLogLevel().set(logLevel);
328-
spec.getParameters().getUri().set(repositoryExtension.getUri());
329-
spec.getParameters().getCacheDir().set(new File(project.getGradle().getGradleUserHomeDir(), "native-build-tools/repositories"));
330-
});
340+
Provider<GraalVMReachabilityMetadataService> serviceProvider = graalVMReachabilityMetadataService(project, repositoryExtension);
331341
options.getConfigurationFileDirectories().from(repositoryExtension.getEnabled().flatMap(enabled -> {
332342
if (enabled) {
333343
if (repositoryExtension.getUri().isPresent()) {
@@ -358,14 +368,7 @@ private void configureJvmReachabilityConfigurationDirectories(Project project, G
358368

359369
private void configureJvmReachabilityExcludeConfigArgs(Project project, GraalVMExtension graalExtension, NativeImageOptions options, SourceSet sourceSet) {
360370
GraalVMReachabilityMetadataRepositoryExtension repositoryExtension = reachabilityExtensionOn(graalExtension);
361-
Provider<GraalVMReachabilityMetadataService> serviceProvider = project.getGradle()
362-
.getSharedServices()
363-
.registerIfAbsent("nativeConfigurationService", GraalVMReachabilityMetadataService.class, spec -> {
364-
LogLevel logLevel = determineLogLevel();
365-
spec.getParameters().getLogLevel().set(logLevel);
366-
spec.getParameters().getUri().set(repositoryExtension.getUri());
367-
spec.getParameters().getCacheDir().set(new File(project.getGradle().getGradleUserHomeDir(), "native-build-tools/repositories"));
368-
});
371+
Provider<GraalVMReachabilityMetadataService> serviceProvider = graalVMReachabilityMetadataService(project, repositoryExtension);
369372
options.getExcludeConfig().putAll(repositoryExtension.getEnabled().flatMap(enabled -> {
370373
if (enabled) {
371374
if (repositoryExtension.getUri().isPresent()) {
@@ -397,6 +400,18 @@ private void configureJvmReachabilityExcludeConfigArgs(Project project, GraalVME
397400
}));
398401
}
399402

403+
private Provider<GraalVMReachabilityMetadataService> graalVMReachabilityMetadataService(Project project,
404+
GraalVMReachabilityMetadataRepositoryExtension repositoryExtension) {
405+
return project.getGradle()
406+
.getSharedServices()
407+
.registerIfAbsent("nativeConfigurationService", GraalVMReachabilityMetadataService.class, spec -> {
408+
LogLevel logLevel = determineLogLevel();
409+
spec.getParameters().getLogLevel().set(logLevel);
410+
spec.getParameters().getUri().set(repositoryExtension.getUri());
411+
spec.getParameters().getCacheDir().set(new File(project.getGradle().getGradleUserHomeDir(), "native-build-tools/repositories"));
412+
});
413+
}
414+
400415
private static LogLevel determineLogLevel() {
401416
LogLevel logLevel = LogLevel.DEBUG;
402417
String loggingProperty = System.getProperty(CONFIG_REPO_LOGLEVEL);
@@ -475,17 +490,19 @@ private void configureNativeConfigurationRepo(ExtensionAware graalvmNative) {
475490
GraalVMReachabilityMetadataRepositoryExtension configurationRepository = graalvmNative.getExtensions().create("metadataRepository", GraalVMReachabilityMetadataRepositoryExtension.class);
476491
configurationRepository.getEnabled().convention(false);
477492
configurationRepository.getVersion().convention(SharedConstants.METADATA_REPO_DEFAULT_VERSION);
478-
configurationRepository.getUri().convention(configurationRepository.getVersion().map(v -> {
479-
try {
480-
return new URI(String.format(METADATA_REPO_URL_TEMPLATE, v));
481-
} catch (URISyntaxException e) {
482-
throw new RuntimeException(e);
483-
}
484-
}));
493+
configurationRepository.getUri().convention(configurationRepository.getVersion().map(this::getReachabilityMetadataRepositoryUrlForVersion));
485494
configurationRepository.getExcludedModules().convention(Collections.emptySet());
486495
configurationRepository.getModuleToConfigVersion().convention(Collections.emptyMap());
487496
}
488497

498+
private URI getReachabilityMetadataRepositoryUrlForVersion(String version) {
499+
try {
500+
return new URI(String.format(METADATA_REPO_URL_TEMPLATE, version));
501+
} catch (URISyntaxException e) {
502+
throw new RuntimeException(e);
503+
}
504+
}
505+
489506
private TaskProvider<GenerateResourcesConfigFile> registerResourcesConfigTask(Provider<Directory> generatedDir,
490507
NativeImageOptions options,
491508
TaskContainer tasks,

native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/GraalVMReachabilityMetadataService.java

+19
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.graalvm.reachability.GraalVMReachabilityMetadataRepository;
4646
import org.graalvm.reachability.Query;
4747
import org.graalvm.reachability.internal.FileSystemRepository;
48+
import org.gradle.api.artifacts.ModuleVersionIdentifier;
4849
import org.gradle.api.file.ArchiveOperations;
4950
import org.gradle.api.file.DirectoryProperty;
5051
import org.gradle.api.file.FileSystemOperations;
@@ -66,6 +67,8 @@
6667
import java.nio.file.Files;
6768
import java.nio.file.Path;
6869
import java.util.Collection;
70+
import java.util.Map;
71+
import java.util.Objects;
6972
import java.util.Set;
7073
import java.util.function.Consumer;
7174
import java.util.function.Supplier;
@@ -208,4 +211,20 @@ public Set<DirectoryConfiguration> findConfigurationsFor(String gavCoordinates)
208211
public Set<DirectoryConfiguration> findConfigurationsFor(Collection<String> modules) {
209212
return repository.findConfigurationsFor(modules);
210213
}
214+
215+
public Set<DirectoryConfiguration> findConfigurationsFor(Set<String> excludedModules, Map<String, String> forcedVersions, ModuleVersionIdentifier moduleVersion) {
216+
Objects.requireNonNull(moduleVersion);
217+
String groupAndArtifact = moduleVersion.getGroup() + ":" + moduleVersion.getName();
218+
return findConfigurationsFor(query -> {
219+
if (!excludedModules.contains(groupAndArtifact)) {
220+
query.forArtifact(artifact -> {
221+
artifact.gav(groupAndArtifact + ":" + moduleVersion.getVersion());
222+
if (forcedVersions.containsKey(groupAndArtifact)) {
223+
artifact.forceConfigVersion(forcedVersions.get(groupAndArtifact));
224+
}
225+
});
226+
}
227+
query.useLatestConfigWhenVersionIsUntested();
228+
});
229+
}
211230
}

0 commit comments

Comments
 (0)