Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust native-build tools to reachability-metadata.json #614

Merged
merged 9 commits into from
Sep 3, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,35 @@
package org.graalvm.buildtools.gradle

import org.graalvm.buildtools.gradle.fixtures.AbstractFunctionalTest
import org.graalvm.buildtools.gradle.fixtures.GraalVMSupport
import org.graalvm.buildtools.utils.NativeImageUtils
import spock.lang.Unroll

class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest {

def getCurrentJDKVersion() {
return NativeImageUtils.getMajorJDKVersion(GraalVMSupport.getGraalVMHomeVersionString())
}

def metadataInSingleConfigFile() {
return getCurrentJDKVersion() >= 23
}

def metadataExistsAt(String path) {
if (metadataInSingleConfigFile()) {
return file("${path}/reachability-metadata.json").exists()
}

boolean allFilesExist = true
['jni', 'proxy', 'reflect', 'resource', 'serialization'].each { name ->
if (!file("${path}/${name}-config.json").exists()) {
allFilesExist = false
}
}
dnestoro marked this conversation as resolved.
Show resolved Hide resolved

return allFilesExist
}

@Unroll("agent is not passed and the application fails with JUnit Platform #junitVersion")
def "agent is not passed"() {
given:
Expand Down Expand Up @@ -94,18 +119,13 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest {
""".trim()

and:
['jni', 'proxy', 'reflect', 'resource', 'serialization'].each { name ->
assert file("build/native/agent-output/test/${name}-config.json").exists()
}
assert metadataExistsAt("build/native/agent-output/test")

when:
run 'metadataCopy'

then:
['jni', 'proxy', 'reflect', 'resource', 'serialization'].each { name ->
assert file("build/native/metadataCopyTest/${name}-config.json").exists()
}

assert metadataExistsAt("build/native/metadataCopyTest")

where:
junitVersion = System.getProperty('versions.junit')
Expand All @@ -125,7 +145,11 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest {
}

and:
assert file("build/native/agent-output/test/reflect-config.json").text.contains("\"condition\"")
if (metadataInSingleConfigFile()) {
assert file("build/native/agent-output/test/reachability-metadata.json").text.contains("\"condition\"")
} else {
assert file("build/native/agent-output/test/reflect-config.json").text.contains("\"condition\"")
}

where:
junitVersion = System.getProperty('versions.junit')
Expand All @@ -148,22 +172,26 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest {
}

and:
['jni', 'proxy', 'reflect', 'resource', 'serialization'].each { name ->
assert file("build/native/agent-output/run/${name}-config.json").exists()
}
assert metadataExistsAt("build/native/agent-output/run")

when:
run'metadataCopy', '--task', 'run', '--dir', metadata_dir
run 'metadataCopy', '--task', 'run', '--dir', metadata_dir

then:
['jni', 'proxy', 'reflect', 'resource', 'serialization'].each { name ->
assert file("${metadata_dir}/${name}-config.json").exists()
}
assert metadataExistsAt(metadata_dir)

and:
var reflect_config = file("${metadata_dir}/reflect-config.json")
var reflect_config_contents = reflect_config.text
assert reflect_config_contents.contains("DummyClass") && reflect_config_contents.contains("org.graalvm.demo.Message")
if (metadataInSingleConfigFile()) {
var reachabilityMetadata = file("${metadata_dir}/reachability-metadata.json")
var reachabilityMetadataContents = reachabilityMetadata.text
println reachabilityMetadataContents
assert reachabilityMetadataContents.contains("DummyClass"), reachabilityMetadataContents
assert reachabilityMetadataContents.contains("org.graalvm.demo.Message"), reachabilityMetadataContents
} else {
var reflect_config = file("${metadata_dir}/reflect-config.json")
var reflect_config_contents = reflect_config.text
assert reflect_config_contents.contains("DummyClass") && reflect_config_contents.contains("org.graalvm.demo.Message")
}

when:
run 'nativeRun'
Expand All @@ -190,9 +218,7 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest {
}

and:
['jni', 'proxy', 'reflect', 'resource', 'serialization'].each { name ->
assert file("build/native/agent-output/run/${name}-config.json").exists()
}
assert metadataExistsAt("build/native/agent-output/run")

when:
run'run', '-Pagent', '--configuration-cache', '--rerun-tasks'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@
import org.gradle.jvm.toolchain.JavaToolchainService;

import javax.inject.Inject;
import java.util.Arrays;

public abstract class DefaultGraalVmExtension implements GraalVMExtension {
private final transient NamedDomainObjectContainer<NativeImageOptions> nativeImages;
Expand All @@ -79,7 +78,8 @@ public DefaultGraalVmExtension(NamedDomainObjectContainer<NativeImageOptions> na
agentOpts.getEnabled().convention(false);
agentOpts.getModes().getConditional().getParallel().convention(true);
agentOpts.getMetadataCopy().getMergeWithExisting().convention(false);
agentOpts.getFilterableEntries().convention(Arrays.asList("org.gradle.", "org.junit."));
// TODO: replace with agent access filter
// agentOpts.getFilterableEntries().convention(Arrays.asList("org.gradle.", "org.junit."));
dnestoro marked this conversation as resolved.
Show resolved Hide resolved
agentOpts.getBuiltinHeuristicFilter().convention(true);
agentOpts.getBuiltinCallerFilter().convention(true);
agentOpts.getEnableExperimentalPredefinedClasses().convention(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;

import static org.graalvm.buildtools.gradle.internal.NativeImageExecutableLocator.findNativeImageExecutable;
Expand Down Expand Up @@ -94,8 +95,11 @@ public MergeAgentFilesAction(Provider<Boolean> isMergingEnabled,
this.noLauncherProperty = objectFactory.property(JavaLauncher.class);
}

private static final Set<String> metadataFiles = Set.of("reflect-config.json", "jni-config.json", "proxy-config.json", "resource-config.json", "reachability-metadata.json");
dnestoro marked this conversation as resolved.
Show resolved Hide resolved

private static boolean isConfigDir(String dir) {
return Arrays.stream(new File(dir).listFiles()).anyMatch(file -> file.getName().equals("reflect-config.json"));
return Arrays.stream(new File(dir).listFiles())
.anyMatch(file -> metadataFiles.contains(file.getName()));
dnestoro marked this conversation as resolved.
Show resolved Hide resolved
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,27 @@ class GraalVMSupport {
(System.getProperty("java.vendor.version", "") - 'GraalVM' - 'CE' - 'EE').trim()
}

static String getJavaHomeVersionString() {
String javaHomeLocation = System.getenv("JAVA_HOME")
return extractVersionString(javaHomeLocation)
}

static String getGraalVMHomeVersionString() {
String graalvmHomeLocation = System.getenv("GRAALVM_HOME")
return extractVersionString(graalvmHomeLocation)
}

private static String extractVersionString(String location) {
def sout = new StringBuilder(), serr = new StringBuilder()
String command = getSystemBasedCommand(location);
def proc = command.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
assert serr.toString().isEmpty()

return sout.toString()
}

static int getMajorVersion() {
String v = version
v.substring(0, v.indexOf('.')).toInteger()
Expand All @@ -62,4 +83,12 @@ class GraalVMSupport {
String v = version - "${majorVersion}."
v.substring(0, v.indexOf('.')).toInteger()
}

private static String getSystemBasedCommand(String location) {
if (System.getProperty("os.name", "unknown").contains("Windows")) {
return location + '\\bin\\native-image.cmd --version'
} else {
return location + '/bin/native-image --version'
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
public class MetadataCopyMojo extends AbstractMergeAgentFilesMojo {

private static final String DEFAULT_OUTPUT_DIRECTORY = "/META-INF/native-image";
private static final List<String> FILES_REQUIRED_FOR_MERGE = Arrays.asList("reflect-config.json", "jni-config.json", "proxy-config.json", "resource-config.json");
private static final List<String> FILES_REQUIRED_FOR_MERGE_LEGACY = Arrays.asList("reflect-config.json", "jni-config.json", "proxy-config.json", "resource-config.json");
private static final List<String> FILES_REQUIRED_FOR_MERGE = Arrays.asList("reachability-metadata.json");

@Parameter(alias = "agent")
private AgentConfiguration agentConfiguration;
Expand Down Expand Up @@ -136,7 +137,7 @@ private void executeCopy(String buildDirectory, String destinationDir) throws Mo

throw new MojoExecutionException("There are missing files for merge in output directory. If you want to merge agent files with " +
"existing files in output directory, please make sure that output directory contains all of the following files: " +
"reflect-config.json, jni-config.json, proxy-config.json, resource-config.json. Currently the output directory is " +
"reflect-config.json, jni-config.json, proxy-config.json, resource-config.json, reachability-metadata.json. Currently the output directory is " +
"missing: " + missingFiles);
}

Expand Down Expand Up @@ -209,7 +210,8 @@ private boolean dirContainsFilesForMerge(String dir) {
}
List<String> dirContent = Arrays.stream(content).map(File::getName).collect(Collectors.toList());

return getListDiff(FILES_REQUIRED_FOR_MERGE, dirContent).isEmpty();
return getListDiff(FILES_REQUIRED_FOR_MERGE, dirContent).isEmpty() ||
getListDiff(FILES_REQUIRED_FOR_MERGE_LEGACY, dirContent).isEmpty();
}

private List<String> getListDiff(List<String> list1, List<String> list2) {
Expand Down
Loading