From 5bb0697e681f68bde18c1f874b89d496546f95c7 Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Thu, 12 May 2022 18:48:02 +0200 Subject: [PATCH] WIP --- .../buildtools/agent/AgentConfiguration.java | 20 ++- .../buildtools/gradle/NativeImagePlugin.java | 140 +++++++++++++----- .../gradle/dsl/GraalVMExtension.java | 4 + .../gradle/dsl/NativeImageOptions.java | 1 - .../gradle/dsl/agent/AgentOptions.java | 24 +-- .../gradle/dsl/agent/CopyMetadataOptions.java | 61 ++++++++ .../internal/AgentCommandLineProvider.java | 9 ++ .../internal/DefaultGraalVmExtension.java | 11 +- .../agent/AgentConfigurationFactory.java | 22 ++- .../gradle/tasks/CopyMetadataTask.java | 117 +++++++++++++++ .../actions/CleanupAgentFilesAction.java | 64 ++++++++ .../actions/MergeAgentFilesAction.java} | 100 +++++++------ ...essGeneratedGraalResourceFilesAction.java} | 70 +++------ .../build.gradle | 14 +- .../filter.json | 6 + 15 files changed, 502 insertions(+), 161 deletions(-) create mode 100644 native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/CopyMetadataOptions.java create mode 100644 native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/CopyMetadataTask.java create mode 100644 native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/CleanupAgentFilesAction.java rename native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/{MergeAgentFiles.java => tasks/actions/MergeAgentFilesAction.java} (60%) rename native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/{internal/ProcessGeneratedGraalResourceFiles.java => tasks/actions/ProcessGeneratedGraalResourceFilesAction.java} (73%) create mode 100644 samples/java-application-with-reflection/filter.json 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 86c0c98aa..1058655ed 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 @@ -42,15 +42,16 @@ import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.List; public class AgentConfiguration implements Serializable { - private final List callerFilterFiles; - private final List accessFilterFiles; + private final Collection callerFilterFiles; + private final Collection accessFilterFiles; private final AgentMode agentMode; - public AgentConfiguration(List callerFilterFiles, List accessFilterFiles, AgentMode agentMode) { + public AgentConfiguration(Collection callerFilterFiles, Collection accessFilterFiles, AgentMode agentMode) { this.callerFilterFiles = callerFilterFiles; this.accessFilterFiles = accessFilterFiles; this.agentMode = agentMode; @@ -63,15 +64,22 @@ public List getAgentCommandLine() { return cmdLine; } + public Collection getAgentFiles() { + List files = new ArrayList<>(callerFilterFiles.size() + accessFilterFiles.size()); + files.addAll(callerFilterFiles); + files.addAll(accessFilterFiles); + return files; + } + public boolean isEnabled() { return !(agentMode instanceof DisabledAgentMode); } - public static void appendOptionToValues(String option, List values, List target) { + public static void appendOptionToValues(String option, Collection values, Collection target) { values.stream().map(value -> option + value).forEach(target::add); } - public List getNativeImageConfigureOptions(List inputDirectories, List outputDirectories) { - return agentMode.getNativeImageConfigureOptions(inputDirectories, outputDirectories); + public AgentMode getAgentMode() { + return agentMode; } } 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 1eca718a6..2f8806348 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 @@ -43,6 +43,8 @@ import org.graalvm.buildtools.VersionInfo; import org.graalvm.buildtools.agent.AgentConfiguration; +import org.graalvm.buildtools.agent.AgentMode; +import org.graalvm.buildtools.agent.StandardAgentMode; import org.graalvm.buildtools.gradle.dsl.GraalVMExtension; import org.graalvm.buildtools.gradle.dsl.JvmReachabilityMetadataRepositoryExtension; import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; @@ -56,11 +58,14 @@ import org.graalvm.buildtools.gradle.internal.GradleUtils; import org.graalvm.buildtools.gradle.internal.JvmReachabilityMetadataService; import org.graalvm.buildtools.gradle.internal.NativeConfigurations; -import org.graalvm.buildtools.gradle.internal.ProcessGeneratedGraalResourceFiles; +import org.graalvm.buildtools.gradle.tasks.actions.CleanupAgentFilesAction; +import org.graalvm.buildtools.gradle.tasks.actions.ProcessGeneratedGraalResourceFilesAction; import org.graalvm.buildtools.gradle.internal.agent.AgentConfigurationFactory; import org.graalvm.buildtools.gradle.tasks.BuildNativeImageTask; +import org.graalvm.buildtools.gradle.tasks.CopyMetadataTask; import org.graalvm.buildtools.gradle.tasks.GenerateResourcesConfigFile; import org.graalvm.buildtools.gradle.tasks.NativeRunTask; +import org.graalvm.buildtools.gradle.tasks.actions.MergeAgentFilesAction; import org.graalvm.buildtools.utils.SharedConstants; import org.gradle.api.Action; import org.gradle.api.NamedDomainObjectContainer; @@ -92,7 +97,6 @@ import org.gradle.api.tasks.OutputDirectory; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.SourceSetContainer; -import org.gradle.api.tasks.TaskCollection; import org.gradle.api.tasks.TaskContainer; import org.gradle.api.tasks.TaskProvider; import org.gradle.api.tasks.bundling.AbstractArchiveTask; @@ -112,16 +116,16 @@ import java.nio.file.Path; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.concurrent.Callable; import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; import static org.graalvm.buildtools.gradle.internal.GradleUtils.transitiveProjectArtifacts; import static org.graalvm.buildtools.gradle.internal.NativeImageExecutableLocator.graalvmHomeProvider; -import static org.graalvm.buildtools.utils.SharedConstants.AGENT_OUTPUT_FOLDER; import static org.graalvm.buildtools.utils.SharedConstants.AGENT_PROPERTY; /** @@ -193,8 +197,18 @@ public void apply(Project project) { private void instrumentTasksWithAgent(Project project, DefaultGraalVmExtension graalExtension) { Provider agentMode = agentProperty(project, graalExtension.getAgent()); Provider agentConfiguration = AgentConfigurationFactory.getAgentConfiguration(agentMode, graalExtension.getAgent()); - TaskCollection tasksToInstrument = graalExtension.getAgent().getInstrumentedTasks().get(); - tasksToInstrument.configureEach(t -> configureAgent(project, agentConfiguration, graalExtension.getToolchainDetection(), getExecOperations(), getFileOperations(), t, t)); + Predicate taskPredicate = graalExtension.getAgent().getTasksToInstrumentPredicate().get(); + project.getTasks().configureEach(t -> { + if (isTaskInstrumentableByAgent(t) && taskPredicate.test(t)) { + configureAgent(project, agentConfiguration, graalExtension.getToolchainDetection(), getExecOperations(), getFileOperations(), t, (JavaForkOptions) t); + } else { + logger.lifecycle("Skipping task: " + t.getName()); + } + }); + } + + private static boolean isTaskInstrumentableByAgent(Task task) { + return task instanceof JavaForkOptions; } private static String deriveTaskName(String name, String prefix, String suffix) { @@ -236,6 +250,34 @@ private void configureJavaProject(Project project, Provider config.forTestTask(tasks.named("test", Test.class)); config.usingSourceSet(GradleUtils.findSourceSet(project, SourceSet.TEST_SOURCE_SET_NAME)); }); + + TaskProvider copyMetadataTask = project.getTasks().register("copyMetadata", CopyMetadataTask.class, task -> { + task.setGroup(LifecycleBasePlugin.BUILD_GROUP); + task.setDescription("Copies metadata collected from tasks instrumented with the agent into target directories."); + task.getInputTaskNames().set(graalExtension.getCopyMetadata().getInputTaskNames()); + task.getOutputDirectories().set(graalExtension.getCopyMetadata().getOutputDirectories()); + task.getMergeWithExisting().set(graalExtension.getCopyMetadata().getMergeWithExisting()); + Provider isMergeEnabled = project.provider(() -> true); + Provider agentModeProvider = project.provider(StandardAgentMode::new); + + Provider> inputDirectories = task.getInputTaskNames().map(list -> + list.stream() + .map(taskName -> AgentConfigurationFactory.getAgentOutputDirectoryForTask(project, taskName)) + .map(dir -> dir.get().getAsFile().getAbsolutePath()) + .collect(Collectors.toList())); + + task.doLast(new MergeAgentFilesAction( + isMergeEnabled, + agentModeProvider, + task.getMergeWithExisting(), + project, + graalvmHomeProvider(project.getProviders()), + inputDirectories, + task.getOutputDirectories(), + graalExtension.getToolchainDetection(), + getExecOperations(), + task.getLogger())); + }); } private void configureAutomaticTaskCreation(Project project, @@ -299,18 +341,18 @@ private void configureJvmReachabilityConfigurationDirectories(Project project, G Set excludedModules = repositoryExtension.getExcludedModules().getOrElse(Collections.emptySet()); Map forcedVersions = repositoryExtension.getModuleToConfigVersion().getOrElse(Collections.emptyMap()); return serviceProvider.map(repo -> repo.findConfigurationDirectoriesFor(query -> classpath.getIncoming().getResolutionResult().allComponents(component -> { - ModuleVersionIdentifier moduleVersion = component.getModuleVersion(); - String module = moduleVersion.getGroup() + ":" + moduleVersion.getName(); - if (!excludedModules.contains(module)) { - query.forArtifact(artifact -> { - artifact.gav(module + ":" + moduleVersion.getVersion()); - if (forcedVersions.containsKey(module)) { - artifact.forceConfigVersion(forcedVersions.get(module)); + ModuleVersionIdentifier moduleVersion = component.getModuleVersion(); + String module = moduleVersion.getGroup() + ":" + moduleVersion.getName(); + if (!excludedModules.contains(module)) { + query.forArtifact(artifact -> { + artifact.gav(module + ":" + moduleVersion.getVersion()); + if (forcedVersions.containsKey(module)) { + artifact.forceConfigVersion(forcedVersions.get(module)); + } + }); } - }); - } - query.useLatestConfigWhenVersionIsUntested(); - })).stream() + query.useLatestConfigWhenVersionIsUntested(); + })).stream() .map(Path::toAbsolutePath) .map(Path::toFile) .collect(Collectors.toList())); @@ -463,6 +505,9 @@ public void registerTestBinary(Project project, task.setOnlyIf(t -> graalExtension.getTestSupport().get()); task.getTestListDirectory().set(testListDirectory); testTask.get(); + if (!agentProperty(project, graalExtension.getAgent()).get().equals("disabled")) { + testOptions.getConfigurationFileDirectories().from(getProcessedAgentOutputFilesDirectory(project, testTask.get())); + } ConfigurableFileCollection testList = project.getObjects().fileCollection(); // Later this will be replaced by a dedicated task not requiring execution of tests testList.from(testListDirectory).builtBy(testTask); @@ -498,13 +543,6 @@ private static Provider agentProperty(Project project, AgentOptions opti .orElse(project.provider(() -> "disabled")); } - private static TaskProvider registerProcessAgentFilesTask(Project project, String name) { - return project.getTasks().register(name, ProcessGeneratedGraalResourceFiles.class, task -> { - task.getFilterableEntries().convention(Arrays.asList("org.gradle.", "java.")); - task.getOutputDirectory().convention(project.getLayout().getBuildDirectory().dir("native/processed/agent/" + name)); - }); - } - @SuppressWarnings("UnstableApiUsage") private static void registerServiceProvider(Project project, Provider nativeImageServiceProvider) { project.getTasks() @@ -590,31 +628,55 @@ private static String postProcessTaskName(String taskName) { return PROCESS_AGENT_RESOURCES_TASK_NAME_PREFIX + capitalize(taskName) + PROCESS_AGENT_RESOURCES_TASK_NAME_SUFFIX; } - private static void configureAgent(Project project, - Provider agentConfiguration, - Provider disableToolchainDetection, - ExecOperations execOperations, - FileSystemOperations fileOperations, - Task taskToInstrument, - JavaForkOptions javaForkOptions) { - TaskProvider postProcessingTask = registerProcessAgentFilesTask(project, postProcessTaskName(taskToInstrument.getName())); + private static List agentSessionDirectories(Directory outputDirectory) { + return Arrays.stream(outputDirectory.getAsFile().listFiles(file -> file.isDirectory() && file.getName().startsWith("session-"))).map(File::getAbsolutePath).collect(Collectors.toList()); + } + + private void configureAgent(Project project, + Provider agentConfiguration, + Provider disableToolchainDetection, + ExecOperations execOperations, + FileSystemOperations fileOperations, + Task taskToInstrument, + JavaForkOptions javaForkOptions) { + logger.lifecycle("Instrumenting task: " + taskToInstrument.getName()); + AgentCommandLineProvider cliProvider = project.getObjects().newInstance(AgentCommandLineProvider.class); + cliProvider.getInputFiles().from(agentConfiguration.map(AgentConfiguration::getAgentFiles)); cliProvider.getEnabled().set(agentConfiguration.map(AgentConfiguration::isEnabled)); - Provider outputDir = project.getLayout().getBuildDirectory().dir(AGENT_OUTPUT_FOLDER + "/" + taskToInstrument.getName()); + + Provider outputDir = AgentConfigurationFactory.getAgentOutputDirectoryForTask(project, taskToInstrument.getName()); + Provider isMergingEnabled = agentConfiguration.map(AgentConfiguration::isEnabled); + Provider agentModeProvider = agentConfiguration.map(AgentConfiguration::getAgentMode); + Provider> mergeOutputDirs = outputDir.map(dir -> Collections.singletonList(dir.getAsFile().getAbsolutePath())); + Provider> mergeInputDirs = outputDir.map(NativeImagePlugin::agentSessionDirectories); cliProvider.getOutputDirectory().set(outputDir); cliProvider.getAgentOptions().set(agentConfiguration.map(AgentConfiguration::getAgentCommandLine)); javaForkOptions.getJvmArgumentProviders().add(cliProvider); - taskToInstrument.doLast(new MergeAgentFiles( - agentConfiguration, + + taskToInstrument.doLast(new MergeAgentFilesAction( + isMergingEnabled, + agentModeProvider, + project.provider(() -> false), project, graalvmHomeProvider(project.getProviders()), - outputDir, + mergeInputDirs, + mergeOutputDirs, disableToolchainDetection, execOperations, - fileOperations, project.getLogger())); - // Gradle won't let us configure from configure so we have to eagerly create the post-processing task :( - postProcessingTask.get().getGeneratedFilesDir().set(outputDir); + taskToInstrument.doLast(new CleanupAgentFilesAction(mergeInputDirs, fileOperations)); + + Provider processedOutputDirectory = getProcessedAgentOutputFilesDirectory(project, taskToInstrument); + taskToInstrument.doLast(new ProcessGeneratedGraalResourceFilesAction( + outputDir, + processedOutputDirectory, + Arrays.asList("org.gradle.", "java.", "org.junit."))); + } + + private static Provider getProcessedAgentOutputFilesDirectory(Project project, Task taskToInstrument) { + String name = postProcessTaskName(taskToInstrument.getName()); + return project.getLayout().getBuildDirectory().dir("native/processed/agent/" + name); } private static void injectTestPluginDependencies(Project project, Property testSupportEnabled) { diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/GraalVMExtension.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/GraalVMExtension.java index 17926133a..e81ccf7c6 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/GraalVMExtension.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/GraalVMExtension.java @@ -42,6 +42,7 @@ package org.graalvm.buildtools.gradle.dsl; import org.graalvm.buildtools.gradle.dsl.agent.AgentOptions; +import org.graalvm.buildtools.gradle.dsl.agent.CopyMetadataOptions; import org.gradle.api.Action; import org.gradle.api.NamedDomainObjectContainer; import org.gradle.api.file.DirectoryProperty; @@ -69,6 +70,9 @@ public interface GraalVMExtension { @Nested AgentOptions getAgent(); + @Nested + CopyMetadataOptions getCopyMetadata(); + void agent(Action spec); DirectoryProperty getGeneratedResourcesDirectory(); diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/NativeImageOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/NativeImageOptions.java index dae701303..359279e80 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/NativeImageOptions.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/NativeImageOptions.java @@ -41,7 +41,6 @@ package org.graalvm.buildtools.gradle.dsl; -import org.graalvm.buildtools.gradle.dsl.agent.AgentOptions; import org.gradle.api.Action; import org.gradle.api.Named; import org.gradle.api.file.ConfigurableFileCollection; diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentOptions.java index 431f6e23c..4dccf208e 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentOptions.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentOptions.java @@ -41,16 +41,16 @@ package org.graalvm.buildtools.gradle.dsl.agent; import org.gradle.api.Action; +import org.gradle.api.Task; +import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; -import org.gradle.api.provider.SetProperty; import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.TaskCollection; -import org.gradle.api.tasks.TaskProvider; -import org.gradle.process.JavaForkOptions; + +import java.util.function.Predicate; @SuppressWarnings({"unused"}) public interface AgentOptions { @@ -65,20 +65,20 @@ default void modes(Action spec) { @Optional Property getDefaultMode(); - @Input + @InputFiles @Optional - ListProperty getCallerFilterFiles(); + ConfigurableFileCollection getCallerFilterFiles(); - @Input + @InputFiles @Optional - ListProperty getAccessFilterFiles(); + ConfigurableFileCollection getAccessFilterFiles(); /** - * Configures the task which needs to be instrumented. + * Configures the tasks which needs to be instrumented * - * @return the instrumented task. + * @return . */ @Input - Property> getInstrumentedTasks(); + Property> getTasksToInstrumentPredicate(); } diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/CopyMetadataOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/CopyMetadataOptions.java new file mode 100644 index 000000000..5f6106d0e --- /dev/null +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/CopyMetadataOptions.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022, 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.dsl.agent; + +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.Optional; + +public interface CopyMetadataOptions { + + @Input + @Optional + ListProperty getInputTaskNames(); + + @Input + @Optional + ListProperty getOutputDirectories(); + + @Input + @Optional + Property getMergeWithExisting(); +} diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/AgentCommandLineProvider.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/AgentCommandLineProvider.java index a2c024ba3..9d297fe58 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/AgentCommandLineProvider.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/AgentCommandLineProvider.java @@ -42,12 +42,17 @@ package org.graalvm.buildtools.gradle.internal; import org.graalvm.buildtools.utils.SharedConstants; +import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.InputFiles; import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; import org.gradle.process.CommandLineArgumentProvider; import javax.inject.Inject; @@ -71,6 +76,10 @@ public AgentCommandLineProvider() { @OutputDirectory public abstract DirectoryProperty getOutputDirectory(); + @InputFiles + @PathSensitive(PathSensitivity.RELATIVE) + public abstract ConfigurableFileCollection getInputFiles(); + @Input @Optional public abstract ListProperty getAgentOptions(); 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 2455fb370..dc4f60796 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 @@ -54,7 +54,6 @@ import org.gradle.jvm.toolchain.JavaLauncher; import org.gradle.jvm.toolchain.JavaToolchainService; import org.gradle.jvm.toolchain.JvmVendorSpec; -import org.gradle.process.JavaForkOptions; import javax.inject.Inject; @@ -64,12 +63,6 @@ public abstract class DefaultGraalVmExtension implements GraalVMExtension { private final Project project; private final Property defaultJavaLauncher; - @SuppressWarnings("unchecked") - /* javac forced our hand */ - private static T iPromiseIKnowWhatImDoing(U u) { - return (T) u; - } - @Inject public DefaultGraalVmExtension(NamedDomainObjectContainer nativeImages, NativeImagePlugin plugin, @@ -81,10 +74,10 @@ public DefaultGraalVmExtension(NamedDomainObjectContainer na getToolchainDetection().convention(true); nativeImages.configureEach(options -> options.getJavaLauncher().convention(defaultJavaLauncher)); getTestSupport().convention(true); - /* Can't use withType here because JavaForkOptions is not a subtype of Task */ - getAgent().getInstrumentedTasks().convention(project.provider(() -> iPromiseIKnowWhatImDoing(project.getTasks().matching(t -> t instanceof JavaForkOptions)))); + getAgent().getTasksToInstrumentPredicate().convention(t -> true); getAgent().getDefaultMode().convention("standard"); getAgent().getModes().getConditional().getParallel().convention(true); + getCopyMetadata().getMergeWithExisting().convention(false); configureToolchain(); } diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/agent/AgentConfigurationFactory.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/agent/AgentConfigurationFactory.java index 6930f361c..3ba94dc5e 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/agent/AgentConfigurationFactory.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/agent/AgentConfigurationFactory.java @@ -49,17 +49,24 @@ import org.graalvm.buildtools.gradle.dsl.agent.AgentOptions; import org.graalvm.buildtools.gradle.dsl.agent.ConditionalAgentModeOptions; import org.gradle.api.GradleException; +import org.gradle.api.Project; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.Directory; import org.gradle.api.provider.Provider; +import java.io.File; +import java.util.Collection; import java.util.Collections; -import java.util.List; +import java.util.stream.Collectors; + +import static org.graalvm.buildtools.utils.SharedConstants.AGENT_OUTPUT_FOLDER; public class AgentConfigurationFactory { public static Provider getAgentConfiguration(Provider modeName, AgentOptions options) { return modeName.map(name -> { AgentMode agentMode; - List callerFilterFiles = options.getCallerFilterFiles().getOrElse(Collections.emptyList()); - List accessFilterFiles = options.getAccessFilterFiles().getOrElse(Collections.emptyList()); + ConfigurableFileCollection callerFilterFiles = options.getCallerFilterFiles(); + ConfigurableFileCollection accessFilterFiles = options.getAccessFilterFiles(); switch (name) { case "standard": agentMode = new StandardAgentMode(); @@ -80,8 +87,15 @@ public static Provider getAgentConfiguration(Provider getFilePaths(ConfigurableFileCollection configurableFileCollection) { + return configurableFileCollection.getFiles().stream().map(File::getAbsolutePath).collect(Collectors.toList()); + } + + public static Provider getAgentOutputDirectoryForTask(Project project, String taskName) { + return project.getLayout().getBuildDirectory().dir(AGENT_OUTPUT_FOLDER + "/" + taskName); + } } diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/CopyMetadataTask.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/CopyMetadataTask.java new file mode 100644 index 000000000..ef73bdaf6 --- /dev/null +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/CopyMetadataTask.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2022, 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; + +import org.graalvm.buildtools.gradle.internal.GraalVMLogger; +import org.graalvm.buildtools.gradle.internal.agent.AgentConfigurationFactory; +import org.gradle.api.DefaultTask; +import org.gradle.api.GradleException; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.options.Option; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; + +public abstract class CopyMetadataTask extends DefaultTask { + + private final GraalVMLogger logger; + + public CopyMetadataTask() { + this.logger = GraalVMLogger.of(getLogger()); + } + + @Internal + public abstract ListProperty getInputTaskNames(); + + @Internal + public abstract ListProperty getOutputDirectories(); + + @Internal + public abstract Property getMergeWithExisting(); + + @Option(option = "task", description = "Executed task previously instrumented with the agent whose metadata should be copied.") + public void overrideInputTaskNames(List inputTaskNames) { + getInputTaskNames().set(inputTaskNames); + } + + @Option(option = "dir", description = "") + public void overrideOutputDirectories(List outputDirectories) { + getOutputDirectories().set(outputDirectories); + } + + @TaskAction + public void exec() { + StringBuilder builder = new StringBuilder(); + for (String taskName : getInputTaskNames().get()) { + File dir = AgentConfigurationFactory.getAgentOutputDirectoryForTask(getProject(), taskName).get().getAsFile(); + if (!dir.exists()) { + builder.append("Could not find configuration for task: ").append(taskName).append(". Please run the task with the agent."); + } else if (!dir.isDirectory()) { + builder.append("Expected a directory with configuration for task: ").append(taskName).append(" but found a regular file at ").append(dir.getAbsolutePath()).append(". Was the output directory manually modified?"); + } + } + String errorString = builder.toString(); + if (!errorString.isEmpty()) { + throw new GradleException(errorString); + } + + for (String dirName : getOutputDirectories().get()) { + File dir = getProject().getLayout().dir(getProject().provider(() -> new File(dirName))).get().getAsFile(); + if (dir.exists()) { + if (!dir.isDirectory()) { + builder.append("Specified output path must either not exist or be a directory: ").append(dirName); + } + } else { + try { + logger.log("Creating output directory: " + dirName); + Files.createDirectories(dir.toPath()); + } catch (IOException e) { + throw new GradleException("Could not create output directory: " + dirName, e); + } + } + } + } +} diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/CleanupAgentFilesAction.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/CleanupAgentFilesAction.java new file mode 100644 index 000000000..a9dd139dd --- /dev/null +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/CleanupAgentFilesAction.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022, 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 org.gradle.api.Action; +import org.gradle.api.Task; +import org.gradle.api.file.FileSystemOperations; +import org.gradle.api.provider.Provider; + +import java.util.List; + +public class CleanupAgentFilesAction implements Action { + + private final Provider> directoriesToCleanup; + private final FileSystemOperations fileOperations; + + public CleanupAgentFilesAction(Provider> directoriesToCleanup, FileSystemOperations fileOperations) { + this.directoriesToCleanup = directoriesToCleanup; + this.fileOperations = fileOperations; + } + + @Override + public void execute(Task task) { + fileOperations.delete(spec -> spec.delete(directoriesToCleanup.get())); + } +} diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/MergeAgentFiles.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java similarity index 60% rename from native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/MergeAgentFiles.java rename to native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java index b39b3b0da..60b93c543 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/MergeAgentFiles.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/MergeAgentFilesAction.java @@ -38,19 +38,15 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package org.graalvm.buildtools.gradle; +package org.graalvm.buildtools.gradle.tasks.actions; -import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; +import org.graalvm.buildtools.agent.AgentMode; import org.graalvm.buildtools.gradle.internal.GraalVMLogger; -import org.graalvm.buildtools.agent.AgentConfiguration; import org.graalvm.buildtools.utils.NativeImageUtils; import org.gradle.api.Action; import org.gradle.api.Project; import org.gradle.api.Task; -import org.gradle.api.file.Directory; -import org.gradle.api.file.FileSystemOperations; import org.gradle.api.logging.Logger; -import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.jvm.toolchain.JavaLauncher; @@ -58,45 +54,55 @@ import org.gradle.process.ExecResult; import java.io.File; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; import static org.graalvm.buildtools.gradle.internal.NativeImageExecutableLocator.findNativeImageExecutable; import static org.graalvm.buildtools.utils.NativeImageUtils.nativeImageConfigureFileName; -class MergeAgentFiles implements Action { - private final Provider agent; +public class MergeAgentFilesAction implements Action { + private final Provider isMergingEnabled; + private final Provider agentMode; + private final Provider mergeWithOutputs; private final Provider graalvmHomeProvider; - private final Provider outputDir; + private final Provider> inputDirs; + private final Provider> outputDirs; private final Provider disableToolchainDetection; private final Property noLauncherProperty; private final ExecOperations execOperations; - private final FileSystemOperations fileOperations; private final Logger logger; - MergeAgentFiles(Provider agent, - Project project, - Provider graalvmHomeProvider, - Provider outputDir, - Provider disableToolchainDetection, - ExecOperations execOperations, - FileSystemOperations fileOperations, - Logger logger) { - this.agent = agent; + public MergeAgentFilesAction(Provider isMergingEnabled, + Provider agentMode, + Provider mergeWithOutputs, + Project project, + Provider graalvmHomeProvider, + Provider> inputDirs, + Provider> outputDirs, + Provider disableToolchainDetection, + ExecOperations execOperations, + Logger logger) { + this.isMergingEnabled = isMergingEnabled; + this.agentMode = agentMode; + this.mergeWithOutputs = mergeWithOutputs; this.graalvmHomeProvider = graalvmHomeProvider; - this.outputDir = outputDir; + this.inputDirs = inputDirs; + this.outputDirs = outputDirs; this.disableToolchainDetection = disableToolchainDetection; this.execOperations = execOperations; - this.fileOperations = fileOperations; this.logger = logger; this.noLauncherProperty = project.getObjects().property(JavaLauncher.class); } + private static boolean isConfigDir(String dir) { + return Arrays.stream(new File(dir).listFiles()).anyMatch(file -> file.getName().equals("reflect-config.json")); + } + @Override public void execute(Task task) { - if (agent.get().isEnabled()) { + if (isMergingEnabled.get()) { File nativeImage = findNativeImageExecutable(noLauncherProperty, disableToolchainDetection, graalvmHomeProvider, execOperations, GraalVMLogger.of(logger)); File workingDir = nativeImage.getParentFile(); File launcher = new File(workingDir, nativeImageConfigureFileName()); @@ -109,25 +115,25 @@ public void execute(Task task) { NativeImageUtils.maybeCreateConfigureUtilSymlink(launcher, nativeImage.toPath()); } if (launcher.exists()) { - List nicInputDirectories = sessionDirectoriesFrom(outputDir.get().getAsFile().listFiles()); - List nicInputDirectoryPaths = nicInputDirectories.stream().map(File::getAbsolutePath).collect(Collectors.toList()); - List nicCommandLine = agent.get().getNativeImageConfigureOptions(nicInputDirectoryPaths, Collections.singletonList(outputDir.get().getAsFile().getAbsolutePath())); + if (mergeWithOutputs.get()) { + List inputs = inputDirs.get(); + List leftoverOutputDirs = new ArrayList<>(); + for (String outputDir : outputDirs.get()) { + if (isConfigDir(outputDir)) { + List newInputs = new ArrayList<>(inputs.size() + 1); + newInputs.addAll(inputs); + newInputs.add(outputDir); + mergeAgentFiles(launcher, newInputs, Collections.singletonList(outputDir)); + } else { + leftoverOutputDirs.add(outputDir); + } + } - if (nicCommandLine.size() > 0) { - logger.info("Merging agent files"); - ExecResult exec = execOperations.exec(spec -> { - spec.executable(launcher); - spec.args(nicCommandLine); - spec.setStandardOutput(System.out); - spec.setErrorOutput(System.err); - }); - if (exec.getExitValue() == 0) { - fileOperations.delete(spec -> nicInputDirectories.forEach(spec::delete)); - } else { - exec.rethrowFailure(); + if (leftoverOutputDirs.size() > 0) { + mergeAgentFiles(launcher, inputs, leftoverOutputDirs); } } else { - logger.info("Not merging agent files"); + mergeAgentFiles(launcher, inputDirs.get(), outputDirs.get()); } } else { logger.warn("Cannot merge agent files because native-image-configure is not installed. Please upgrade to a newer version of GraalVM."); @@ -135,9 +141,17 @@ public void execute(Task task) { } } - private List sessionDirectoriesFrom(File[] files) { - return Arrays.stream(files) - .filter(File::isDirectory) - .filter(f -> f.getName().startsWith("session-")).collect(Collectors.toList()); + private void mergeAgentFiles(File launcher, List inputDirs, List outputDirs) { + List nicCommandLine = agentMode.get().getNativeImageConfigureOptions(inputDirs, outputDirs); + + ExecResult exec = execOperations.exec(spec -> { + spec.executable(launcher); + spec.args(nicCommandLine); + spec.setStandardOutput(System.out); + spec.setErrorOutput(System.err); + }); + if (exec.getExitValue() != 0) { + exec.rethrowFailure(); + } } } diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/ProcessGeneratedGraalResourceFiles.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/ProcessGeneratedGraalResourceFilesAction.java similarity index 73% rename from native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/ProcessGeneratedGraalResourceFiles.java rename to native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/ProcessGeneratedGraalResourceFilesAction.java index 81cc86ecb..1283788ea 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/ProcessGeneratedGraalResourceFiles.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/actions/ProcessGeneratedGraalResourceFilesAction.java @@ -39,23 +39,16 @@ * SOFTWARE. */ -package org.graalvm.buildtools.gradle.internal; +package org.graalvm.buildtools.gradle.tasks.actions; import groovy.json.JsonGenerator; import groovy.json.JsonOutput; import groovy.json.JsonSlurper; -import org.gradle.api.DefaultTask; -import org.gradle.api.file.DirectoryProperty; -import org.gradle.api.provider.ListProperty; -import org.gradle.api.tasks.CacheableTask; -import org.gradle.api.tasks.Input; -import org.gradle.api.tasks.InputDirectory; -import org.gradle.api.tasks.OutputDirectory; -import org.gradle.api.tasks.PathSensitive; -import org.gradle.api.tasks.PathSensitivity; -import org.gradle.api.tasks.TaskAction; -import org.gradle.work.FileChange; -import org.gradle.work.InputChanges; +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.Provider; import java.io.File; import java.io.FileOutputStream; @@ -76,43 +69,28 @@ * the GraalVM agent, in particular to filter out entries which are * inherited from the Gradle environment itself. */ -@CacheableTask -public abstract class ProcessGeneratedGraalResourceFiles extends DefaultTask { - /** - * The directory which contains the files generated by the GraalVM agent. - */ - @InputDirectory - @PathSensitive(PathSensitivity.NAME_ONLY) - public abstract DirectoryProperty getGeneratedFilesDir(); - - @OutputDirectory - public abstract DirectoryProperty getOutputDirectory(); +public class ProcessGeneratedGraalResourceFilesAction implements Action { + private final Provider inputDirectory; + private final Provider outputDirectory; + private final List filterableEntries; - @Input - public abstract ListProperty getFilterableEntries(); + public ProcessGeneratedGraalResourceFilesAction(Provider inputDirectory, Provider outputDirectory, List filterableEntries) { + this.inputDirectory = inputDirectory; + this.outputDirectory = outputDirectory; + this.filterableEntries = filterableEntries; + } - @TaskAction - public void filterResources(InputChanges inputChanges) throws IOException { - File outputDir = getOutputDirectory().get().getAsFile(); - if (outputDir.isDirectory() || outputDir.mkdirs()) { - if (inputChanges.isIncremental()) { - Iterable fileChanges = inputChanges.getFileChanges(getGeneratedFilesDir()); - for (FileChange change : fileChanges) { - switch (change.getChangeType()) { - case ADDED: - case MODIFIED: - processFile(change.getFile(), outputDir); - break; - case REMOVED: - new File(outputDir, change.getFile().getName()).delete(); - break; - } - } - } else { - for (File resourceFile : getGeneratedFilesDir().getAsFileTree().getFiles()) { + @Override + public void execute(Task task) { + try { + File outputDir = outputDirectory.get().getAsFile(); + if (outputDir.isDirectory() || outputDir.mkdirs()) { + for (File resourceFile : inputDirectory.get().getAsFileTree()) { processFile(resourceFile, outputDir); } } + } catch (IOException e) { + throw new GradleException("An IO error occured when processing the agent generated files", e); } } @@ -181,7 +159,7 @@ private Map filterMap(Map map) { private boolean shouldFilterString(Object value) { if (value instanceof CharSequence) { String string = value.toString(); - return getFilterableEntries().get().stream().anyMatch(string::startsWith); + return filterableEntries.stream().anyMatch(string::startsWith); } return false; } diff --git a/samples/java-application-with-reflection/build.gradle b/samples/java-application-with-reflection/build.gradle index 416a1534d..34487d530 100644 --- a/samples/java-application-with-reflection/build.gradle +++ b/samples/java-application-with-reflection/build.gradle @@ -68,11 +68,23 @@ test { graalvmNative { agent { - + defaultMode = "standard" + modes { + conditional { + userCodeFilterPath = "filter.json" + } + } + accessFilterFiles.from('test.json') + } + copyMetadata { + mergeWithExisting = true + inputTaskNames.add("test") + outputDirectories.add("src/main/resources/META-INF/native-image") } binaries { test { verbose = true + buildArgs('--allow-incomplete-classpath') } } } diff --git a/samples/java-application-with-reflection/filter.json b/samples/java-application-with-reflection/filter.json new file mode 100644 index 000000000..366aacb63 --- /dev/null +++ b/samples/java-application-with-reflection/filter.json @@ -0,0 +1,6 @@ +{ + "rules": [ + {"excludeClasses": "**"}, + {"includeClasses": "org.graalvm.demo.**"} + ] +} \ No newline at end of file