From 7bb291c1835864bd4e859e02467c278c09c92053 Mon Sep 17 00:00:00 2001 From: Vojin Jovanovic Date: Mon, 12 Aug 2024 22:09:24 +0200 Subject: [PATCH 01/14] 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 02/14] 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 03/14] 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 04/14] 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 05/14] 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 06/14] 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 07/14] 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 08/14] 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 09/14] 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); } From a221227c23c35c84d0fb06a5db0eaaac7507b51e Mon Sep 17 00:00:00 2001 From: linghengqian Date: Thu, 13 Jun 2024 23:14:58 +0800 Subject: [PATCH 10/14] Fixes the issue that nativeTest cannot be executed using Junit 5.11.0-M2 --- .../platform/config/platform/PlatformConfigProvider.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/platform/PlatformConfigProvider.java b/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/platform/PlatformConfigProvider.java index d9c03eb16..4b94023b1 100644 --- a/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/platform/PlatformConfigProvider.java +++ b/common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/platform/PlatformConfigProvider.java @@ -60,7 +60,9 @@ public void onLoad(NativeImageConfiguration config) { "org.junit.platform.engine.UniqueIdFormat", "org.junit.platform.commons.util.ReflectionUtils", // https://github.com/graalvm/native-build-tools/issues/300 - "org.junit.platform.reporting.open.xml.OpenTestReportGeneratingListener" + "org.junit.platform.reporting.open.xml.OpenTestReportGeneratingListener", + // https://github.com/graalvm/native-build-tools/issues/602 + "org.junit.platform.commons.util.LruCache" ); if (getMajorJDKVersion() >= 21) { From 357b7475c4cbffd1e6ffa081f26bcbf1f8a50b14 Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Tue, 3 Sep 2024 14:42:39 +0200 Subject: [PATCH 11/14] Bump metadata repository version to 0.3.9 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 90e2120df..a6f9882a1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] # Project versions nativeBuildTools = "0.10.3-SNAPSHOT" -metadataRepository = "0.3.8" +metadataRepository = "0.3.9" # External dependencies spock = "2.1-groovy-3.0" From 0a05df5ed491c118820881f5011abb24a6983928 Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Tue, 3 Sep 2024 15:13:03 +0200 Subject: [PATCH 12/14] Fix broken link for quick build mode --- docs/src/docs/asciidoc/maven-plugin.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/docs/asciidoc/maven-plugin.adoc b/docs/src/docs/asciidoc/maven-plugin.adoc index 67d6eaf89..46edea173 100644 --- a/docs/src/docs/asciidoc/maven-plugin.adoc +++ b/docs/src/docs/asciidoc/maven-plugin.adoc @@ -173,7 +173,7 @@ Build Configuration]. It is also possible to customize the plugin within a true ---- ``:: - If you want to build the image using https://blogs.oracle.com/java/post/graalvm-enterprise-221--faster-smarter-leaner[quick build mode], supply the following in the configuration of the plugin (alternatively set the `GRAALVM_QUICK_BUILD` environment variable to `true`): + If you want to build the image using https://www.graalvm.org/latest/reference-manual/native-image/overview/BuildOutput/#qbm-use-quick-build-mode-for-faster-builds[quick build mode], supply the following in the configuration of the plugin (alternatively set the `GRAALVM_QUICK_BUILD` environment variable to `true`): [source,xml] ---- true From 3fdca05ddc27e814fe291879e08f9ac9036f2a79 Mon Sep 17 00:00:00 2001 From: David Nestorovic Date: Tue, 3 Sep 2024 14:48:59 +0200 Subject: [PATCH 13/14] Add missing changelog entries --- docs/src/docs/asciidoc/index.adoc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/src/docs/asciidoc/index.adoc b/docs/src/docs/asciidoc/index.adoc index d14e45e0b..703456ede 100644 --- a/docs/src/docs/asciidoc/index.adoc +++ b/docs/src/docs/asciidoc/index.adoc @@ -22,6 +22,8 @@ If you are using alternative build systems, see < Date: Fri, 30 Aug 2024 16:36:44 +0200 Subject: [PATCH 14/14] Fix error message when the JDK is not a GraalVM --- .../NativeImageExecutableLocator.java | 42 +++++++++---------- .../utils/NativeImageConfigurationUtils.java | 31 +++++++------- 2 files changed, 35 insertions(+), 38 deletions(-) diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageExecutableLocator.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageExecutableLocator.java index ae05fcb61..0a77f440d 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageExecutableLocator.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageExecutableLocator.java @@ -91,29 +91,29 @@ public static File findNativeImageExecutable(Property javaLauncher executablePath = metadata.getInstallationPath().file("bin/" + NATIVE_IMAGE_EXE).getAsFile(); } - try { - if (!executablePath.exists()) { - logger.log("Native Image executable wasn't found. We will now try to download it. "); - File graalVmHomeGuess = executablePath.getParentFile(); - - File guPath = graalVmHomeGuess.toPath().resolve(GU_EXE).toFile(); - if (!guPath.exists()) { - throw new GradleException("'" + GU_EXE + "' at '" + guPath + "' tool wasn't found. This probably means that JDK at isn't a GraalVM distribution."); - } - ExecResult res = execOperations.exec(spec -> { - spec.args("install", "native-image"); - spec.setExecutable(Paths.get(graalVmHomeGuess.getAbsolutePath(), GU_EXE)); - }); - if (res.getExitValue() != 0) { - throw new GradleException("Native Image executable wasn't found, and '" + GU_EXE + "' tool failed to install it."); - } - diagnostics.withGuInstall(); + File graalVmHomeGuess = executablePath.getParentFile(); + File guPath = graalVmHomeGuess.toPath().resolve(GU_EXE).toFile(); + if (guPath.exists() && !executablePath.exists()) { + logger.log("Native Image executable wasn't found. We will now try to download it. "); + + ExecResult res = execOperations.exec(spec -> { + spec.args("install", "native-image"); + spec.setExecutable(Paths.get(graalVmHomeGuess.getAbsolutePath(), GU_EXE)); + }); + if (res.getExitValue() != 0) { + throw new GradleException("Native Image executable wasn't found, and '" + GU_EXE + "' tool failed to install it.\n" + + "Make sure to declare the GRAALVM_HOME or JAVA_HOME environment variable or install GraalVM with " + + "native-image in a standard location recognized by Gradle Java toolchain support"); } - } catch (GradleException e) { - throw new GradleException("Determining GraalVM installation failed with message: " + e.getMessage() + "\n\n" - + "Make sure to declare the GRAALVM_HOME environment variable or install GraalVM with " + - "native-image in a standard location recognized by Gradle Java toolchain support"); + diagnostics.withGuInstall(); } + + if (!executablePath.exists()) { + throw new GradleException(executablePath + " wasn't found. This probably means that JDK isn't a GraalVM distribution.\n" + + "Make sure to declare the GRAALVM_HOME or JAVA_HOME environment variable or install GraalVM with" + + "native-image in a standard location recognized by Gradle Java toolchain support"); + } + diagnostics.withExecutablePath(executablePath); return executablePath; } diff --git a/native-maven-plugin/src/main/java/org/graalvm/buildtools/utils/NativeImageConfigurationUtils.java b/native-maven-plugin/src/main/java/org/graalvm/buildtools/utils/NativeImageConfigurationUtils.java index e3401033b..364e051c6 100644 --- a/native-maven-plugin/src/main/java/org/graalvm/buildtools/utils/NativeImageConfigurationUtils.java +++ b/native-maven-plugin/src/main/java/org/graalvm/buildtools/utils/NativeImageConfigurationUtils.java @@ -69,34 +69,31 @@ public static Path getJavaHomeNativeImage(String javaHomeVariable, Boolean failF Path graalHomePath = Paths.get(graalHome); Path nativeImageExe = graalHomePath.resolve("bin").resolve(NATIVE_IMAGE_EXE); + Path guExe = graalHomePath.resolve("bin").resolve(GU_EXE); - if (!Files.exists(nativeImageExe)) { - Path guExe = graalHomePath.resolve("bin").resolve(GU_EXE); - if (Files.exists(guExe)) { - ProcessBuilder processBuilder = new ProcessBuilder(guExe.toString(), "install", "native-image"); - processBuilder.inheritIO(); - try { - Process nativeImageFetchingProcess = processBuilder.start(); - if (nativeImageFetchingProcess.waitFor() != 0) { - throw new MojoExecutionException("native-image was not found, and '" + GU_EXE + "' tool failed to install it."); - } - } catch (MojoExecutionException | IOException | InterruptedException e) { - throw new MojoExecutionException("Determining GraalVM installation failed with message: " + e.getMessage()); + if (Files.exists(guExe) && !Files.exists(nativeImageExe)) { + ProcessBuilder processBuilder = new ProcessBuilder(guExe.toString(), "install", "native-image"); + processBuilder.inheritIO(); + try { + Process nativeImageFetchingProcess = processBuilder.start(); + if (nativeImageFetchingProcess.waitFor() != 0) { + throw new MojoExecutionException("native-image was not found, and '" + GU_EXE + "' tool failed to install it."); } - } else if (failFast) { - throw new MojoExecutionException("'" + GU_EXE + "' tool was not found in your " + javaHomeVariable + "." + - "This probably means that the JDK at '" + graalHomePath + "' is not a GraalVM distribution."); + } catch (MojoExecutionException | IOException | InterruptedException e) { + throw new MojoExecutionException("Determining GraalVM installation failed with message: " + e.getMessage()); } } if (!Files.exists(nativeImageExe)) { if (failFast) { - throw new RuntimeException("native-image is not installed in your " + javaHomeVariable + "." + - "This probably means that the JDK at '" + graalHomePath + "' is not a GraalVM distribution."); + throw new MojoExecutionException("native-image is not installed in your " + javaHomeVariable + "." + + "This probably means that the JDK at '" + graalHomePath + "' is not a GraalVM distribution. " + + "The GraalVM Native Maven Plugin requires GRAALVM_HOME or JAVA_HOME to be a GraalVM distribution."); } else { return null; } } + logger.info("Found GraalVM installation from " + javaHomeVariable + " variable."); return nativeImageExe; }