From 7bb291c1835864bd4e859e02467c278c09c92053 Mon Sep 17 00:00:00 2001 From: Vojin Jovanovic Date: Mon, 12 Aug 2024 22:09:24 +0200 Subject: [PATCH 1/9] Adjust native-build tools to reachability-metadata.json --- ...aApplicationWithAgentFunctionalTest.groovy | 38 +++++++++---------- .../internal/DefaultGraalVmExtension.java | 3 +- .../tasks/actions/MergeAgentFilesAction.java | 6 ++- .../buildtools/maven/MetadataCopyMojo.java | 8 ++-- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy b/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy index 15e976132..7135db226 100644 --- a/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy +++ b/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy @@ -46,6 +46,10 @@ import spock.lang.Unroll class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest { + def metadataExistsAt(String path) { + file("${path}/reachability-metadata.json").exists() + } + @Unroll("agent is not passed and the application fails with JUnit Platform #junitVersion") def "agent is not passed"() { given: @@ -94,18 +98,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') @@ -125,7 +124,7 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest { } and: - assert file("build/native/agent-output/test/reflect-config.json").text.contains("\"condition\"") + assert file("build/native/agent-output/test/reachability-metadata.json").text.contains("\"condition\"") where: junitVersion = System.getProperty('versions.junit') @@ -148,22 +147,21 @@ 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") + 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 + when: run 'nativeRun' @@ -190,9 +188,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' diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java index 1d4235f6c..82c1cebf3 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java @@ -79,7 +79,8 @@ public DefaultGraalVmExtension(NamedDomainObjectContainer 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.")); agentOpts.getBuiltinHeuristicFilter().convention(true); agentOpts.getBuiltinCallerFilter().convention(true); agentOpts.getEnableExperimentalPredefinedClasses().convention(false); diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java index 013479ce4..8e0e5ed99 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java @@ -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; @@ -94,8 +95,11 @@ public MergeAgentFilesAction(Provider isMergingEnabled, this.noLauncherProperty = objectFactory.property(JavaLauncher.class); } + private static final Set metadataFiles = Set.of("reflect-config.json", "jni-config.json", "proxy-config.json", "resource-config.json", "reachability-metadata.json"); + 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())); } @Override diff --git a/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/MetadataCopyMojo.java b/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/MetadataCopyMojo.java index 267a40498..67b7b5494 100644 --- a/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/MetadataCopyMojo.java +++ b/native-maven-plugin/src/main/java/org/graalvm/buildtools/maven/MetadataCopyMojo.java @@ -66,7 +66,8 @@ public class MetadataCopyMojo extends AbstractMergeAgentFilesMojo { private static final String DEFAULT_OUTPUT_DIRECTORY = "/META-INF/native-image"; - private static final List FILES_REQUIRED_FOR_MERGE = Arrays.asList("reflect-config.json", "jni-config.json", "proxy-config.json", "resource-config.json"); + private static final List FILES_REQUIRED_FOR_MERGE_LEGACY = Arrays.asList("reflect-config.json", "jni-config.json", "proxy-config.json", "resource-config.json"); + private static final List FILES_REQUIRED_FOR_MERGE = Arrays.asList("reachability-metadata.json"); @Parameter(alias = "agent") private AgentConfiguration agentConfiguration; @@ -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); } @@ -209,7 +210,8 @@ private boolean dirContainsFilesForMerge(String dir) { } List 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 getListDiff(List list1, List list2) { From e5d055aa4cc160828552b47718ff36d82bdc066c Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Tue, 13 Aug 2024 16:55:53 +0200 Subject: [PATCH 2/9] Perform differnet checks in tests based on jdk version --- ...aApplicationWithAgentFunctionalTest.groovy | 46 +++++++++++++++---- .../internal/DefaultGraalVmExtension.java | 1 - .../gradle/fixtures/GraalVMSupport.groovy | 20 ++++++++ 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy b/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy index 7135db226..3f39e6852 100644 --- a/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy +++ b/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy @@ -42,12 +42,33 @@ 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) { - file("${path}/reachability-metadata.json").exists() + 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 + } + } + + return allFilesExist } @Unroll("agent is not passed and the application fails with JUnit Platform #junitVersion") @@ -124,7 +145,11 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest { } and: - assert file("build/native/agent-output/test/reachability-metadata.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') @@ -156,12 +181,17 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest { assert metadataExistsAt(metadata_dir) and: - 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 - + 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' diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java index 82c1cebf3..c5c04a37d 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java @@ -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 nativeImages; diff --git a/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy b/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy index 9c357ebd6..d67708a05 100644 --- a/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy +++ b/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy @@ -53,6 +53,26 @@ 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() + def proc = (location + '/bin/native-image --version').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() From 04e873544054cf812be9c1f4e3ec5558db52ae20 Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Tue, 13 Aug 2024 17:53:54 +0200 Subject: [PATCH 3/9] Execute different version commands based on the system --- .../buildtools/gradle/fixtures/GraalVMSupport.groovy | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy b/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy index d67708a05..08b034fb8 100644 --- a/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy +++ b/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy @@ -65,7 +65,8 @@ class GraalVMSupport { private static String extractVersionString(String location) { def sout = new StringBuilder(), serr = new StringBuilder() - def proc = (location + '/bin/native-image --version').execute() + String command = getSystemBasedCommand(location); + def proc = command.execute() proc.consumeProcessOutput(sout, serr) proc.waitForOrKill(1000) assert serr.toString().isEmpty() @@ -82,4 +83,12 @@ class GraalVMSupport { String v = version - "${majorVersion}." v.substring(0, v.indexOf('.')).toInteger() } + + private static boolean 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' + } + } } From 07737516eb701b5f4bbc273ff1ff28ea70a853c7 Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Wed, 14 Aug 2024 14:28:09 +0200 Subject: [PATCH 4/9] Fix return type of command generating function --- .../graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy b/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy index 08b034fb8..344bccee4 100644 --- a/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy +++ b/native-gradle-plugin/src/testFixtures/groovy/org/graalvm/buildtools/gradle/fixtures/GraalVMSupport.groovy @@ -84,7 +84,7 @@ class GraalVMSupport { v.substring(0, v.indexOf('.')).toInteger() } - private static boolean getSystemBasedCommand(String location) { + private static String getSystemBasedCommand(String location) { if (System.getProperty("os.name", "unknown").contains("Windows")) { return location + '\\bin\\native-image.cmd --version' } else { From 1411a607907df518fb6a63d31e4fa406d03759db Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Wed, 21 Aug 2024 18:15:23 +0200 Subject: [PATCH 5/9] Simplify file existence check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cédric Champeau --- .../gradle/JavaApplicationWithAgentFunctionalTest.groovy | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy b/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy index 3f39e6852..7d8566b6a 100644 --- a/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy +++ b/native-gradle-plugin/src/functionalTest/groovy/org/graalvm/buildtools/gradle/JavaApplicationWithAgentFunctionalTest.groovy @@ -61,11 +61,8 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest { 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 - } + boolean allFilesExist = ['jni', 'proxy', 'reflect', 'resource', 'serialization'].every { name -> + file("${path}/${name}-config.json").exists() } return allFilesExist From 1a8fddd1bf582b37e3737caa8a854597f5f1458d Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Wed, 21 Aug 2024 18:16:50 +0200 Subject: [PATCH 6/9] Use capital case for static variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cédric Champeau --- .../buildtools/gradle/tasks/actions/MergeAgentFilesAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java index 8e0e5ed99..0408c740f 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java @@ -95,7 +95,7 @@ public MergeAgentFilesAction(Provider isMergingEnabled, this.noLauncherProperty = objectFactory.property(JavaLauncher.class); } - private static final Set metadataFiles = Set.of("reflect-config.json", "jni-config.json", "proxy-config.json", "resource-config.json", "reachability-metadata.json"); + private static final Set METADATA_FILES = Set.of("reflect-config.json", "jni-config.json", "proxy-config.json", "resource-config.json", "reachability-metadata.json"); private static boolean isConfigDir(String dir) { return Arrays.stream(new File(dir).listFiles()) From a02c0421936d644c6418f18d4619190905dbff94 Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Wed, 21 Aug 2024 18:17:19 +0200 Subject: [PATCH 7/9] Refactor code after variable renaming MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cédric Champeau --- .../buildtools/gradle/tasks/actions/MergeAgentFilesAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java index 0408c740f..e2040b9b2 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java @@ -99,7 +99,7 @@ public MergeAgentFilesAction(Provider isMergingEnabled, private static boolean isConfigDir(String dir) { return Arrays.stream(new File(dir).listFiles()) - .anyMatch(file -> metadataFiles.contains(file.getName())); + .anyMatch(file -> METADATA_FILES.contains(file.getName())); } @Override From 9e9703ce6be9cd57a57c691da9b4d1d776211a94 Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Thu, 29 Aug 2024 16:03:42 +0200 Subject: [PATCH 8/9] Use access-filter for filtering gradle and junit metadata --- .../buildtools/agent/AgentConfiguration.java | 23 +++ .../src/main/resources/access-filter.json | 13 ++ .../buildtools/gradle/NativeImagePlugin.java | 6 - .../internal/DefaultGraalVmExtension.java | 2 - ...cessGeneratedGraalResourceFilesAction.java | 166 ------------------ 5 files changed, 36 insertions(+), 174 deletions(-) create mode 100644 common/utils/src/main/resources/access-filter.json delete mode 100644 native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/ProcessGeneratedGraalResourceFilesAction.java diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java index 105311a43..63bb59dbf 100644 --- a/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java @@ -40,13 +40,21 @@ */ package org.graalvm.buildtools.agent; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; import java.io.Serializable; +import java.nio.file.CopyOption; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Collection; import java.util.List; public class AgentConfiguration implements Serializable { + private static final String DEFAULT_ACCESS_FILTER_FILE = "/access-filter.json"; private final Collection callerFilterFiles; private final Collection accessFilterFiles; private final Boolean builtinCallerFilter; @@ -79,6 +87,7 @@ public AgentConfiguration(Collection callerFilterFiles, AgentMode agentMode) { this.callerFilterFiles = callerFilterFiles; this.accessFilterFiles = accessFilterFiles; + addDefaultAccessFilter(); this.builtinCallerFilter = builtinCallerFilter; this.builtinHeuristicFilter = builtinHeuristicFilter; this.experimentalPredefinedClasses = experimentalPredefinedClasses; @@ -127,4 +136,18 @@ private void addToCmd(String option, Boolean value, List cmdLine) { } } + private void addDefaultAccessFilter() { + try(InputStream accessFilter = AgentConfiguration.class.getResourceAsStream(DEFAULT_ACCESS_FILTER_FILE)) { + if (accessFilter != null) { + Path accessFilterPath = Files.createTempFile("access-filter", ".json"); + Files.copy(accessFilter, accessFilterPath, StandardCopyOption.REPLACE_EXISTING); + accessFilterFiles.add(accessFilterPath.toString()); + } else { + throw new IOException("Cannot find access-filter.json on default location: " + DEFAULT_ACCESS_FILTER_FILE); + } + } catch (IOException e) { + throw new RuntimeException("Cannot add default access-filter.json" ,e); + } + } + } diff --git a/common/utils/src/main/resources/access-filter.json b/common/utils/src/main/resources/access-filter.json new file mode 100644 index 000000000..4781418b7 --- /dev/null +++ b/common/utils/src/main/resources/access-filter.json @@ -0,0 +1,13 @@ +{ + "rules": [ + { + "includeClasses": "**" + }, + { + "excludeClasses": "org.gradle.**" + }, + { + "excludeClasses": "org.junit.**" + } + ] +} \ No newline at end of file diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/NativeImagePlugin.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/NativeImagePlugin.java index 89685b41d..dfa3b521a 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/NativeImagePlugin.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/NativeImagePlugin.java @@ -64,7 +64,6 @@ import org.graalvm.buildtools.gradle.tasks.NativeRunTask; import org.graalvm.buildtools.gradle.tasks.actions.CleanupAgentFilesAction; import org.graalvm.buildtools.gradle.tasks.actions.MergeAgentFilesAction; -import org.graalvm.buildtools.gradle.tasks.actions.ProcessGeneratedGraalResourceFilesAction; import org.graalvm.buildtools.utils.SharedConstants; import org.graalvm.reachability.DirectoryConfiguration; import org.gradle.api.Action; @@ -871,11 +870,6 @@ public void execute(@Nonnull Task task) { execOperations)); taskToInstrument.doLast(new CleanupAgentFilesAction(mergeInputDirs, fileOperations)); - - taskToInstrument.doLast(new ProcessGeneratedGraalResourceFilesAction( - outputDir, - graalExtension.getAgent().getFilterableEntries() - )); } private static void injectTestPluginDependencies(Project project, Property testSupportEnabled) { diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java index c5c04a37d..9bc4d1662 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java @@ -78,8 +78,6 @@ public DefaultGraalVmExtension(NamedDomainObjectContainer na agentOpts.getEnabled().convention(false); agentOpts.getModes().getConditional().getParallel().convention(true); agentOpts.getMetadataCopy().getMergeWithExisting().convention(false); - // TODO: replace with agent access filter - // agentOpts.getFilterableEntries().convention(Arrays.asList("org.gradle.", "org.junit.")); agentOpts.getBuiltinHeuristicFilter().convention(true); agentOpts.getBuiltinCallerFilter().convention(true); agentOpts.getEnableExperimentalPredefinedClasses().convention(false); diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/ProcessGeneratedGraalResourceFilesAction.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/ProcessGeneratedGraalResourceFilesAction.java deleted file mode 100644 index aaefbd3a0..000000000 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/ProcessGeneratedGraalResourceFilesAction.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * The Universal Permissive License (UPL), Version 1.0 - * - * Subject to the condition set forth below, permission is hereby granted to any - * person obtaining a copy of this software, associated documentation and/or - * data (collectively the "Software"), free of charge and under any and all - * copyright rights in the Software, and any and all patent rights owned or - * freely licensable by each licensor hereunder covering either (i) the - * unmodified Software as contributed to or provided by such licensor, or (ii) - * the Larger Works (as defined below), to deal in both - * - * (a) the Software, and - * - * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if - * one is included with the Software each a "Larger Work" to which the Software - * is contributed by such licensors), - * - * without restriction, including without limitation the rights to copy, create - * derivative works of, display, perform, and distribute the Software and make, - * use, sell, offer for sale, import, export, have made, and have sold the - * Software and the Larger Work(s), and to sublicense the foregoing rights on - * either these or other terms. - * - * This license is subject to the following condition: - * - * The above copyright notice and either this complete permission notice or at a - * minimum a reference to the UPL must be included in all copies or substantial - * portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package org.graalvm.buildtools.gradle.tasks.actions; - -import groovy.json.JsonGenerator; -import groovy.json.JsonOutput; -import groovy.json.JsonSlurper; -import org.gradle.api.Action; -import org.gradle.api.GradleException; -import org.gradle.api.Task; -import org.gradle.api.file.Directory; -import org.gradle.api.provider.ListProperty; -import org.gradle.api.provider.Provider; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * This task is responsible for processing the JSON files generated by - * the GraalVM agent, in particular to filter out entries which are - * inherited from the Gradle environment itself. - */ -public class ProcessGeneratedGraalResourceFilesAction implements Action { - private final Provider inputDirectory; - private final ListProperty filterableEntries; - - public ProcessGeneratedGraalResourceFilesAction(Provider inputDirectory, ListProperty filterableEntries) { - this.inputDirectory = inputDirectory; - this.filterableEntries = filterableEntries; - } - - @Override - public void execute(Task task) { - try { - for (File resourceFile : inputDirectory.get().getAsFileTree()) { - processFile(resourceFile); - } - } catch (IOException e) { - throw new GradleException("An IO error occured when processing the agent generated files", e); - } - } - - protected void processFile(File file) throws IOException { - if (file.getName().endsWith(".json")) { - processJsonFile(file); - } - } - - protected void processJsonFile(File jsonFile) throws IOException { - JsonSlurper json = new JsonSlurper(); - Object result = json.parse(jsonFile); - Object filtered = filter(result); - JsonGenerator generator = new JsonGenerator.Options() - .build(); - String processed = JsonOutput.prettyPrint(generator.toJson(filtered)); - try (Writer writer = new OutputStreamWriter(new FileOutputStream(jsonFile), StandardCharsets.UTF_8)) { - writer.write(processed); - } - } - - /** - * Filters the parsed JSON file to remove entries which are configured - * by the filterable entries parameter. This is a very rough algorithm - * which would deserve specific implementation for each JSON format. - * Instead it takes a "brute force" approach which may result in some - * weird errors. - */ - @SuppressWarnings("unchecked") - private Object filter(Object in) { - Class clazz = in.getClass(); - if (shouldFilterString(in)) { - return null; - } - if (List.class.isAssignableFrom(clazz)) { - return filterList((List) in); - } - if (Map.class.isAssignableFrom(clazz)) { - return filterMap((Map) in); - } - return in; - } - - private Map filterMap(Map map) { - if (shouldFilterString(map.get("name"))) { - return null; - } - Map out = new HashMap<>(map.size()); - for (Map.Entry entry : map.entrySet()) { - Object key = entry.getKey(); - Object value = entry.getValue(); - if (shouldFilterString(value)) { - continue; - } - out.put(key, filter(value)); - } - return out; - } - - private boolean shouldFilterString(Object value) { - if (value instanceof CharSequence) { - String string = value.toString(); - return filterableEntries.get().stream().anyMatch(string::startsWith); - } - return false; - } - - private List filterList(List in) { - List out = new ArrayList<>(in.size()); - for (Object element : in) { - Object filtered = filter(element); - if (filtered == null || (filtered instanceof Collection && ((Collection) filtered).isEmpty())) { - continue; - } - out.add(filtered); - } - return out; - } -} From ef4b53629872a5e246377a083ea2cd9cc4d0cc43 Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Tue, 3 Sep 2024 14:02:09 +0200 Subject: [PATCH 9/9] Add access-filter file with fixed path --- .../buildtools/agent/AgentConfiguration.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java index 63bb59dbf..2072b4cdb 100644 --- a/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java @@ -87,7 +87,6 @@ public AgentConfiguration(Collection callerFilterFiles, AgentMode agentMode) { this.callerFilterFiles = callerFilterFiles; this.accessFilterFiles = accessFilterFiles; - addDefaultAccessFilter(); this.builtinCallerFilter = builtinCallerFilter; this.builtinHeuristicFilter = builtinHeuristicFilter; this.experimentalPredefinedClasses = experimentalPredefinedClasses; @@ -97,6 +96,7 @@ public AgentConfiguration(Collection callerFilterFiles, } public List getAgentCommandLine() { + addDefaultAccessFilter(); List cmdLine = new ArrayList<>(agentMode.getAgentCommandLine()); appendOptionToValues("caller-filter-file=", callerFilterFiles, cmdLine); appendOptionToValues("access-filter-file=", accessFilterFiles, cmdLine); @@ -137,11 +137,27 @@ private void addToCmd(String option, Boolean value, List cmdLine) { } private void addDefaultAccessFilter() { + if (accessFilterFiles == null) { + // this could only happen if we instantiated disabled agent configuration + return; + } + + String tempDir = System.getProperty("java.io.tmpdir"); + Path agentDir = Path.of(tempDir).resolve("agent-config"); + Path accessFilterFile = agentDir.resolve("access-filter.json"); + if (Files.exists(accessFilterFile)) { + accessFilterFiles.add(accessFilterFile.toString()); + return; + } + try(InputStream accessFilter = AgentConfiguration.class.getResourceAsStream(DEFAULT_ACCESS_FILTER_FILE)) { if (accessFilter != null) { - Path accessFilterPath = Files.createTempFile("access-filter", ".json"); - Files.copy(accessFilter, accessFilterPath, StandardCopyOption.REPLACE_EXISTING); - accessFilterFiles.add(accessFilterPath.toString()); + if (!Files.exists(agentDir)) { + Files.createDirectory(agentDir); + } + + Files.copy(accessFilter, accessFilterFile, StandardCopyOption.REPLACE_EXISTING); + accessFilterFiles.add(accessFilterFile.toString()); } else { throw new IOException("Cannot find access-filter.json on default location: " + DEFAULT_ACCESS_FILTER_FILE); }