From 6d8c46c6176226994bde31da31b3d866dfd53aa9 Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Thu, 28 Apr 2022 17:27:23 +0200 Subject: [PATCH 01/10] Cleanup unused imports --- .../src/main/kotlin/org/graalvm/build/tasks/GitAdd.kt | 4 ---- .../src/main/kotlin/org/graalvm/build/tasks/GitClone.kt | 2 -- .../src/main/kotlin/org/graalvm/build/tasks/GitCommit.kt | 4 ---- .../src/main/kotlin/org/graalvm/build/tasks/GitPush.kt | 4 ---- .../src/main/kotlin/org/graalvm/build/tasks/GitReset.kt | 4 ---- 5 files changed, 18 deletions(-) diff --git a/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitAdd.kt b/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitAdd.kt index 192c40449..f6dd0ec84 100644 --- a/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitAdd.kt +++ b/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitAdd.kt @@ -42,12 +42,8 @@ package org.graalvm.build.tasks import org.eclipse.jgit.api.Git -import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction abstract class GitAdd : AbstractGitTask() { diff --git a/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitClone.kt b/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitClone.kt index b4a0ac23d..6d0616da0 100644 --- a/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitClone.kt +++ b/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitClone.kt @@ -42,9 +42,7 @@ package org.graalvm.build.tasks import org.eclipse.jgit.api.Git -import org.eclipse.jgit.api.TransportConfigCallback import org.eclipse.jgit.transport.SshTransport -import org.eclipse.jgit.transport.Transport import org.eclipse.jgit.util.FileUtils import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property diff --git a/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitCommit.kt b/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitCommit.kt index 04016c7cb..776cf7f6b 100644 --- a/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitCommit.kt +++ b/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitCommit.kt @@ -42,12 +42,8 @@ package org.graalvm.build.tasks import org.eclipse.jgit.api.Git -import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction abstract class GitCommit : AbstractGitTask() { diff --git a/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitPush.kt b/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitPush.kt index 3a14c4fe7..d57630eac 100644 --- a/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitPush.kt +++ b/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitPush.kt @@ -43,12 +43,8 @@ package org.graalvm.build.tasks import org.eclipse.jgit.api.Git import org.eclipse.jgit.transport.SshTransport -import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction abstract class GitPush : AbstractGitTask() { diff --git a/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitReset.kt b/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitReset.kt index b8f39f23f..0dd59a3e6 100644 --- a/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitReset.kt +++ b/build-logic/aggregator/src/main/kotlin/org/graalvm/build/tasks/GitReset.kt @@ -43,12 +43,8 @@ package org.graalvm.build.tasks import org.eclipse.jgit.api.Git import org.eclipse.jgit.api.ResetCommand -import org.gradle.api.DefaultTask -import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputDirectory -import org.gradle.api.tasks.OutputDirectory import org.gradle.api.tasks.TaskAction abstract class GitReset : AbstractGitTask() { From 21d497bb8bf84fea86b54c87ecd007315701efa5 Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Tue, 3 May 2022 18:03:53 +0200 Subject: [PATCH 02/10] Support different agent modes in the native-image Gradle plugin --- .../buildtools/agent/AgentConfiguration.java | 77 +++++++++++++++ .../graalvm/buildtools/agent/AgentMode.java | 50 ++++++++++ .../agent/ConditionalAgentMode.java | 94 +++++++++++++++++++ .../buildtools/agent/DirectAgentMode.java | 62 ++++++++++++ .../buildtools/agent/DisabledAgentMode.java | 56 +++++++++++ .../buildtools/agent/StandardAgentMode.java | 66 +++++++++++++ .../buildtools/gradle/MergeAgentFiles.java | 34 +++---- .../buildtools/gradle/NativeImagePlugin.java | 41 ++++---- .../gradle/dsl/NativeImageOptions.java | 5 +- .../gradle/dsl/agent/AgentModeOptions.java | 68 ++++++++++++++ .../AgentOptions.java} | 29 ++++-- .../agent/ConditionalAgentModeOptions.java | 62 ++++++++++++ .../dsl/agent/DirectAgentModeOptions.java | 51 ++++++++++ .../dsl/agent/StandardAgentModeOptions.java | 44 +++++++++ .../internal/BaseNativeImageOptions.java | 2 + .../internal/DefaultGraalVmExtension.java | 5 +- .../DeprecatedNativeImageOptions.java | 4 +- .../NativeImageCommandLineProvider.java | 13 +-- .../agent/AgentConfigurationFactory.java | 87 +++++++++++++++++ .../gradle/tasks/BuildNativeImageTask.java | 5 +- 20 files changed, 798 insertions(+), 57 deletions(-) create mode 100644 common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java create mode 100644 common/utils/src/main/java/org/graalvm/buildtools/agent/AgentMode.java create mode 100644 common/utils/src/main/java/org/graalvm/buildtools/agent/ConditionalAgentMode.java create mode 100644 common/utils/src/main/java/org/graalvm/buildtools/agent/DirectAgentMode.java create mode 100644 common/utils/src/main/java/org/graalvm/buildtools/agent/DisabledAgentMode.java create mode 100644 common/utils/src/main/java/org/graalvm/buildtools/agent/StandardAgentMode.java create mode 100644 native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentModeOptions.java rename native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/{AgentConfiguration.java => agent/AgentOptions.java} (84%) create mode 100644 native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/ConditionalAgentModeOptions.java create mode 100644 native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/DirectAgentModeOptions.java create mode 100644 native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/StandardAgentModeOptions.java create mode 100644 native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/agent/AgentConfigurationFactory.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 new file mode 100644 index 000000000..86c0c98aa --- /dev/null +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022, 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.agent; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +public class AgentConfiguration implements Serializable { + + private final List callerFilterFiles; + private final List accessFilterFiles; + private final AgentMode agentMode; + + public AgentConfiguration(List callerFilterFiles, List accessFilterFiles, AgentMode agentMode) { + this.callerFilterFiles = callerFilterFiles; + this.accessFilterFiles = accessFilterFiles; + this.agentMode = agentMode; + } + + public List getAgentCommandLine() { + List cmdLine = new ArrayList<>(agentMode.getAgentCommandLine()); + appendOptionToValues("caller-filter-file=", callerFilterFiles, cmdLine); + appendOptionToValues("access-filter-file=", accessFilterFiles, cmdLine); + return cmdLine; + } + + public boolean isEnabled() { + return !(agentMode instanceof DisabledAgentMode); + } + + public static void appendOptionToValues(String option, List values, List target) { + values.stream().map(value -> option + value).forEach(target::add); + } + + public List getNativeImageConfigureOptions(List inputDirectories, List outputDirectories) { + return agentMode.getNativeImageConfigureOptions(inputDirectories, outputDirectories); + } +} diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentMode.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentMode.java new file mode 100644 index 000000000..6ae61374a --- /dev/null +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentMode.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022, 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.agent; + +import java.io.Serializable; +import java.util.List; + +public interface AgentMode extends Serializable { + List getAgentCommandLine(); + + List getNativeImageConfigureOptions(List inputDirectories, List outputDirectories); +} diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/ConditionalAgentMode.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/ConditionalAgentMode.java new file mode 100644 index 000000000..17c103966 --- /dev/null +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/ConditionalAgentMode.java @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2022, 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.agent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class ConditionalAgentMode implements AgentMode { + + private final String userCodeFilterPath; + private final String extraFilterPath; + private final boolean parallel; + + public ConditionalAgentMode(String userCodeFilterPath, String extraFilterPath, boolean parallel) { + this.userCodeFilterPath = userCodeFilterPath; + this.extraFilterPath = extraFilterPath; + this.parallel = parallel; + } + + @Override + public List getAgentCommandLine() { + List cmdLine = new ArrayList<>(); + if (parallel) { + cmdLine.add("experimental-conditional-config-part"); + } else { + cmdLine.add("experimental-conditional-config-filter-file=" + userCodeFilterPath); + if (!extraFilterPath.isEmpty()) { + cmdLine.add("conditional-config-class-filter-file=" + extraFilterPath); + } + } + return cmdLine; + } + + @Override + public List getNativeImageConfigureOptions(List inputDirectories, List outputDirectories) { + int inputDirCount = inputDirectories.size(); + int outputDirCount = outputDirectories.size(); + if (inputDirCount > 0 && outputDirCount > 0) { + List cmdLine = new ArrayList<>(inputDirCount + outputDirCount + 3); + if (parallel) { + cmdLine.add("generate-conditional"); + cmdLine.add("--user-code-filter=" + userCodeFilterPath); + if (!extraFilterPath.isEmpty()) { + cmdLine.add("--class-name-filter=" + extraFilterPath); + } + } else { + cmdLine.add("generate"); + } + AgentConfiguration.appendOptionToValues("--input-dir=", inputDirectories, cmdLine); + AgentConfiguration.appendOptionToValues("--output-dir=", outputDirectories, cmdLine); + return cmdLine; + } + return Collections.emptyList(); + } +} diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/DirectAgentMode.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/DirectAgentMode.java new file mode 100644 index 000000000..b9948e14d --- /dev/null +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/DirectAgentMode.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022, 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.agent; + +import java.util.Collections; +import java.util.List; + +public class DirectAgentMode implements AgentMode{ + private final List agentCmdLine; + + public DirectAgentMode(List agentCmdLine) { + this.agentCmdLine = agentCmdLine; + } + + @Override + public List getAgentCommandLine() { + return agentCmdLine; + } + + @Override + public List getNativeImageConfigureOptions(List inputDirectories, List outputDirectories) { + return Collections.emptyList(); + } +} diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/DisabledAgentMode.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/DisabledAgentMode.java new file mode 100644 index 000000000..418de8db7 --- /dev/null +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/DisabledAgentMode.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022, 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.agent; + +import java.util.Collections; +import java.util.List; + +public class DisabledAgentMode implements AgentMode { + @Override + public List getAgentCommandLine() { + return Collections.emptyList(); + } + + @Override + public List getNativeImageConfigureOptions(List inputDirectories, List outputDirectories) { + return Collections.emptyList(); + } +} diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/StandardAgentMode.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/StandardAgentMode.java new file mode 100644 index 000000000..782b496cb --- /dev/null +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/StandardAgentMode.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022, 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.agent; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class StandardAgentMode implements AgentMode { + @Override + public List getAgentCommandLine() { + return Collections.emptyList(); + } + + @Override + public List getNativeImageConfigureOptions(List inputDirectories, List outputDirectories) { + int inputDirCount = inputDirectories.size(); + int outputDirCount = outputDirectories.size(); + if (inputDirCount > 0 && outputDirCount > 0) { + List cmdLine = new ArrayList<>(inputDirCount + outputDirectories.size() + 1); + cmdLine.add("generate"); + AgentConfiguration.appendOptionToValues("--input-dir=", inputDirectories, cmdLine); + AgentConfiguration.appendOptionToValues("--output-dir=", outputDirectories, cmdLine); + return cmdLine; + } + return Collections.emptyList(); + } +} 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/MergeAgentFiles.java index 45f771eb2..cdab895ec 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/MergeAgentFiles.java @@ -42,6 +42,7 @@ import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; 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.Task; @@ -53,16 +54,16 @@ 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.Stream; +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; + private final Provider agent; private final Provider graalvmHomeProvider; private final Provider outputDir; private final Provider disableToolchainDetection; @@ -71,7 +72,7 @@ class MergeAgentFiles implements Action { private final FileSystemOperations fileOperations; private final Logger logger; - MergeAgentFiles(Provider agent, + MergeAgentFiles(Provider agent, Provider graalvmHomeProvider, Provider outputDir, Provider disableToolchainDetection, @@ -91,7 +92,7 @@ class MergeAgentFiles implements Action { @Override public void execute(Task task) { - if (agent.get()) { + if (agent.get().isEnabled()) { File nativeImage = findNativeImageExecutable(options, disableToolchainDetection, graalvmHomeProvider, execOperations, GraalVMLogger.of(logger)); File workingDir = nativeImage.getParentFile(); File launcher = new File(workingDir, nativeImageConfigureFileName()); @@ -104,26 +105,25 @@ public void execute(Task task) { NativeImageUtils.maybeCreateConfigureUtilSymlink(launcher, nativeImage.toPath()); } if (launcher.exists()) { - File[] files = outputDir.get().getAsFile().listFiles(); - List args = new ArrayList<>(files.length + 2); - args.add("generate"); - sessionDirectoriesFrom(files) - .map(f -> "--input-dir=" + f.getAbsolutePath()) - .forEach(args::add); - if (args.size() > 1) { + 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 (nicCommandLine.size() > 0) { logger.info("Merging agent files"); - args.add("--output-dir=" + outputDir.get().getAsFile().getAbsolutePath()); ExecResult exec = execOperations.exec(spec -> { spec.executable(launcher); - spec.args(args); + spec.args(nicCommandLine); spec.setStandardOutput(System.out); spec.setErrorOutput(System.err); }); if (exec.getExitValue() == 0) { - fileOperations.delete(spec -> sessionDirectoriesFrom(files).forEach(spec::delete)); + fileOperations.delete(spec -> nicInputDirectories.forEach(spec::delete)); } else { exec.rethrowFailure(); } + } else { + logger.info("Not merging agent files"); } } else { logger.warn("Cannot merge agent files because native-image-configure is not installed. Please upgrade to a newer version of GraalVM."); @@ -131,9 +131,9 @@ public void execute(Task task) { } } - private Stream sessionDirectoriesFrom(File[] files) { + private List sessionDirectoriesFrom(File[] files) { return Arrays.stream(files) .filter(File::isDirectory) - .filter(f -> f.getName().startsWith("session-")); + .filter(f -> f.getName().startsWith("session-")).collect(Collectors.toList()); } } 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 e35e67179..7a44cee5c 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 @@ -42,10 +42,10 @@ package org.graalvm.buildtools.gradle; import org.graalvm.buildtools.VersionInfo; -import org.graalvm.buildtools.gradle.dsl.AgentConfiguration; import org.graalvm.buildtools.gradle.dsl.GraalVMExtension; import org.graalvm.buildtools.gradle.dsl.JvmReachabilityMetadataRepositoryExtension; import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; +import org.graalvm.buildtools.gradle.dsl.agent.AgentOptions; import org.graalvm.buildtools.gradle.internal.AgentCommandLineProvider; import org.graalvm.buildtools.gradle.internal.BaseNativeImageOptions; import org.graalvm.buildtools.gradle.internal.DefaultGraalVmExtension; @@ -56,6 +56,8 @@ 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.agent.AgentConfiguration; +import org.graalvm.buildtools.gradle.internal.agent.AgentConfigurationFactory; import org.graalvm.buildtools.gradle.tasks.BuildNativeImageTask; import org.graalvm.buildtools.gradle.tasks.GenerateResourcesConfigFile; import org.graalvm.buildtools.gradle.tasks.NativeRunTask; @@ -184,10 +186,10 @@ public void apply(Project project) { project.getPlugins() .withType(JavaPlugin.class, javaPlugin -> configureJavaProject(project, nativeImageServiceProvider, graalExtension)); project.afterEvaluate(p -> { - Map> agents = graalExtension.getAgentProperties(); + Map> agents = graalExtension.getAgentProperties(); graalExtension.getBinaries().all(options -> { - AgentConfiguration agentConfiguration = options.getAgent(); - if (agentConfiguration.getInstrumentedTask().isPresent()) { + AgentOptions agentOptions = options.getAgent(); + if (agentOptions.getInstrumentedTask().isPresent()) { configureAgent(p, agents, graalExtension.getToolchainDetection().map(b -> !b), options, getExecOperations(), getFileOperations()); } }); @@ -206,7 +208,7 @@ private void configureJavaProject(Project project, Provider logger.log("Initializing project: " + project.getName()); logger.log("===================="); - Map> agents = graalExtension.getAgentProperties(); + Map> agents = graalExtension.getAgentProperties(); // Add DSL extensions for building and testing NativeImageOptions mainOptions = createMainOptions(graalExtension, project); @@ -246,7 +248,7 @@ private void configureJavaProject(Project project, Provider private void configureAutomaticTaskCreation(Project project, GraalVMExtension graalExtension, - Map> agents, + Map> agents, TaskContainer tasks, SourceSetContainer sourceSets) { graalExtension.getBinaries().configureEach(options -> { @@ -255,14 +257,15 @@ private void configureAutomaticTaskCreation(Project project, if ("main".equals(binaryName)) { compileTaskName = NATIVE_COMPILE_TASK_NAME; } - Provider agent = agentPropertyOverride(project, options); - agents.put(binaryName, agent); + Provider agentModeProperty = agentPropertyOverride(project, options); + Provider agentConfiguration = AgentConfigurationFactory.getAgentConfiguration(agentModeProperty, options.getAgent()); + agents.put(binaryName, agentConfiguration); TaskProvider imageBuilder = tasks.register(compileTaskName, BuildNativeImageTask.class, builder -> { builder.setDescription("Compiles a native image for the " + options.getName() + " binary"); builder.setGroup(LifecycleBasePlugin.BUILD_GROUP); builder.getOptions().convention(options); - builder.getAgentEnabled().set(agent); + builder.getAgentConfiguration().set(agentConfiguration); builder.getUseArgFile().convention(graalExtension.getUseArgFile()); }); String runTaskName = deriveTaskName(binaryName, "native", "Run"); @@ -496,17 +499,17 @@ public void registerTestBinary(Project project, * Returns a provider which prefers the CLI arguments over the configured * extension value. */ - private static Provider agentPropertyOverride(Project project, NativeImageOptions extension) { + private static Provider agentPropertyOverride(Project project, NativeImageOptions extension) { return project.getProviders() .gradleProperty(AGENT_PROPERTY) .forUseAtConfigurationTime() .map(v -> { if (!v.isEmpty()) { - return Boolean.valueOf(v); + return v; } - return true; + return extension.getAgent().getDefaultMode().get(); }) - .orElse(extension.getAgent().getEnabled()); + .orElse(project.provider(() -> extension.getAgent().getEnabled().get() ? extension.getAgent().getDefaultMode().get() : "disabled")); } private static TaskProvider registerProcessAgentFilesTask(Project project, String name) { @@ -598,7 +601,7 @@ private static NativeImageOptions createTestOptions(GraalVMExtension graalExtens } private static void configureAgent(Project project, - Map> agents, + Map> agents, Provider disableToolchainDetection, NativeImageOptions nativeImageOptions, ExecOperations execOperations, @@ -607,11 +610,11 @@ private static void configureAgent(Project project, TaskProvider postProcessingTask = registerProcessAgentFilesTask(project, postProcessTaskName); TaskProvider instrumentedTask = nativeImageOptions.getAgent().getInstrumentedTask().get(); AgentCommandLineProvider cliProvider = project.getObjects().newInstance(AgentCommandLineProvider.class); - Provider agent = agents.get(nativeImageOptions.getName()); - cliProvider.getEnabled().set(agent); + Provider agent = agents.get(nativeImageOptions.getName()); + cliProvider.getEnabled().set(agent.get().isEnabled()); Provider outputDir = project.getLayout().getBuildDirectory().dir(AGENT_OUTPUT_FOLDER + "/" + instrumentedTask.getName()); cliProvider.getOutputDirectory().set(outputDir); - cliProvider.getAgentOptions().set(nativeImageOptions.getAgent().getOptions()); + cliProvider.getAgentOptions().set(agent.get().getAgentCommandLine()); instrumentedTask.get().getJvmArgumentProviders().add(cliProvider); instrumentedTask.configure(task -> task.doLast(new MergeAgentFiles( agent, @@ -634,8 +637,8 @@ private static void configureAgent(Project project, // ) // but Gradle won't track the postProcessingTask dependency so we have to write this: ConfigurableFileCollection files = project.getObjects().fileCollection(); - files.from(agent.map(enabled -> enabled ? postProcessingTask : project.files())); - files.builtBy((Callable) () -> agent.get() ? postProcessingTask.get() : null); + files.from(agent.map(mode -> mode.isEnabled() ? postProcessingTask : project.files())); + files.builtBy((Callable) () -> agent.get().isEnabled() ? postProcessingTask.get() : null); nativeImageOptions.getConfigurationFileDirectories().from(files); } 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 d19585cf5..a12d7a5f6 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,6 +41,7 @@ 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; @@ -158,13 +159,13 @@ public interface NativeImageOptions extends Named { * @return the configuration. */ @Nested - AgentConfiguration getAgent(); + AgentOptions getAgent(); /** * Configures the GraalVM agent options. * @param spec the agent configuration. */ - default void agent(Action spec) { + default void agent(Action spec) { spec.execute(getAgent()); } diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentModeOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentModeOptions.java new file mode 100644 index 000000000..a6d356198 --- /dev/null +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentModeOptions.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022, 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.Action; +import org.gradle.api.tasks.Nested; + +@SuppressWarnings({"unused"}) +public interface AgentModeOptions { + @Nested + StandardAgentModeOptions getStandard(); + + default void standard(Action spec) { + spec.execute(getStandard()); + } + + @Nested + ConditionalAgentModeOptions getConditional(); + + default void conditional(Action spec) { + spec.execute(getConditional()); + } + + @Nested + DirectAgentModeOptions getDirect(); + + default void direct(Action spec) { + spec.execute(getDirect()); + } +} diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/AgentConfiguration.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentOptions.java similarity index 84% rename from native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/AgentConfiguration.java rename to native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentOptions.java index 7e0576cc9..b7f3e505d 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/AgentConfiguration.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentOptions.java @@ -38,17 +38,20 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package org.graalvm.buildtools.gradle.dsl; +package org.graalvm.buildtools.gradle.dsl.agent; +import org.gradle.api.Action; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Internal; +import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.Optional; import org.gradle.api.tasks.TaskProvider; import org.gradle.process.JavaForkOptions; -public interface AgentConfiguration { +@SuppressWarnings({"unused"}) +public interface AgentOptions { /** * Gets the value which toggles the native-image-agent usage. * @@ -57,16 +60,28 @@ public interface AgentConfiguration { @Input Property getEnabled(); - /** - * Gets the native agent options. Only used when {@link #getEnabled()} is true. - * @return the native agent options. - */ + @Nested + AgentModeOptions getModes(); + + default void modes(Action spec) { + spec.execute(getModes()); + } + @Input @Optional - ListProperty getOptions(); + Property getDefaultMode(); + + @Input + @Optional + ListProperty getCallerFilterFiles(); + + @Input + @Optional + ListProperty getAccessFilterFiles(); /** * Configures the task which needs to be instrumented. + * * @return the instrumented task. */ @Internal diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/ConditionalAgentModeOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/ConditionalAgentModeOptions.java new file mode 100644 index 000000000..711c3405c --- /dev/null +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/ConditionalAgentModeOptions.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022, 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.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.Optional; + +public interface ConditionalAgentModeOptions { + + @InputFile + @Optional + Property getUserCodeFilterPath(); + + @Input + @Optional + Property getExtraFilterPath(); + + @Input + @Optional + Property getParallel(); + +} diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/DirectAgentModeOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/DirectAgentModeOptions.java new file mode 100644 index 000000000..7fab6e902 --- /dev/null +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/DirectAgentModeOptions.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022, 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.tasks.Input; + +public interface DirectAgentModeOptions { + + @Input + ListProperty getOptions(); + +} diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/StandardAgentModeOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/StandardAgentModeOptions.java new file mode 100644 index 000000000..973e9a1e9 --- /dev/null +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/StandardAgentModeOptions.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022, 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; + +public interface StandardAgentModeOptions { +} diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/BaseNativeImageOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/BaseNativeImageOptions.java index cc4a82d6c..f01dacc6a 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/BaseNativeImageOptions.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/BaseNativeImageOptions.java @@ -211,7 +211,9 @@ public BaseNativeImageOptions(String name, getDebug().convention(false); getFallback().convention(false); getVerbose().convention(false); + getAgent().getDefaultMode().convention("standard"); getAgent().getEnabled().convention(false); + getAgent().getModes().getConditional().getParallel().convention(true); getSharedLibrary().convention(false); getImageName().convention(defaultImageName); getUseFatJar().convention(false); 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 cc69c4b74..ed0c1a259 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 @@ -44,6 +44,7 @@ import org.graalvm.buildtools.gradle.NativeImagePlugin; import org.graalvm.buildtools.gradle.dsl.GraalVMExtension; import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; +import org.graalvm.buildtools.agent.AgentConfiguration; import org.gradle.api.Action; import org.gradle.api.JavaVersion; import org.gradle.api.NamedDomainObjectContainer; @@ -63,7 +64,7 @@ public abstract class DefaultGraalVmExtension implements GraalVMExtension { private final NamedDomainObjectContainer nativeImages; private final NativeImagePlugin plugin; private final Project project; - private final Map> agentProperties = new HashMap<>(); + private final Map> agentProperties = new HashMap<>(); private final Property defaultJavaLauncher; @Inject @@ -109,7 +110,7 @@ public void binaries(Action> getAgentProperties() { + public Map> getAgentProperties() { return agentProperties; } diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DeprecatedNativeImageOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DeprecatedNativeImageOptions.java index 754055125..06c87bb47 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DeprecatedNativeImageOptions.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DeprecatedNativeImageOptions.java @@ -40,7 +40,7 @@ */ package org.graalvm.buildtools.gradle.internal; -import org.graalvm.buildtools.gradle.dsl.AgentConfiguration; +import org.graalvm.buildtools.gradle.dsl.agent.AgentOptions; import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; import org.graalvm.buildtools.gradle.dsl.NativeResourcesOptions; import org.gradle.api.Action; @@ -168,7 +168,7 @@ public Property getVerbose() { @Override @Nested - public AgentConfiguration getAgent() { + public AgentOptions getAgent() { return warnAboutDeprecation(delegate::getAgent); } diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java index 9d0b80394..44ed6957c 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java @@ -42,6 +42,7 @@ package org.graalvm.buildtools.gradle.internal; import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; +import org.graalvm.buildtools.agent.AgentConfiguration; import org.graalvm.buildtools.utils.NativeImageUtils; import org.gradle.api.Transformer; import org.gradle.api.file.FileSystemLocation; @@ -62,20 +63,20 @@ public class NativeImageCommandLineProvider implements CommandLineArgumentProvid private static final Transformer NEGATE = b -> !b; private final Provider options; - private final Provider agentEnabled; + private final Provider agentConfiguration; private final Provider executableName; private final Provider outputDirectory; private final Provider classpathJar; private final Provider useArgFile; public NativeImageCommandLineProvider(Provider options, - Provider agentEnabled, + Provider agentConfiguration, Provider executableName, Provider outputDirectory, Provider classpathJar, Provider useArgFile) { this.options = options; - this.agentEnabled = agentEnabled; + this.agentConfiguration = agentConfiguration; this.executableName = executableName; this.outputDirectory = outputDirectory; this.classpathJar = classpathJar; @@ -88,8 +89,8 @@ public Provider getOptions() { } @Input - public Provider getAgentEnabled() { - return agentEnabled; + public Provider getAgentConfiguration() { + return agentConfiguration; } @Input @@ -142,7 +143,7 @@ public List asArguments() { if (!configFiles.isEmpty()) { cliArgs.add("-H:ConfigurationFileDirectories=" + configFiles); } - if (getAgentEnabled().get()) { + if (getAgentConfiguration().get().isEnabled()) { cliArgs.add("--allow-incomplete-classpath"); } if (options.getMainClass().isPresent()) { 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 new file mode 100644 index 000000000..6930f361c --- /dev/null +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/agent/AgentConfigurationFactory.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022, 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.internal.agent; + +import org.graalvm.buildtools.agent.AgentConfiguration; +import org.graalvm.buildtools.agent.AgentMode; +import org.graalvm.buildtools.agent.ConditionalAgentMode; +import org.graalvm.buildtools.agent.DirectAgentMode; +import org.graalvm.buildtools.agent.DisabledAgentMode; +import org.graalvm.buildtools.agent.StandardAgentMode; +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.provider.Provider; + +import java.util.Collections; +import java.util.List; + +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()); + switch (name) { + case "standard": + agentMode = new StandardAgentMode(); + break; + case "disabled": + agentMode = new DisabledAgentMode(); + break; + case "conditional": + ConditionalAgentModeOptions opts = options.getModes().getConditional(); + if (!opts.getUserCodeFilterPath().isPresent()) { + throw new GradleException("Missing property userCodeFilterPath in agent conditional configuration"); + } + agentMode = new ConditionalAgentMode(opts.getUserCodeFilterPath().get(), opts.getExtraFilterPath().getOrElse(""), opts.getParallel().get()); + break; + case "direct": + agentMode = new DirectAgentMode(options.getModes().getDirect().getOptions().getOrElse(Collections.emptyList())); + break; + default: + throw new GradleException("Unknown agent mode selected: " + name); + } + return new AgentConfiguration(callerFilterFiles, accessFilterFiles, agentMode); + }); + } + +} diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java index 4a75130e6..2c7e724d0 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java @@ -46,6 +46,7 @@ import org.graalvm.buildtools.gradle.internal.GraalVMLogger; import org.graalvm.buildtools.gradle.internal.NativeImageCommandLineProvider; import org.graalvm.buildtools.gradle.internal.NativeImageExecutableLocator; +import org.graalvm.buildtools.agent.AgentConfiguration; import org.gradle.api.DefaultTask; import org.gradle.api.file.Directory; import org.gradle.api.file.DirectoryProperty; @@ -118,7 +119,7 @@ public Provider getOutputFile() { } @Input - public abstract Property getAgentEnabled(); + public abstract Property getAgentConfiguration(); @Input public abstract Property getDisableToolchainDetection(); @@ -153,7 +154,7 @@ private List buildActualCommandLineArgs() { getOptions().finalizeValue(); return new NativeImageCommandLineProvider( getOptions(), - getAgentEnabled(), + getAgentConfiguration(), getExecutableShortName(), // Can't use getOutputDirectory().map(...) because Gradle would complain that we use // a mapped value before the task was called, when we are actually calling it... From e2e54c4c692a18ce016db02fe97828d8e022e614 Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Tue, 10 May 2022 20:41:26 +0200 Subject: [PATCH 03/10] WIP --- .../buildtools/gradle/MergeAgentFiles.java | 12 +- .../buildtools/gradle/NativeImagePlugin.java | 113 +++++++----------- .../gradle/dsl/GraalVMExtension.java | 7 ++ .../gradle/dsl/NativeImageOptions.java | 15 --- .../gradle/dsl/agent/AgentOptions.java | 14 +-- .../internal/BaseNativeImageOptions.java | 3 - .../internal/DefaultGraalVmExtension.java | 26 ++-- .../DeprecatedNativeImageOptions.java | 7 -- .../NativeImageCommandLineProvider.java | 11 -- .../NativeImageExecutableLocator.java | 8 +- .../gradle/tasks/BuildNativeImageTask.java | 6 +- .../gradle/tasks/NativeRunTask.java | 2 +- .../build.gradle | 8 +- .../settings.gradle | 1 + 14 files changed, 92 insertions(+), 141 deletions(-) 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/MergeAgentFiles.java index cdab895ec..b39b3b0da 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/MergeAgentFiles.java @@ -45,11 +45,15 @@ 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; import org.gradle.process.ExecOperations; import org.gradle.process.ExecResult; @@ -67,16 +71,16 @@ class MergeAgentFiles implements Action { private final Provider graalvmHomeProvider; private final Provider outputDir; private final Provider disableToolchainDetection; + private final Property noLauncherProperty; private final ExecOperations execOperations; - private final NativeImageOptions options; private final FileSystemOperations fileOperations; private final Logger logger; MergeAgentFiles(Provider agent, + Project project, Provider graalvmHomeProvider, Provider outputDir, Provider disableToolchainDetection, - NativeImageOptions options, ExecOperations execOperations, FileSystemOperations fileOperations, Logger logger) { @@ -84,16 +88,16 @@ class MergeAgentFiles implements Action { this.graalvmHomeProvider = graalvmHomeProvider; this.outputDir = outputDir; this.disableToolchainDetection = disableToolchainDetection; - this.options = options; this.execOperations = execOperations; this.fileOperations = fileOperations; this.logger = logger; + this.noLauncherProperty = project.getObjects().property(JavaLauncher.class); } @Override public void execute(Task task) { if (agent.get().isEnabled()) { - File nativeImage = findNativeImageExecutable(options, disableToolchainDetection, graalvmHomeProvider, execOperations, GraalVMLogger.of(logger)); + File nativeImage = findNativeImageExecutable(noLauncherProperty, disableToolchainDetection, graalvmHomeProvider, execOperations, GraalVMLogger.of(logger)); File workingDir = nativeImage.getParentFile(); File launcher = new File(workingDir, nativeImageConfigureFileName()); if (!launcher.exists()) { 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 7a44cee5c..1eca718a6 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 @@ -42,6 +42,7 @@ package org.graalvm.buildtools.gradle; import org.graalvm.buildtools.VersionInfo; +import org.graalvm.buildtools.agent.AgentConfiguration; import org.graalvm.buildtools.gradle.dsl.GraalVMExtension; import org.graalvm.buildtools.gradle.dsl.JvmReachabilityMetadataRepositoryExtension; import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; @@ -56,7 +57,6 @@ 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.agent.AgentConfiguration; import org.graalvm.buildtools.gradle.internal.agent.AgentConfigurationFactory; import org.graalvm.buildtools.gradle.tasks.BuildNativeImageTask; import org.graalvm.buildtools.gradle.tasks.GenerateResourcesConfigFile; @@ -82,7 +82,6 @@ import org.gradle.api.file.FileSystemOperations; import org.gradle.api.logging.LogLevel; import org.gradle.api.model.ObjectFactory; -import org.gradle.api.plugins.ApplicationPlugin; import org.gradle.api.plugins.ExtensionAware; import org.gradle.api.plugins.JavaApplication; import org.gradle.api.plugins.JavaPlugin; @@ -90,10 +89,10 @@ import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; -import org.gradle.api.tasks.JavaExec; 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; @@ -185,17 +184,19 @@ public void apply(Project project) { graalExtension.getUseArgFile().convention(true); project.getPlugins() .withType(JavaPlugin.class, javaPlugin -> configureJavaProject(project, nativeImageServiceProvider, graalExtension)); + project.afterEvaluate(p -> { - Map> agents = graalExtension.getAgentProperties(); - graalExtension.getBinaries().all(options -> { - AgentOptions agentOptions = options.getAgent(); - if (agentOptions.getInstrumentedTask().isPresent()) { - configureAgent(p, agents, graalExtension.getToolchainDetection().map(b -> !b), options, getExecOperations(), getFileOperations()); - } - }); + instrumentTasksWithAgent(project, graalExtension); }); } + 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)); + } + private static String deriveTaskName(String name, String prefix, String suffix) { if ("main".equals(name)) { return prefix + suffix; @@ -208,8 +209,6 @@ private void configureJavaProject(Project project, Provider logger.log("Initializing project: " + project.getName()); logger.log("===================="); - Map> agents = graalExtension.getAgentProperties(); - // Add DSL extensions for building and testing NativeImageOptions mainOptions = createMainOptions(graalExtension, project); deprecateExtension(project, mainOptions, DEPRECATED_NATIVE_BUILD_EXTENSION, "main"); @@ -225,7 +224,7 @@ private void configureJavaProject(Project project, Provider // Register Native Image tasks TaskContainer tasks = project.getTasks(); JavaPluginConvention javaConvention = project.getConvention().getPlugin(JavaPluginConvention.class); - configureAutomaticTaskCreation(project, graalExtension, agents, tasks, javaConvention.getSourceSets()); + configureAutomaticTaskCreation(project, graalExtension, tasks, javaConvention.getSourceSets()); TaskProvider imageBuilder = tasks.named(NATIVE_COMPILE_TASK_NAME, BuildNativeImageTask.class); TaskProvider deprecatedTask = tasks.register(DEPRECATED_NATIVE_BUILD_TASK, t -> { @@ -233,13 +232,6 @@ private void configureJavaProject(Project project, Provider t.doFirst("Warn about deprecation", task -> task.getLogger().warn("Task " + DEPRECATED_NATIVE_BUILD_TASK + " is deprecated. Use " + NATIVE_COMPILE_TASK_NAME + " instead.")); }); - // We want to add agent invocation to "run" task, but it is only available when - // Application Plugin is initialized. - project.getPlugins().withType(ApplicationPlugin.class, applicationPlugin -> { - TaskProvider runTask = tasks.withType(JavaExec.class).named(ApplicationPlugin.TASK_RUN_NAME); - mainOptions.getAgent().getInstrumentedTask().convention(runTask); - }); - graalExtension.registerTestBinary("test", config -> { config.forTestTask(tasks.named("test", Test.class)); config.usingSourceSet(GradleUtils.findSourceSet(project, SourceSet.TEST_SOURCE_SET_NAME)); @@ -248,7 +240,6 @@ private void configureJavaProject(Project project, Provider private void configureAutomaticTaskCreation(Project project, GraalVMExtension graalExtension, - Map> agents, TaskContainer tasks, SourceSetContainer sourceSets) { graalExtension.getBinaries().configureEach(options -> { @@ -257,15 +248,11 @@ private void configureAutomaticTaskCreation(Project project, if ("main".equals(binaryName)) { compileTaskName = NATIVE_COMPILE_TASK_NAME; } - Provider agentModeProperty = agentPropertyOverride(project, options); - Provider agentConfiguration = AgentConfigurationFactory.getAgentConfiguration(agentModeProperty, options.getAgent()); - agents.put(binaryName, agentConfiguration); TaskProvider imageBuilder = tasks.register(compileTaskName, BuildNativeImageTask.class, builder -> { builder.setDescription("Compiles a native image for the " + options.getName() + " binary"); builder.setGroup(LifecycleBasePlugin.BUILD_GROUP); builder.getOptions().convention(options); - builder.getAgentConfiguration().set(agentConfiguration); builder.getUseArgFile().convention(graalExtension.getUseArgFile()); }); String runTaskName = deriveTaskName(binaryName, "native", "Run"); @@ -312,18 +299,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())); @@ -457,7 +444,6 @@ public void registerTestBinary(Project project, } TaskProvider testTask = config.validate().getTestTask(); - testOptions.getAgent().getInstrumentedTask().set(testTask); testTask.configure(test -> { File testList = new File(testResultsDir, test.getName() + "/testlist"); testListDirectory.set(testList); @@ -499,7 +485,7 @@ public void registerTestBinary(Project project, * Returns a provider which prefers the CLI arguments over the configured * extension value. */ - private static Provider agentPropertyOverride(Project project, NativeImageOptions extension) { + private static Provider agentProperty(Project project, AgentOptions options) { return project.getProviders() .gradleProperty(AGENT_PROPERTY) .forUseAtConfigurationTime() @@ -507,9 +493,9 @@ private static Provider agentPropertyOverride(Project project, NativeIma if (!v.isEmpty()) { return v; } - return extension.getAgent().getDefaultMode().get(); + return options.getDefaultMode().get(); }) - .orElse(project.provider(() -> extension.getAgent().getEnabled().get() ? extension.getAgent().getDefaultMode().get() : "disabled")); + .orElse(project.provider(() -> "disabled")); } private static TaskProvider registerProcessAgentFilesTask(Project project, String name) { @@ -600,46 +586,35 @@ private static NativeImageOptions createTestOptions(GraalVMExtension graalExtens return testExtension; } + 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, - Map> agents, + Provider agentConfiguration, Provider disableToolchainDetection, - NativeImageOptions nativeImageOptions, ExecOperations execOperations, - FileSystemOperations fileOperations) { - String postProcessTaskName = PROCESS_AGENT_RESOURCES_TASK_NAME_PREFIX + capitalize(nativeImageOptions.getName()) + PROCESS_AGENT_RESOURCES_TASK_NAME_SUFFIX; - TaskProvider postProcessingTask = registerProcessAgentFilesTask(project, postProcessTaskName); - TaskProvider instrumentedTask = nativeImageOptions.getAgent().getInstrumentedTask().get(); + FileSystemOperations fileOperations, + Task taskToInstrument, + JavaForkOptions javaForkOptions) { + TaskProvider postProcessingTask = registerProcessAgentFilesTask(project, postProcessTaskName(taskToInstrument.getName())); AgentCommandLineProvider cliProvider = project.getObjects().newInstance(AgentCommandLineProvider.class); - Provider agent = agents.get(nativeImageOptions.getName()); - cliProvider.getEnabled().set(agent.get().isEnabled()); - Provider outputDir = project.getLayout().getBuildDirectory().dir(AGENT_OUTPUT_FOLDER + "/" + instrumentedTask.getName()); + cliProvider.getEnabled().set(agentConfiguration.map(AgentConfiguration::isEnabled)); + Provider outputDir = project.getLayout().getBuildDirectory().dir(AGENT_OUTPUT_FOLDER + "/" + taskToInstrument.getName()); cliProvider.getOutputDirectory().set(outputDir); - cliProvider.getAgentOptions().set(agent.get().getAgentCommandLine()); - instrumentedTask.get().getJvmArgumentProviders().add(cliProvider); - instrumentedTask.configure(task -> task.doLast(new MergeAgentFiles( - agent, + cliProvider.getAgentOptions().set(agentConfiguration.map(AgentConfiguration::getAgentCommandLine)); + javaForkOptions.getJvmArgumentProviders().add(cliProvider); + taskToInstrument.doLast(new MergeAgentFiles( + agentConfiguration, + project, graalvmHomeProvider(project.getProviders()), outputDir, disableToolchainDetection, - nativeImageOptions, execOperations, fileOperations, - project.getLogger()))); + project.getLogger())); // Gradle won't let us configure from configure so we have to eagerly create the post-processing task :( - postProcessingTask.get().getGeneratedFilesDir().set( - instrumentedTask.map(t -> outputDir.get()) - ); - // We can't set from(postProcessingTask) directly, otherwise a task - // dependency would be introduced even if the agent is not enabled. - // We should be able to write this: - // nativeImageOptions.getConfigurationFileDirectories().from( - // agent.map(enabled -> enabled ? postProcessingTask : project.files()) - // ) - // but Gradle won't track the postProcessingTask dependency so we have to write this: - ConfigurableFileCollection files = project.getObjects().fileCollection(); - files.from(agent.map(mode -> mode.isEnabled() ? postProcessingTask : project.files())); - files.builtBy((Callable) () -> agent.get().isEnabled() ? postProcessingTask.get() : null); - nativeImageOptions.getConfigurationFileDirectories().from(files); + postProcessingTask.get().getGeneratedFilesDir().set(outputDir); } 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 fb574b07b..17926133a 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 @@ -41,10 +41,12 @@ package org.graalvm.buildtools.gradle.dsl; +import org.graalvm.buildtools.gradle.dsl.agent.AgentOptions; import org.gradle.api.Action; import org.gradle.api.NamedDomainObjectContainer; import org.gradle.api.file.DirectoryProperty; import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.SourceSet; import org.gradle.api.tasks.TaskProvider; import org.gradle.api.tasks.testing.Test; @@ -64,6 +66,11 @@ public interface GraalVMExtension { */ Property getTestSupport(); + @Nested + AgentOptions getAgent(); + + 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 a12d7a5f6..dae701303 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 @@ -154,21 +154,6 @@ public interface NativeImageOptions extends Named { @Input Property getVerbose(); - /** - * Returns the GraalVM agent configuration. - * @return the configuration. - */ - @Nested - AgentOptions getAgent(); - - /** - * Configures the GraalVM agent options. - * @param spec the agent configuration. - */ - default void agent(Action spec) { - spec.execute(getAgent()); - } - /** * Gets the value which determines if shared library is being built. * 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 b7f3e505d..431f6e23c 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 @@ -43,23 +43,17 @@ import org.gradle.api.Action; 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.Nested; import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.TaskCollection; import org.gradle.api.tasks.TaskProvider; import org.gradle.process.JavaForkOptions; @SuppressWarnings({"unused"}) public interface AgentOptions { - /** - * Gets the value which toggles the native-image-agent usage. - * - * @return The value which toggles the native-image-agent usage. - */ - @Input - Property getEnabled(); - @Nested AgentModeOptions getModes(); @@ -84,7 +78,7 @@ default void modes(Action spec) { * * @return the instrumented task. */ - @Internal - Property> getInstrumentedTask(); + @Input + Property> getInstrumentedTasks(); } diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/BaseNativeImageOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/BaseNativeImageOptions.java index f01dacc6a..2e6d690be 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/BaseNativeImageOptions.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/BaseNativeImageOptions.java @@ -211,9 +211,6 @@ public BaseNativeImageOptions(String name, getDebug().convention(false); getFallback().convention(false); getVerbose().convention(false); - getAgent().getDefaultMode().convention("standard"); - getAgent().getEnabled().convention(false); - getAgent().getModes().getConditional().getParallel().convention(true); getSharedLibrary().convention(false); getImageName().convention(defaultImageName); getUseFatJar().convention(false); 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 ed0c1a259..2455fb370 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 @@ -44,29 +44,32 @@ import org.graalvm.buildtools.gradle.NativeImagePlugin; import org.graalvm.buildtools.gradle.dsl.GraalVMExtension; import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; -import org.graalvm.buildtools.agent.AgentConfiguration; +import org.graalvm.buildtools.gradle.dsl.agent.AgentOptions; import org.gradle.api.Action; import org.gradle.api.JavaVersion; import org.gradle.api.NamedDomainObjectContainer; import org.gradle.api.Project; import org.gradle.api.provider.Property; -import org.gradle.api.provider.Provider; import org.gradle.jvm.toolchain.JavaLanguageVersion; 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; -import java.util.HashMap; -import java.util.Map; public abstract class DefaultGraalVmExtension implements GraalVMExtension { private final NamedDomainObjectContainer nativeImages; private final NativeImagePlugin plugin; private final Project project; - private final Map> agentProperties = new HashMap<>(); 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, @@ -78,6 +81,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().getDefaultMode().convention("standard"); + getAgent().getModes().getConditional().getParallel().convention(true); configureToolchain(); } @@ -106,12 +113,13 @@ public NamedDomainObjectContainer getBinaries() { } @Override - public void binaries(Action> spec) { - spec.execute(nativeImages); + public void agent(Action spec) { + spec.execute(getAgent()); } - public Map> getAgentProperties() { - return agentProperties; + @Override + public void binaries(Action> spec) { + spec.execute(nativeImages); } @Override diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DeprecatedNativeImageOptions.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DeprecatedNativeImageOptions.java index 06c87bb47..e566526bb 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DeprecatedNativeImageOptions.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DeprecatedNativeImageOptions.java @@ -40,7 +40,6 @@ */ package org.graalvm.buildtools.gradle.internal; -import org.graalvm.buildtools.gradle.dsl.agent.AgentOptions; import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; import org.graalvm.buildtools.gradle.dsl.NativeResourcesOptions; import org.gradle.api.Action; @@ -166,12 +165,6 @@ public Property getVerbose() { return warnAboutDeprecation(delegate::getVerbose); } - @Override - @Nested - public AgentOptions getAgent() { - return warnAboutDeprecation(delegate::getAgent); - } - @Override @Input public Property getSharedLibrary() { diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java index 44ed6957c..208beeb7f 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java @@ -63,20 +63,17 @@ public class NativeImageCommandLineProvider implements CommandLineArgumentProvid private static final Transformer NEGATE = b -> !b; private final Provider options; - private final Provider agentConfiguration; private final Provider executableName; private final Provider outputDirectory; private final Provider classpathJar; private final Provider useArgFile; public NativeImageCommandLineProvider(Provider options, - Provider agentConfiguration, Provider executableName, Provider outputDirectory, Provider classpathJar, Provider useArgFile) { this.options = options; - this.agentConfiguration = agentConfiguration; this.executableName = executableName; this.outputDirectory = outputDirectory; this.classpathJar = classpathJar; @@ -88,11 +85,6 @@ public Provider getOptions() { return options; } - @Input - public Provider getAgentConfiguration() { - return agentConfiguration; - } - @Input public Provider getExecutableName() { return executableName; @@ -143,9 +135,6 @@ public List asArguments() { if (!configFiles.isEmpty()) { cliArgs.add("-H:ConfigurationFileDirectories=" + configFiles); } - if (getAgentConfiguration().get().isEnabled()) { - cliArgs.add("--allow-incomplete-classpath"); - } if (options.getMainClass().isPresent()) { cliArgs.add("-H:Class=" + options.getMainClass().get()); } 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 1cb3a41f9..5f938b8a8 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 @@ -42,9 +42,11 @@ import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; import org.gradle.api.GradleException; +import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.provider.ProviderFactory; import org.gradle.jvm.toolchain.JavaInstallationMetadata; +import org.gradle.jvm.toolchain.JavaLauncher; import org.gradle.process.ExecOperations; import org.gradle.process.ExecResult; @@ -62,13 +64,13 @@ public static Provider graalvmHomeProvider(ProviderFactory providers) { .orElse(providers.environmentVariable("JAVA_HOME").forUseAtConfigurationTime()); } - public static File findNativeImageExecutable(NativeImageOptions options, + public static File findNativeImageExecutable(Property javaLauncher, Provider disableToolchainDetection, Provider graalvmHomeProvider, ExecOperations execOperations, GraalVMLogger logger) { File executablePath = null; - if (disableToolchainDetection.get() || !options.getJavaLauncher().isPresent()) { + if (disableToolchainDetection.get() || !javaLauncher.isPresent()) { if (graalvmHomeProvider.isPresent()) { String graalvmHome = graalvmHomeProvider.get(); logger.lifecycle("Toolchain detection is disabled, will use GraalVM from {}.", graalvmHome); @@ -76,7 +78,7 @@ public static File findNativeImageExecutable(NativeImageOptions options, } } if (executablePath == null) { - JavaInstallationMetadata metadata = options.getJavaLauncher().get().getMetadata(); + JavaInstallationMetadata metadata = javaLauncher.get().getMetadata(); executablePath = metadata.getInstallationPath().file("bin/" + NATIVE_IMAGE_EXE).getAsFile(); if (!executablePath.exists() && graalvmHomeProvider.isPresent()) { executablePath = Paths.get(graalvmHomeProvider.get()).resolve("bin").resolve(NATIVE_IMAGE_EXE).toFile(); diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java index 2c7e724d0..8af5a8cd2 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java @@ -118,9 +118,6 @@ public Provider getOutputFile() { return getOutputDirectory().map(dir -> dir.file(getExecutableName()).get()); } - @Input - public abstract Property getAgentConfiguration(); - @Input public abstract Property getDisableToolchainDetection(); @@ -154,7 +151,6 @@ private List buildActualCommandLineArgs() { getOptions().finalizeValue(); return new NativeImageCommandLineProvider( getOptions(), - getAgentConfiguration(), getExecutableShortName(), // Can't use getOutputDirectory().map(...) because Gradle would complain that we use // a mapped value before the task was called, when we are actually calling it... @@ -179,7 +175,7 @@ public void exec() { logger.lifecycle("Args are: " + args); } File executablePath = NativeImageExecutableLocator.findNativeImageExecutable( - options, + options.getJavaLauncher(), getDisableToolchainDetection(), getGraalVMHome(), getExecOperations(), diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/NativeRunTask.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/NativeRunTask.java index 4129bc83e..be71af965 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/NativeRunTask.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/NativeRunTask.java @@ -84,7 +84,7 @@ public void exec() { spec.setExecutable(getImage().get().getAsFile().getAbsolutePath()); spec.args(getRuntimeArgs().get()); if (getEnvironment().isPresent()) { - Map env = (Map) getEnvironment().get(); + Map env = getEnvironment().get(); for (Map.Entry entry : env.entrySet()) { spec.environment(entry.getKey(), entry.getValue()); } diff --git a/samples/java-application-with-reflection/build.gradle b/samples/java-application-with-reflection/build.gradle index 1fd07d1e8..416a1534d 100644 --- a/samples/java-application-with-reflection/build.gradle +++ b/samples/java-application-with-reflection/build.gradle @@ -46,6 +46,7 @@ plugins { repositories { mavenCentral() + mavenLocal() } application { @@ -66,13 +67,12 @@ test { } graalvmNative { + agent { + + } binaries { test { verbose = true - agent { - enabled = true - options.add(providers.systemProperty("agentOptions").forUseAtConfigurationTime()) - } } } } diff --git a/samples/java-application-with-reflection/settings.gradle b/samples/java-application-with-reflection/settings.gradle index 53fde2a34..3494ddadf 100644 --- a/samples/java-application-with-reflection/settings.gradle +++ b/samples/java-application-with-reflection/settings.gradle @@ -45,6 +45,7 @@ pluginManagement { } repositories { mavenCentral() + mavenLocal() gradlePluginPortal() } } From 5bb0697e681f68bde18c1f874b89d496546f95c7 Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Thu, 12 May 2022 18:48:02 +0200 Subject: [PATCH 04/10] 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 From 00947baad607715336e7d167be1f70fe5a5baa97 Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Mon, 23 May 2022 19:50:31 +0200 Subject: [PATCH 05/10] Multiple improvements. Rename copyMetadata to metadataCopy and move it into the agent block. Run the merge action from inside the MetadataCopyTask. Introduce a marker for agent options that is substituted with the output directory. --- .../buildtools/agent/AgentConfiguration.java | 1 + .../graalvm/buildtools/agent/AgentMode.java | 2 + .../agent/ConditionalAgentMode.java | 14 ++++ .../buildtools/agent/DirectAgentMode.java | 5 ++ .../buildtools/agent/DisabledAgentMode.java | 5 ++ .../buildtools/agent/StandardAgentMode.java | 10 ++- .../buildtools/utils/SharedConstants.java | 2 + .../buildtools/gradle/NativeImagePlugin.java | 67 +++++++------------ .../gradle/dsl/GraalVMExtension.java | 8 +-- .../gradle/dsl/agent/AgentOptions.java | 8 ++- ...aOptions.java => MetadataCopyOptions.java} | 2 +- .../internal/AgentCommandLineProvider.java | 14 ++-- .../internal/DefaultGraalVmExtension.java | 2 +- .../agent/AgentConfigurationFactory.java | 5 +- ...etadataTask.java => MetadataCopyTask.java} | 54 +++++++++++++-- .../tasks/actions/MergeAgentFilesAction.java | 23 ++++--- .../build.gradle | 14 ++-- .../filter.json | 1 + 18 files changed, 156 insertions(+), 81 deletions(-) rename native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/{CopyMetadataOptions.java => MetadataCopyOptions.java} (98%) rename native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/{CopyMetadataTask.java => MetadataCopyTask.java} (67%) 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 1058655ed..157040d74 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 @@ -68,6 +68,7 @@ public Collection getAgentFiles() { List files = new ArrayList<>(callerFilterFiles.size() + accessFilterFiles.size()); files.addAll(callerFilterFiles); files.addAll(accessFilterFiles); + files.addAll(agentMode.getInputFiles()); return files; } diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentMode.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentMode.java index 6ae61374a..6c9fafae4 100644 --- a/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentMode.java +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/AgentMode.java @@ -47,4 +47,6 @@ public interface AgentMode extends Serializable { List getAgentCommandLine(); List getNativeImageConfigureOptions(List inputDirectories, List outputDirectories); + + List getInputFiles(); } diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/ConditionalAgentMode.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/ConditionalAgentMode.java index 17c103966..2dae05fa0 100644 --- a/common/utils/src/main/java/org/graalvm/buildtools/agent/ConditionalAgentMode.java +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/ConditionalAgentMode.java @@ -44,6 +44,9 @@ import java.util.Collections; import java.util.List; +import static org.graalvm.buildtools.utils.SharedConstants.AGENT_OUTPUT_DIRECTORY_MARKER; +import static org.graalvm.buildtools.utils.SharedConstants.AGENT_OUTPUT_DIRECTORY_OPTION; + public class ConditionalAgentMode implements AgentMode { private final String userCodeFilterPath; @@ -59,6 +62,7 @@ public ConditionalAgentMode(String userCodeFilterPath, String extraFilterPath, b @Override public List getAgentCommandLine() { List cmdLine = new ArrayList<>(); + cmdLine.add(AGENT_OUTPUT_DIRECTORY_OPTION + AGENT_OUTPUT_DIRECTORY_MARKER); if (parallel) { cmdLine.add("experimental-conditional-config-part"); } else { @@ -91,4 +95,14 @@ public List getNativeImageConfigureOptions(List inputDirectories } return Collections.emptyList(); } + + @Override + public List getInputFiles() { + List files = new ArrayList<>(); + files.add(userCodeFilterPath); + if (!extraFilterPath.isEmpty()) { + files.add(extraFilterPath); + } + return files; + } } diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/DirectAgentMode.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/DirectAgentMode.java index b9948e14d..f6a4dc573 100644 --- a/common/utils/src/main/java/org/graalvm/buildtools/agent/DirectAgentMode.java +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/DirectAgentMode.java @@ -59,4 +59,9 @@ public List getAgentCommandLine() { public List getNativeImageConfigureOptions(List inputDirectories, List outputDirectories) { return Collections.emptyList(); } + + @Override + public List getInputFiles() { + return Collections.emptyList(); + } } diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/DisabledAgentMode.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/DisabledAgentMode.java index 418de8db7..78bc79061 100644 --- a/common/utils/src/main/java/org/graalvm/buildtools/agent/DisabledAgentMode.java +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/DisabledAgentMode.java @@ -53,4 +53,9 @@ public List getAgentCommandLine() { public List getNativeImageConfigureOptions(List inputDirectories, List outputDirectories) { return Collections.emptyList(); } + + @Override + public List getInputFiles() { + return Collections.emptyList(); + } } diff --git a/common/utils/src/main/java/org/graalvm/buildtools/agent/StandardAgentMode.java b/common/utils/src/main/java/org/graalvm/buildtools/agent/StandardAgentMode.java index 782b496cb..fc63e6ae6 100644 --- a/common/utils/src/main/java/org/graalvm/buildtools/agent/StandardAgentMode.java +++ b/common/utils/src/main/java/org/graalvm/buildtools/agent/StandardAgentMode.java @@ -44,10 +44,13 @@ import java.util.Collections; import java.util.List; +import static org.graalvm.buildtools.utils.SharedConstants.AGENT_OUTPUT_DIRECTORY_MARKER; +import static org.graalvm.buildtools.utils.SharedConstants.AGENT_OUTPUT_DIRECTORY_OPTION; + public class StandardAgentMode implements AgentMode { @Override public List getAgentCommandLine() { - return Collections.emptyList(); + return Collections.singletonList(AGENT_OUTPUT_DIRECTORY_OPTION + AGENT_OUTPUT_DIRECTORY_MARKER); } @Override @@ -63,4 +66,9 @@ public List getNativeImageConfigureOptions(List inputDirectories } return Collections.emptyList(); } + + @Override + public List getInputFiles() { + return Collections.emptyList(); + } } diff --git a/common/utils/src/main/java/org/graalvm/buildtools/utils/SharedConstants.java b/common/utils/src/main/java/org/graalvm/buildtools/utils/SharedConstants.java index 31ddf9963..2911e96f0 100644 --- a/common/utils/src/main/java/org/graalvm/buildtools/utils/SharedConstants.java +++ b/common/utils/src/main/java/org/graalvm/buildtools/utils/SharedConstants.java @@ -70,4 +70,6 @@ public interface SharedConstants { ".*/package.html" )); String AGENT_SESSION_SUBDIR = "session-{pid}-{datetime}"; + String AGENT_OUTPUT_DIRECTORY_MARKER = "{output_dir}"; + String AGENT_OUTPUT_DIRECTORY_OPTION = "config-output-dir="; } 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 2f8806348..8d54335b5 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 @@ -44,7 +44,6 @@ 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; @@ -62,7 +61,7 @@ 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.MetadataCopyTask; import org.graalvm.buildtools.gradle.tasks.GenerateResourcesConfigFile; import org.graalvm.buildtools.gradle.tasks.NativeRunTask; import org.graalvm.buildtools.gradle.tasks.actions.MergeAgentFilesAction; @@ -202,7 +201,13 @@ private void instrumentTasksWithAgent(Project project, DefaultGraalVmExtension g if (isTaskInstrumentableByAgent(t) && taskPredicate.test(t)) { configureAgent(project, agentConfiguration, graalExtension.getToolchainDetection(), getExecOperations(), getFileOperations(), t, (JavaForkOptions) t); } else { - logger.lifecycle("Skipping task: " + t.getName()); + String reason; + if (isTaskInstrumentableByAgent(t)) { + reason = "Not instrumentable by agent as it does not extend JavaForkOptions."; + } else { + reason = "Task does not match user predicate"; + } + logger.log("Not instrumenting task with native-image-agent: " + t.getName() + ". Reason: " + reason); } }); } @@ -251,32 +256,12 @@ private void configureJavaProject(Project project, Provider config.usingSourceSet(GradleUtils.findSourceSet(project, SourceSet.TEST_SOURCE_SET_NAME)); }); - TaskProvider copyMetadataTask = project.getTasks().register("copyMetadata", CopyMetadataTask.class, task -> { + TaskProvider copyMetadataTask = project.getTasks().register("copyMetadata", MetadataCopyTask.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())); + task.getInputTaskNames().set(graalExtension.getAgent().getMetadataCopy().getInputTaskNames()); + task.getOutputDirectories().set(graalExtension.getAgent().getMetadataCopy().getOutputDirectories()); + task.getMergeWithExisting().set(graalExtension.getAgent().getMetadataCopy().getMergeWithExisting()); }); } @@ -341,18 +326,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())); @@ -639,13 +624,13 @@ private void configureAgent(Project project, FileSystemOperations fileOperations, Task taskToInstrument, JavaForkOptions javaForkOptions) { - logger.lifecycle("Instrumenting task: " + taskToInstrument.getName()); + logger.lifecycle("Instrumenting task with the native-image-agent: " + 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 = AgentConfigurationFactory.getAgentOutputDirectoryForTask(project, taskToInstrument.getName()); + Provider outputDir = AgentConfigurationFactory.getAgentOutputDirectoryForTask(project.getLayout(), taskToInstrument.getName()); Provider isMergingEnabled = agentConfiguration.map(AgentConfiguration::isEnabled); Provider agentModeProvider = agentConfiguration.map(AgentConfiguration::getAgentMode); Provider> mergeOutputDirs = outputDir.map(dir -> Collections.singletonList(dir.getAsFile().getAbsolutePath())); @@ -658,7 +643,7 @@ private void configureAgent(Project project, isMergingEnabled, agentModeProvider, project.provider(() -> false), - project, + project.getObjects(), graalvmHomeProvider(project.getProviders()), mergeInputDirs, mergeOutputDirs, 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 e81ccf7c6..e9f1ee2b3 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,7 +42,6 @@ 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; @@ -63,16 +62,12 @@ public interface GraalVMExtension { * to disable automatic test support, especially in cases * where the test framework doesn't allow testing within * a native image. - * */ Property getTestSupport(); @Nested AgentOptions getAgent(); - @Nested - CopyMetadataOptions getCopyMetadata(); - void agent(Action spec); DirectoryProperty getGeneratedResourcesDirectory(); @@ -91,6 +86,7 @@ public interface GraalVMExtension { /** * Registers a new native image binary with testing support. + * * @param spec the test image configuration */ void registerTestBinary(String name, Action spec); @@ -105,6 +101,7 @@ public interface GraalVMExtension { * Property driving the use of @-arg files when invoking native image. * This is enabled by default. For older native-image versions, this * needs to be disabled. + * * @return the argument file property */ Property getUseArgFile(); @@ -114,6 +111,7 @@ interface TestBinaryConfig { /** * Sets the JVM test task which corresponds to the * native test that we're configuring. + * * @param jvmTestTask an existing JVM test task */ void forTestTask(TaskProvider jvmTestTask); 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 4dccf208e..097e42843 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 @@ -43,7 +43,6 @@ 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.tasks.Input; import org.gradle.api.tasks.InputFiles; @@ -73,6 +72,13 @@ default void modes(Action spec) { @Optional ConfigurableFileCollection getAccessFilterFiles(); + @Nested + MetadataCopyOptions getMetadataCopy(); + + default void metadataCopy(Action spec) { + spec.execute(getMetadataCopy()); + } + /** * Configures the tasks which needs to be instrumented * 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/MetadataCopyOptions.java similarity index 98% rename from native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/CopyMetadataOptions.java rename to native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/MetadataCopyOptions.java index 5f6106d0e..d07e20dc4 100644 --- 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/MetadataCopyOptions.java @@ -45,7 +45,7 @@ import org.gradle.api.tasks.Input; import org.gradle.api.tasks.Optional; -public interface CopyMetadataOptions { +public interface MetadataCopyOptions { @Input @Optional 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 9d297fe58..8b02779aa 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 @@ -47,7 +47,6 @@ 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; @@ -57,17 +56,18 @@ import javax.inject.Inject; 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.utils.SharedConstants.AGENT_OUTPUT_DIRECTORY_MARKER; public abstract class AgentCommandLineProvider implements CommandLineArgumentProvider { @Inject @SuppressWarnings("checkstyle:redundantmodifier") public AgentCommandLineProvider() { - } @Input @@ -87,12 +87,8 @@ public AgentCommandLineProvider() { @Override public Iterable asArguments() { if (getEnabled().get()) { - File outputDir = getOutputDirectory().getAsFile().get(); - List agentOptions = new ArrayList<>(getAgentOptions().getOrElse(Collections.emptyList())); - if (agentOptions.stream().map(s -> s.split("=")[0]).anyMatch(s -> s.contains("config-output-dir"))) { - throw new IllegalStateException("config-output-dir cannot be supplied as an agent option"); - } - agentOptions.add("config-output-dir=" + outputDir.getAbsolutePath() + File.separator + SharedConstants.AGENT_SESSION_SUBDIR); + String outputDirPath = getOutputDirectory().getAsFile().get().getAbsolutePath() + File.separator + SharedConstants.AGENT_SESSION_SUBDIR; + List agentOptions = getAgentOptions().get().stream().map(opt -> opt.replace(AGENT_OUTPUT_DIRECTORY_MARKER, outputDirPath)).collect(Collectors.toList()); return Arrays.asList( "-agentlib:native-image-agent=" + String.join(",", agentOptions), "-Dorg.graalvm.nativeimage.imagecode=agent" 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 dc4f60796..20184ea7d 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 @@ -77,7 +77,7 @@ public DefaultGraalVmExtension(NamedDomainObjectContainer na getAgent().getTasksToInstrumentPredicate().convention(t -> true); getAgent().getDefaultMode().convention("standard"); getAgent().getModes().getConditional().getParallel().convention(true); - getCopyMetadata().getMergeWithExisting().convention(false); + getAgent().getMetadataCopy().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 3ba94dc5e..98667eef4 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 @@ -52,6 +52,7 @@ import org.gradle.api.Project; import org.gradle.api.file.ConfigurableFileCollection; import org.gradle.api.file.Directory; +import org.gradle.api.file.ProjectLayout; import org.gradle.api.provider.Provider; import java.io.File; @@ -95,7 +96,7 @@ private static Collection getFilePaths(ConfigurableFileCollection config 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); + public static Provider getAgentOutputDirectoryForTask(ProjectLayout layout, String taskName) { + return layout.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/MetadataCopyTask.java similarity index 67% rename from native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/CopyMetadataTask.java rename to native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/MetadataCopyTask.java index ef73bdaf6..1296f39dc 100644 --- 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/MetadataCopyTask.java @@ -40,27 +40,55 @@ */ package org.graalvm.buildtools.gradle.tasks; +import org.graalvm.buildtools.agent.AgentMode; +import org.graalvm.buildtools.agent.StandardAgentMode; +import org.graalvm.buildtools.gradle.dsl.GraalVMExtension; import org.graalvm.buildtools.gradle.internal.GraalVMLogger; import org.graalvm.buildtools.gradle.internal.agent.AgentConfigurationFactory; +import org.graalvm.buildtools.gradle.tasks.actions.MergeAgentFilesAction; import org.gradle.api.DefaultTask; import org.gradle.api.GradleException; +import org.gradle.api.file.ProjectLayout; +import org.gradle.api.model.ObjectFactory; import org.gradle.api.provider.ListProperty; import org.gradle.api.provider.Property; +import org.gradle.api.provider.Provider; +import org.gradle.api.provider.ProviderFactory; import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.TaskAction; import org.gradle.api.tasks.options.Option; +import org.gradle.process.ExecOperations; +import javax.inject.Inject; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.util.List; -public abstract class CopyMetadataTask extends DefaultTask { +import static org.graalvm.buildtools.gradle.internal.NativeImageExecutableLocator.graalvmHomeProvider; + +public abstract class MetadataCopyTask extends DefaultTask { private final GraalVMLogger logger; - public CopyMetadataTask() { + private final ProjectLayout layout; + private final ProviderFactory providerFactory; + private final ObjectFactory objectFactory; + private final GraalVMExtension graalExtension; + private final ExecOperations execOperations; + + @Inject + public MetadataCopyTask(ProjectLayout layout, + ProviderFactory providerFactory, + ObjectFactory objectFactory, + GraalVMExtension graalExtension, + ExecOperations execOperations) { this.logger = GraalVMLogger.of(getLogger()); + this.layout = layout; + this.providerFactory = providerFactory; + this.objectFactory = objectFactory; + this.graalExtension = graalExtension; + this.execOperations = execOperations; } @Internal @@ -85,13 +113,16 @@ public void overrideOutputDirectories(List outputDirectories) { @TaskAction public void exec() { StringBuilder builder = new StringBuilder(); + ListProperty inputDirectories = objectFactory.listProperty(String.class); + for (String taskName : getInputTaskNames().get()) { - File dir = AgentConfigurationFactory.getAgentOutputDirectoryForTask(getProject(), taskName).get().getAsFile(); + File dir = AgentConfigurationFactory.getAgentOutputDirectoryForTask(layout, 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?"); } + inputDirectories.add(dir.getAbsolutePath()); } String errorString = builder.toString(); if (!errorString.isEmpty()) { @@ -99,7 +130,7 @@ public void exec() { } for (String dirName : getOutputDirectories().get()) { - File dir = getProject().getLayout().dir(getProject().provider(() -> new File(dirName))).get().getAsFile(); + File dir = layout.dir(providerFactory.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); @@ -113,5 +144,20 @@ public void exec() { } } } + + Provider isMergeEnabled = providerFactory.provider(() -> true); + Provider agentModeProvider = providerFactory.provider(StandardAgentMode::new); + + new MergeAgentFilesAction( + isMergeEnabled, + agentModeProvider, + getMergeWithExisting(), + objectFactory, + graalvmHomeProvider(providerFactory), + inputDirectories, + getOutputDirectories(), + graalExtension.getToolchainDetection(), + execOperations, + getLogger()).execute(this); } } 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 60b93c543..17450fde6 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 @@ -47,6 +47,7 @@ import org.gradle.api.Project; import org.gradle.api.Task; 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; @@ -77,7 +78,7 @@ public class MergeAgentFilesAction implements Action { public MergeAgentFilesAction(Provider isMergingEnabled, Provider agentMode, Provider mergeWithOutputs, - Project project, + ObjectFactory objectFactory, Provider graalvmHomeProvider, Provider> inputDirs, Provider> outputDirs, @@ -93,7 +94,7 @@ public MergeAgentFilesAction(Provider isMergingEnabled, this.disableToolchainDetection = disableToolchainDetection; this.execOperations = execOperations; this.logger = logger; - this.noLauncherProperty = project.getObjects().property(JavaLauncher.class); + this.noLauncherProperty = objectFactory.property(JavaLauncher.class); } private static boolean isConfigDir(String dir) { @@ -144,14 +145,16 @@ public void execute(Task task) { 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(); + if (nicCommandLine.size() > 0) { + 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/samples/java-application-with-reflection/build.gradle b/samples/java-application-with-reflection/build.gradle index 34487d530..b51eb96e3 100644 --- a/samples/java-application-with-reflection/build.gradle +++ b/samples/java-application-with-reflection/build.gradle @@ -69,17 +69,19 @@ test { graalvmNative { agent { defaultMode = "standard" + accessFilterFiles.from('test.json') + modes { conditional { userCodeFilterPath = "filter.json" } } - accessFilterFiles.from('test.json') - } - copyMetadata { - mergeWithExisting = true - inputTaskNames.add("test") - outputDirectories.add("src/main/resources/META-INF/native-image") + + metadataCopy { + mergeWithExisting = true + inputTaskNames.add("test") + outputDirectories.add("src/main/resources/META-INF/native-image") + } } binaries { test { diff --git a/samples/java-application-with-reflection/filter.json b/samples/java-application-with-reflection/filter.json index 366aacb63..e261fe506 100644 --- a/samples/java-application-with-reflection/filter.json +++ b/samples/java-application-with-reflection/filter.json @@ -1,6 +1,7 @@ { "rules": [ {"excludeClasses": "**"}, + {"includeClasses": "org.graalvm.demo.**"}, {"includeClasses": "org.graalvm.demo.**"} ] } \ No newline at end of file From 134d3d995176adcec0c604dc858b1b5a97703fd7 Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Mon, 23 May 2022 20:43:40 +0200 Subject: [PATCH 06/10] Post-process agent files in place --- .../buildtools/gradle/NativeImagePlugin.java | 48 ++++--------------- ...cessGeneratedGraalResourceFilesAction.java | 27 +++-------- 2 files changed, 16 insertions(+), 59 deletions(-) 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 8d54335b5..6e2e20364 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 @@ -57,14 +57,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.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.MetadataCopyTask; import org.graalvm.buildtools.gradle.tasks.GenerateResourcesConfigFile; +import org.graalvm.buildtools.gradle.tasks.MetadataCopyTask; 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.gradle.api.Action; import org.gradle.api.NamedDomainObjectContainer; @@ -119,7 +119,6 @@ import java.util.Locale; import java.util.Map; import java.util.Set; -import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -130,17 +129,11 @@ /** * Gradle plugin for GraalVM Native Image. */ -@SuppressWarnings("unused") public class NativeImagePlugin implements Plugin { public static final String NATIVE_COMPILE_TASK_NAME = "nativeCompile"; public static final String NATIVE_TEST_COMPILE_TASK_NAME = "nativeTestCompile"; public static final String NATIVE_TEST_TASK_NAME = "nativeTest"; - public static final String NATIVE_TEST_EXTENSION = "test"; public static final String NATIVE_MAIN_EXTENSION = "main"; - public static final String PROCESS_AGENT_RESOURCES_TASK_NAME_PREFIX = "filterAgent"; - public static final String PROCESS_AGENT_RESOURCES_TASK_NAME_SUFFIX = "Resources"; - public static final String GENERATE_RESOURCES_CONFIG_FILE_TASK_NAME = "generateResourcesConfigFile"; - public static final String GENERATE_TEST_RESOURCES_CONFIG_FILE_TASK_NAME = "generateTestResourcesConfigFile"; public static final String DEPRECATED_NATIVE_BUILD_EXTENSION = "nativeBuild"; public static final String DEPRECATED_NATIVE_TEST_EXTENSION = "nativeTest"; @@ -149,14 +142,6 @@ public class NativeImagePlugin implements Plugin { public static final String CONFIG_REPO_LOGLEVEL = "org.graalvm.internal.gradle.configrepo.logging"; - /** - * This looks strange, but it is used to force the configuration of a dependent - * task during the configuration of another one. This is a workaround for a bug - * when applying the Kotlin plugin, where the test task is configured too late - * for some reason. - */ - private static final Consumer FORCE_CONFIG = t -> { - }; private static final String JUNIT_PLATFORM_LISTENERS_UID_TRACKING_ENABLED = "junit.platform.listeners.uid.tracking.enabled"; private static final String JUNIT_PLATFORM_LISTENERS_UID_TRACKING_OUTPUT_DIR = "junit.platform.listeners.uid.tracking.output.dir"; @@ -188,9 +173,7 @@ public void apply(Project project) { project.getPlugins() .withType(JavaPlugin.class, javaPlugin -> configureJavaProject(project, nativeImageServiceProvider, graalExtension)); - project.afterEvaluate(p -> { - instrumentTasksWithAgent(project, graalExtension); - }); + project.afterEvaluate(p -> instrumentTasksWithAgent(project, graalExtension)); } private void instrumentTasksWithAgent(Project project, DefaultGraalVmExtension graalExtension) { @@ -246,7 +229,7 @@ private void configureJavaProject(Project project, Provider configureAutomaticTaskCreation(project, graalExtension, tasks, javaConvention.getSourceSets()); TaskProvider imageBuilder = tasks.named(NATIVE_COMPILE_TASK_NAME, BuildNativeImageTask.class); - TaskProvider deprecatedTask = tasks.register(DEPRECATED_NATIVE_BUILD_TASK, t -> { + tasks.register(DEPRECATED_NATIVE_BUILD_TASK, t -> { t.dependsOn(imageBuilder); t.doFirst("Warn about deprecation", task -> task.getLogger().warn("Task " + DEPRECATED_NATIVE_BUILD_TASK + " is deprecated. Use " + NATIVE_COMPILE_TASK_NAME + " instead.")); }); @@ -256,7 +239,7 @@ private void configureJavaProject(Project project, Provider config.usingSourceSet(GradleUtils.findSourceSet(project, SourceSet.TEST_SOURCE_SET_NAME)); }); - TaskProvider copyMetadataTask = project.getTasks().register("copyMetadata", MetadataCopyTask.class, task -> { + project.getTasks().register("copyMetadata", MetadataCopyTask.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.getAgent().getMetadataCopy().getInputTaskNames()); @@ -364,7 +347,6 @@ private void deprecateExtension(Project project, NativeImageOptions delegate, String name, String substitute) { - JavaToolchainService toolchains = project.getExtensions().findByType(JavaToolchainService.class); ObjectFactory objects = project.getObjects(); project.getExtensions().add(name, objects.newInstance(DeprecatedNativeImageOptions.class, name, @@ -465,7 +447,7 @@ public void registerTestBinary(Project project, DirectoryProperty testListDirectory = project.getObjects().directoryProperty(); // Add DSL extension for testing - NativeImageOptions testOptions = createTestOptions(graalExtension, name, project, mainOptions, testListDirectory, config.getSourceSet()); + NativeImageOptions testOptions = createTestOptions(graalExtension, name, project, mainOptions, config.getSourceSet()); if (isPrimaryTest) { deprecateExtension(project, testOptions, DEPRECATED_NATIVE_TEST_EXTENSION, "test"); } @@ -491,7 +473,7 @@ public void registerTestBinary(Project project, task.getTestListDirectory().set(testListDirectory); testTask.get(); if (!agentProperty(project, graalExtension.getAgent()).get().equals("disabled")) { - testOptions.getConfigurationFileDirectories().from(getProcessedAgentOutputFilesDirectory(project, testTask.get())); + testOptions.getConfigurationFileDirectories().from(AgentConfigurationFactory.getAgentOutputDirectoryForTask(project.getLayout(), testTask.getName())); } ConfigurableFileCollection testList = project.getObjects().fileCollection(); // Later this will be replaced by a dedicated task not requiring execution of tests @@ -528,7 +510,6 @@ private static Provider agentProperty(Project project, AgentOptions opti .orElse(project.provider(() -> "disabled")); } - @SuppressWarnings("UnstableApiUsage") private static void registerServiceProvider(Project project, Provider nativeImageServiceProvider) { project.getTasks() .withType(BuildNativeImageTask.class) @@ -587,7 +568,6 @@ private static NativeImageOptions createTestOptions(GraalVMExtension graalExtens String binaryName, Project project, NativeImageOptions mainExtension, - DirectoryProperty testListDirectory, SourceSet sourceSet) { NativeImageOptions testExtension = graalExtension.getBinaries().create(binaryName); NativeConfigurations configs = createNativeConfigurations( @@ -609,10 +589,6 @@ private static NativeImageOptions createTestOptions(GraalVMExtension graalExtens return testExtension; } - private static String postProcessTaskName(String taskName) { - return PROCESS_AGENT_RESOURCES_TASK_NAME_PREFIX + capitalize(taskName) + PROCESS_AGENT_RESOURCES_TASK_NAME_SUFFIX; - } - 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()); } @@ -650,20 +626,14 @@ private void configureAgent(Project project, disableToolchainDetection, execOperations, project.getLogger())); + 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) { project.afterEvaluate(p -> { if (testSupportEnabled.get()) { 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 index 1283788ea..f556fbad8 100644 --- 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 @@ -56,8 +56,6 @@ import java.io.OutputStreamWriter; import java.io.Writer; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; @@ -71,49 +69,38 @@ */ public class ProcessGeneratedGraalResourceFilesAction implements Action { private final Provider inputDirectory; - private final Provider outputDirectory; private final List filterableEntries; - public ProcessGeneratedGraalResourceFilesAction(Provider inputDirectory, Provider outputDirectory, List filterableEntries) { + public ProcessGeneratedGraalResourceFilesAction(Provider inputDirectory, List filterableEntries) { this.inputDirectory = inputDirectory; - this.outputDirectory = outputDirectory; this.filterableEntries = filterableEntries; } @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); - } + 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, File outputDir) throws IOException { + protected void processFile(File file) throws IOException { if (file.getName().endsWith(".json")) { - processJsonFile(file, outputDir); - } else { - copyFile(file, outputDir); + processJsonFile(file); } } - private static void copyFile(File file, File outputDir) throws IOException { - Files.copy(file.toPath(), outputDir.toPath().resolve(file.getName()), StandardCopyOption.REPLACE_EXISTING); - } - - protected void processJsonFile(File jsonFile, File outputDir) throws IOException { + 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(new File(outputDir, jsonFile.getName())), StandardCharsets.UTF_8)) { + try (Writer writer = new OutputStreamWriter(new FileOutputStream(jsonFile), StandardCharsets.UTF_8)) { writer.write(processed); } } From c8635d1d33ff6d0a4cfeb8521990375b84e275fa Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Mon, 23 May 2022 21:00:03 +0200 Subject: [PATCH 07/10] Properly re-run instrumented tasks if the agent mode changes. Make post-processing lists tweakable. --- .../buildtools/gradle/NativeImagePlugin.java | 15 +++++++++------ .../buildtools/gradle/dsl/agent/AgentOptions.java | 4 ++++ .../gradle/internal/AgentCommandLineProvider.java | 6 ++++++ .../gradle/internal/DefaultGraalVmExtension.java | 2 ++ .../ProcessGeneratedGraalResourceFilesAction.java | 7 ++++--- 5 files changed, 25 insertions(+), 9 deletions(-) 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 6e2e20364..e6c50192d 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 @@ -178,11 +178,10 @@ 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()); 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); + configureAgent(project, agentMode, graalExtension, getExecOperations(), getFileOperations(), t, (JavaForkOptions) t); } else { String reason; if (isTaskInstrumentableByAgent(t)) { @@ -594,17 +593,20 @@ private static List agentSessionDirectories(Directory outputDirectory) { } private void configureAgent(Project project, - Provider agentConfiguration, - Provider disableToolchainDetection, + Provider agentMode, + GraalVMExtension graalExtension, ExecOperations execOperations, FileSystemOperations fileOperations, Task taskToInstrument, JavaForkOptions javaForkOptions) { logger.lifecycle("Instrumenting task with the native-image-agent: " + taskToInstrument.getName()); + Provider agentConfiguration = AgentConfigurationFactory.getAgentConfiguration(agentMode, graalExtension.getAgent()); AgentCommandLineProvider cliProvider = project.getObjects().newInstance(AgentCommandLineProvider.class); cliProvider.getInputFiles().from(agentConfiguration.map(AgentConfiguration::getAgentFiles)); cliProvider.getEnabled().set(agentConfiguration.map(AgentConfiguration::isEnabled)); + cliProvider.getFilterableEntries().set(graalExtension.getAgent().getFilterableEntries()); + cliProvider.getAgentMode().set(agentMode); Provider outputDir = AgentConfigurationFactory.getAgentOutputDirectoryForTask(project.getLayout(), taskToInstrument.getName()); Provider isMergingEnabled = agentConfiguration.map(AgentConfiguration::isEnabled); @@ -623,7 +625,7 @@ private void configureAgent(Project project, graalvmHomeProvider(project.getProviders()), mergeInputDirs, mergeOutputDirs, - disableToolchainDetection, + graalExtension.getToolchainDetection(), execOperations, project.getLogger())); @@ -631,7 +633,8 @@ private void configureAgent(Project project, taskToInstrument.doLast(new ProcessGeneratedGraalResourceFilesAction( outputDir, - Arrays.asList("org.gradle.", "java.", "org.junit."))); + graalExtension.getAgent().getFilterableEntries() + )); } private static void injectTestPluginDependencies(Project project, Property testSupportEnabled) { 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 097e42843..ac76b3e31 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 @@ -43,6 +43,7 @@ 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.tasks.Input; import org.gradle.api.tasks.InputFiles; @@ -79,6 +80,9 @@ default void metadataCopy(Action spec) { spec.execute(getMetadataCopy()); } + @Input + ListProperty getFilterableEntries(); + /** * Configures the tasks which needs to be instrumented * 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 8b02779aa..02f22ea30 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 @@ -80,6 +80,12 @@ public AgentCommandLineProvider() { @PathSensitive(PathSensitivity.RELATIVE) public abstract ConfigurableFileCollection getInputFiles(); + @Input + public abstract ListProperty getFilterableEntries(); + + @Input + public abstract Property getAgentMode(); + @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 20184ea7d..95e871b01 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 @@ -56,6 +56,7 @@ import org.gradle.jvm.toolchain.JvmVendorSpec; import javax.inject.Inject; +import java.util.Arrays; public abstract class DefaultGraalVmExtension implements GraalVMExtension { private final NamedDomainObjectContainer nativeImages; @@ -78,6 +79,7 @@ public DefaultGraalVmExtension(NamedDomainObjectContainer na getAgent().getDefaultMode().convention("standard"); getAgent().getModes().getConditional().getParallel().convention(true); getAgent().getMetadataCopy().getMergeWithExisting().convention(false); + getAgent().getFilterableEntries().convention(Arrays.asList("org.gradle.", "java.", "org.junit.")); configureToolchain(); } 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 index f556fbad8..aaefbd3a0 100644 --- 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 @@ -48,6 +48,7 @@ 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; @@ -69,9 +70,9 @@ */ public class ProcessGeneratedGraalResourceFilesAction implements Action { private final Provider inputDirectory; - private final List filterableEntries; + private final ListProperty filterableEntries; - public ProcessGeneratedGraalResourceFilesAction(Provider inputDirectory, List filterableEntries) { + public ProcessGeneratedGraalResourceFilesAction(Provider inputDirectory, ListProperty filterableEntries) { this.inputDirectory = inputDirectory; this.filterableEntries = filterableEntries; } @@ -146,7 +147,7 @@ private Map filterMap(Map map) { private boolean shouldFilterString(Object value) { if (value instanceof CharSequence) { String string = value.toString(); - return filterableEntries.stream().anyMatch(string::startsWith); + return filterableEntries.get().stream().anyMatch(string::startsWith); } return false; } From 5b104dd1ebf0c342e20213859043c8f00f0858f8 Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Wed, 25 May 2022 04:48:29 +0200 Subject: [PATCH 08/10] Update agent functional tests --- ...aApplicationWithAgentFunctionalTest.groovy | 98 +++++++++---------- .../buildtools/gradle/NativeImagePlugin.java | 3 +- .../gradle/dsl/agent/AgentOptions.java | 4 +- .../NativeImageCommandLineProvider.java | 2 +- .../NativeImageExecutableLocator.java | 5 +- .../agent/AgentConfigurationFactory.java | 1 - .../gradle/tasks/BuildNativeImageTask.java | 1 - .../gradle/tasks/MetadataCopyTask.java | 15 +-- .../tasks/actions/MergeAgentFilesAction.java | 1 - .../build.gradle | 6 +- .../settings.gradle | 1 - .../META-INF/native-image/jni-config.json | 2 + .../predefined-classes-config.json | 8 ++ .../META-INF/native-image/proxy-config.json | 3 + .../META-INF/native-image/reflect-config.json | 5 + .../native-image/resource-config.json | 9 ++ .../native-image/serialization-config.json | 8 ++ .../{filter.json => user-code-filter.json} | 0 18 files changed, 99 insertions(+), 73 deletions(-) create mode 100644 samples/java-application-with-reflection/src/main/resources/META-INF/native-image/jni-config.json create mode 100644 samples/java-application-with-reflection/src/main/resources/META-INF/native-image/predefined-classes-config.json create mode 100644 samples/java-application-with-reflection/src/main/resources/META-INF/native-image/proxy-config.json create mode 100644 samples/java-application-with-reflection/src/main/resources/META-INF/native-image/reflect-config.json create mode 100644 samples/java-application-with-reflection/src/main/resources/META-INF/native-image/resource-config.json create mode 100644 samples/java-application-with-reflection/src/main/resources/META-INF/native-image/serialization-config.json rename samples/java-application-with-reflection/{filter.json => user-code-filter.json} (100%) 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 d06a46156..e98659f09 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 @@ -47,19 +47,33 @@ import spock.lang.Unroll class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest { - @Unroll("agent is passed and generates resources files with JUnit Platform #junitVersion") + @Unroll("agent is not passed and the application fails with JUnit Platform #junitVersion") + def "agent is not passed"() { + given: + withSample("java-application-with-reflection") + + when: + fails 'nativeTest' + + then: + outputContains "expected: but was: " + + where: + junitVersion = System.getProperty('versions.junit') + } + + @Unroll("agent is passed, generates metadata files and copies metadata with JUnit Platform #junitVersion") def "agent is passed"() { debug = true given: withSample("java-application-with-reflection") when: - run 'nativeTest' + run 'nativeTest', '-Pagent' then: tasks { succeeded ':jar', - ':filterAgentTestResources', ':nativeTest' doesNotContain ':build' } @@ -85,6 +99,15 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest { assert file("build/native/agent-output/test/${name}-config.json").exists() } + when: + run 'metadataCopy' + + then: + ['jni', 'proxy', 'reflect', 'resource', 'serialization'].each { name -> + assert file("build/native/metadataCopyTest/${name}-config.json").exists() + } + + where: junitVersion = System.getProperty('versions.junit') } @@ -95,24 +118,29 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest { withSample("java-application-with-reflection") when: - fails 'nativeTest', '-Pagent=false' + run 'nativeTest', '-Pagent=conditional' then: - outputContains """org.graalvm.demo.ApplicationTest > message is hello native FAILED""" + tasks { + succeeded ':nativeTest' + } + + and: + assert file("build/native/agent-output/test/reflect-config.json").text.contains("\"condition\"") where: junitVersion = System.getProperty('versions.junit') } - @Issue("https://github.com/graalvm/native-build-tools/issues/134") - @Unroll("generated agent files are added when building native image with JUnit Platform #junitVersion") - def "generated agent files are used when building native image"() { + @Unroll("agent instruments run task, metadata is copied and merged, and the app runs JUnit Platform #junitVersion") + def "agent instruments run task"() { debug = true + var metadata_dir = 'src/main/resources/META-INF/native-image' given: withSample("java-application-with-reflection") when: - run '-Pagent=true', 'run' + run 'run', '-Pagent=standard' then: tasks { @@ -126,55 +154,23 @@ class JavaApplicationWithAgentFunctionalTest extends AbstractFunctionalTest { } when: - run '-Pagent=true', 'nativeRun' - - then: - outputContains "Application message: Hello, native!" - - where: - junitVersion = System.getProperty('versions.junit') - } - - def "can configure extra options to the agent"() { - debug = true - given: - withSample("java-application-with-reflection") - - when: - fails 'nativeTest', '-DagentOptions=will-fail' + run'metadataCopy', '--task', 'run', '--dir', metadata_dir then: - errorOutputContains "native-image-agent: unknown option: 'will-fail'." - - where: - junitVersion = System.getProperty('versions.junit') - } - - def "reasonable error message if the user provides themselves an output directory"() { - debug = true - given: - withSample("java-application-with-reflection") - - when: - fails 'nativeTest', '-DagentOptions=config-output-dir' - - then: - errorOutputContains "config-output-dir cannot be supplied as an agent option" - - where: - junitVersion = System.getProperty('versions.junit') - } + ['jni', 'proxy', 'reflect', 'resource', 'serialization'].each { name -> + assert file("${metadata_dir}/${name}-config.json").exists() + } - def "reasonable error message if the user provides themselves an output directory value"() { - debug = true - given: - withSample("java-application-with-reflection") + 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") when: - fails 'nativeTest', '-DagentOptions=config-output-dir=nope!' + run 'nativeRun' then: - errorOutputContains "config-output-dir cannot be supplied as an agent option" + outputContains "Application message: Hello, native!" where: junitVersion = System.getProperty('versions.junit') 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 e6c50192d..9b010a7c4 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 @@ -238,12 +238,13 @@ private void configureJavaProject(Project project, Provider config.usingSourceSet(GradleUtils.findSourceSet(project, SourceSet.TEST_SOURCE_SET_NAME)); }); - project.getTasks().register("copyMetadata", MetadataCopyTask.class, task -> { + project.getTasks().register("metadataCopy", MetadataCopyTask.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.getAgent().getMetadataCopy().getInputTaskNames()); task.getOutputDirectories().set(graalExtension.getAgent().getMetadataCopy().getOutputDirectories()); task.getMergeWithExisting().set(graalExtension.getAgent().getMetadataCopy().getMergeWithExisting()); + task.getToolchainDetection().set(graalExtension.getToolchainDetection()); }); } 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 ac76b3e31..5339a29f3 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 @@ -84,9 +84,9 @@ default void metadataCopy(Action spec) { ListProperty getFilterableEntries(); /** - * Configures the tasks which needs to be instrumented + * Selects tasks that should be instrumented with the agent. * - * @return . + * @return Task predicate that accepts tasks during task configuration. */ @Input Property> getTasksToInstrumentPredicate(); diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java index 208beeb7f..7a12094f4 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/NativeImageCommandLineProvider.java @@ -42,7 +42,6 @@ package org.graalvm.buildtools.gradle.internal; import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; -import org.graalvm.buildtools.agent.AgentConfiguration; import org.graalvm.buildtools.utils.NativeImageUtils; import org.gradle.api.Transformer; import org.gradle.api.file.FileSystemLocation; @@ -153,6 +152,7 @@ public List asArguments() { * to build images within a docker container, which makes it so * that the paths in the options are invalid (they would be prefixed * by a Windows path). + * * @param options the native options * @return the classpath string */ 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 5f938b8a8..1b528bd0c 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 @@ -40,7 +40,6 @@ */ package org.graalvm.buildtools.gradle.internal; -import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; import org.gradle.api.GradleException; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; @@ -103,8 +102,8 @@ public static File findNativeImageExecutable(Property javaLauncher } } 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"); + + "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"); } return executablePath; } 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 98667eef4..3c1c45da5 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,7 +49,6 @@ 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.file.ProjectLayout; diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java index 8af5a8cd2..2588c2f23 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/BuildNativeImageTask.java @@ -46,7 +46,6 @@ import org.graalvm.buildtools.gradle.internal.GraalVMLogger; import org.graalvm.buildtools.gradle.internal.NativeImageCommandLineProvider; import org.graalvm.buildtools.gradle.internal.NativeImageExecutableLocator; -import org.graalvm.buildtools.agent.AgentConfiguration; import org.gradle.api.DefaultTask; import org.gradle.api.file.Directory; import org.gradle.api.file.DirectoryProperty; diff --git a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/MetadataCopyTask.java b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/MetadataCopyTask.java index 1296f39dc..1efc510a3 100644 --- a/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/MetadataCopyTask.java +++ b/native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/tasks/MetadataCopyTask.java @@ -42,7 +42,6 @@ import org.graalvm.buildtools.agent.AgentMode; import org.graalvm.buildtools.agent.StandardAgentMode; -import org.graalvm.buildtools.gradle.dsl.GraalVMExtension; import org.graalvm.buildtools.gradle.internal.GraalVMLogger; import org.graalvm.buildtools.gradle.internal.agent.AgentConfigurationFactory; import org.graalvm.buildtools.gradle.tasks.actions.MergeAgentFilesAction; @@ -74,20 +73,17 @@ public abstract class MetadataCopyTask extends DefaultTask { private final ProjectLayout layout; private final ProviderFactory providerFactory; private final ObjectFactory objectFactory; - private final GraalVMExtension graalExtension; private final ExecOperations execOperations; @Inject public MetadataCopyTask(ProjectLayout layout, ProviderFactory providerFactory, ObjectFactory objectFactory, - GraalVMExtension graalExtension, ExecOperations execOperations) { this.logger = GraalVMLogger.of(getLogger()); this.layout = layout; this.providerFactory = providerFactory; this.objectFactory = objectFactory; - this.graalExtension = graalExtension; this.execOperations = execOperations; } @@ -100,12 +96,15 @@ public MetadataCopyTask(ProjectLayout layout, @Internal public abstract Property getMergeWithExisting(); + @Internal + public abstract Property getToolchainDetection(); + @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 = "") + @Option(option = "dir", description = "Directory to which the metadata will be copied.") public void overrideOutputDirectories(List outputDirectories) { getOutputDirectories().set(outputDirectories); } @@ -129,8 +128,10 @@ public void exec() { throw new GradleException(errorString); } + ListProperty outputDirectories = objectFactory.listProperty(String.class); for (String dirName : getOutputDirectories().get()) { File dir = layout.dir(providerFactory.provider(() -> new File(dirName))).get().getAsFile(); + outputDirectories.add(dir.getAbsolutePath()); if (dir.exists()) { if (!dir.isDirectory()) { builder.append("Specified output path must either not exist or be a directory: ").append(dirName); @@ -155,8 +156,8 @@ public void exec() { objectFactory, graalvmHomeProvider(providerFactory), inputDirectories, - getOutputDirectories(), - graalExtension.getToolchainDetection(), + outputDirectories, + getToolchainDetection(), execOperations, getLogger()).execute(this); } 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 17450fde6..4a4e43959 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 @@ -44,7 +44,6 @@ import org.graalvm.buildtools.gradle.internal.GraalVMLogger; 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.logging.Logger; import org.gradle.api.model.ObjectFactory; diff --git a/samples/java-application-with-reflection/build.gradle b/samples/java-application-with-reflection/build.gradle index b51eb96e3..c36340782 100644 --- a/samples/java-application-with-reflection/build.gradle +++ b/samples/java-application-with-reflection/build.gradle @@ -46,7 +46,6 @@ plugins { repositories { mavenCentral() - mavenLocal() } application { @@ -69,18 +68,17 @@ test { graalvmNative { agent { defaultMode = "standard" - accessFilterFiles.from('test.json') modes { conditional { - userCodeFilterPath = "filter.json" + userCodeFilterPath = "user-code-filter.json" } } metadataCopy { mergeWithExisting = true inputTaskNames.add("test") - outputDirectories.add("src/main/resources/META-INF/native-image") + outputDirectories.add("build/native/metadataCopyTest") } } binaries { diff --git a/samples/java-application-with-reflection/settings.gradle b/samples/java-application-with-reflection/settings.gradle index 3494ddadf..53fde2a34 100644 --- a/samples/java-application-with-reflection/settings.gradle +++ b/samples/java-application-with-reflection/settings.gradle @@ -45,7 +45,6 @@ pluginManagement { } repositories { mavenCentral() - mavenLocal() gradlePluginPortal() } } diff --git a/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/jni-config.json b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/jni-config.json new file mode 100644 index 000000000..0d4f101c7 --- /dev/null +++ b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/jni-config.json @@ -0,0 +1,2 @@ +[ +] diff --git a/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/predefined-classes-config.json b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/predefined-classes-config.json new file mode 100644 index 000000000..df6f9356f --- /dev/null +++ b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/predefined-classes-config.json @@ -0,0 +1,8 @@ +[ + { + "type": "agent-extracted", + "classes": [ + + ] + } +] diff --git a/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/proxy-config.json b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/proxy-config.json new file mode 100644 index 000000000..41b42e677 --- /dev/null +++ b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/proxy-config.json @@ -0,0 +1,3 @@ +[ + +] diff --git a/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/reflect-config.json b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/reflect-config.json new file mode 100644 index 000000000..eca7589aa --- /dev/null +++ b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/reflect-config.json @@ -0,0 +1,5 @@ +[ + { + "name": "DummyClass" + } +] diff --git a/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/resource-config.json b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/resource-config.json new file mode 100644 index 000000000..28680f37d --- /dev/null +++ b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/resource-config.json @@ -0,0 +1,9 @@ +{ + "resources": { + "includes": [ + ] + }, + "bundles": [ + + ] +} diff --git a/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/serialization-config.json b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/serialization-config.json new file mode 100644 index 000000000..bb47bac64 --- /dev/null +++ b/samples/java-application-with-reflection/src/main/resources/META-INF/native-image/serialization-config.json @@ -0,0 +1,8 @@ +{ + "lambdaCapturingTypes": [ + + ], + "types": [ + + ] +} diff --git a/samples/java-application-with-reflection/filter.json b/samples/java-application-with-reflection/user-code-filter.json similarity index 100% rename from samples/java-application-with-reflection/filter.json rename to samples/java-application-with-reflection/user-code-filter.json From 1257d59d591036d3123867d794b1a98660aad710 Mon Sep 17 00:00:00 2001 From: Aleksandar Gradinac Date: Wed, 25 May 2022 05:21:02 +0200 Subject: [PATCH 09/10] Agent doc refactor and support for additional options --- .../buildtools/agent/AgentConfiguration.java | 25 ++++++++- docs/src/docs/asciidoc/gradle-plugin.adoc | 39 ++++++-------- docs/src/docs/asciidoc/index.adoc | 10 ++++ .../docs/snippets/gradle/groovy/build.gradle | 48 +++++++++++++++-- .../snippets/gradle/kotlin/build.gradle.kts | 28 +--------- .../gradle/dsl/agent/AgentOptions.java | 52 +++++++++++++++++++ .../internal/DefaultGraalVmExtension.java | 16 ++++-- .../agent/AgentConfigurationFactory.java | 9 +++- 8 files changed, 167 insertions(+), 60 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 157040d74..7e3dfe404 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 @@ -49,11 +49,29 @@ public class AgentConfiguration implements Serializable { private final Collection callerFilterFiles; private final Collection accessFilterFiles; + private final boolean builtinCallerFilter; + private final boolean builtinHeuristicFilter; + private final boolean experimentalPredefinedClasses; + private final boolean experimentalUnsafeAllocationTracing; + private final boolean trackReflectionMetadata; + private final AgentMode agentMode; - public AgentConfiguration(Collection callerFilterFiles, Collection accessFilterFiles, AgentMode agentMode) { + public AgentConfiguration(Collection callerFilterFiles, + Collection accessFilterFiles, + boolean builtinCallerFilter, + boolean builtinHeuristicFilter, + boolean experimentalPredefinedClasses, + boolean experimentalUnsafeAllocationTracing, + boolean trackReflectionMetadata, + AgentMode agentMode) { this.callerFilterFiles = callerFilterFiles; this.accessFilterFiles = accessFilterFiles; + this.builtinCallerFilter = builtinCallerFilter; + this.builtinHeuristicFilter = builtinHeuristicFilter; + this.experimentalPredefinedClasses = experimentalPredefinedClasses; + this.experimentalUnsafeAllocationTracing = experimentalUnsafeAllocationTracing; + this.trackReflectionMetadata = trackReflectionMetadata; this.agentMode = agentMode; } @@ -61,6 +79,11 @@ public List getAgentCommandLine() { List cmdLine = new ArrayList<>(agentMode.getAgentCommandLine()); appendOptionToValues("caller-filter-file=", callerFilterFiles, cmdLine); appendOptionToValues("access-filter-file=", accessFilterFiles, cmdLine); + cmdLine.add("builtin-caller-filter=" + builtinCallerFilter); + cmdLine.add("builtin-heuristic-filter=" + builtinHeuristicFilter); + cmdLine.add("experimental-class-define-support=" + experimentalPredefinedClasses); + cmdLine.add("experimental-unsafe-allocation-support=" + experimentalUnsafeAllocationTracing); + cmdLine.add("track-reflection-metadata=" + trackReflectionMetadata); return cmdLine; } diff --git a/docs/src/docs/asciidoc/gradle-plugin.adoc b/docs/src/docs/asciidoc/gradle-plugin.adoc index d864ea551..65e3f0954 100644 --- a/docs/src/docs/asciidoc/gradle-plugin.adoc +++ b/docs/src/docs/asciidoc/gradle-plugin.adoc @@ -285,24 +285,33 @@ The same mechanism can be used if you have multiple test tasks for a single test If your project requires reflection, classpath resources, dynamic proxies or other features requiring explicit native configuration, it may prove helpful to first run your application or tests using the https://www.graalvm.org/reference-manual/native-image/Agent/[`native-image-agent`]. -The Native Image Gradle plugin simplifies generation of the required configuration files by injecting the agent automatically for you (this includes, but is not limited to the reflection file). +The Native Image Gradle plugin simplifies generation of the required metadata files by injecting the agent automatically for you (this includes, but is not limited to the reflection file). -This should be as easy as appending `-Pagent` to the `run` and `nativeBuild`, or `test` and `nativeTest` task invocations: +Any task that extends `JavaForkOptions` (like `test`, `run` etc) can be instrumented by passing `-Pagent` to gradle when running said tasks. + +The agent can run in multiple modes that dictate how the metadata is collected and merged. + +Once the metadata is collected, it can be copied into the project using the `metadataCopy` task. [source,bash] ---- ./gradlew -Pagent run # Runs on JVM with native-image-agent. -./gradlew -Pagent nativeCompile # Builds image using configuration acquired by agent. +./gradlew metadataCopy --task run --dir src/main/resources/META-INF/native-image # Copies the metadata collected by the agent into the project sources +./gradlew nativeCompile # Builds image using metadata acquired by the agent. # For testing -./gradlew -Pagent test # Runs on JVM with native-image-agent. -./gradlew -Pagent nativeTest # Builds image using configuration acquired by agent. +./gradlew -Pagent nativeTest # Runs on JVM with the native-image agent, collects the metadata and uses it for testing on native-image. ---- -The agent can also be enabled by setting the corresponding DSL flag; however, that is not recommended since this is a development mode feature only. +The agent can run in multiple modes: +* Standard - Collects metadata without conditions. This is recommended if you are building an executable. +* Conditional - Collects metadata with conditions. This is recommended if you are creating conditional metadata for a library intended for further use. +* Direct - For advanced users only. This mode allows directly controlling the command line passed to the agent. + +The default mode is specified in the DSL but can be changed by passing the mode name to Gradle when using the agent: `-Pagent=conditional` The generated configuration files will be found in the `${buildDir}/native/agent-output/${taskName}` directory, for example, `build/native/agent-output/run`. -Although those files will be automatically used if you run your build with the agent enabled, you should consider reviewing them and adding them to your sources instead. +The plugin will also substitute `{output_dir}` in the agent options to point to this directory during the agent run. [[agent-support-configuring-options]] === Configuring agent options @@ -310,7 +319,7 @@ Although those files will be automatically used if you run your build with the a The native agent can be configured https://www.graalvm.org/reference-manual/native-image/Agent/[with additional options]. This can be done using the `agent` configuration block: -.Configuring agent options for every binary +.Configuring agent options [source, groovy, role="multi-language-sample"] ---- include::../snippets/gradle/groovy/build.gradle[tags=add-agent-options] @@ -321,20 +330,6 @@ include::../snippets/gradle/groovy/build.gradle[tags=add-agent-options] include::../snippets/gradle/kotlin/build.gradle.kts[tags=add-agent-options] ---- -You may also define distinct agent options for different images. -In the following example, the agent used for instrumentation for the main image has distinct options from the test ones: - -.Configuring agent options specifically -[source, groovy, role="multi-language-sample"] ----- -include::../snippets/gradle/groovy/build.gradle[tags=add-agent-options-individual] ----- - -[source, kotlin, role="multi-language-sample"] ----- -include::../snippets/gradle/kotlin/build.gradle.kts[tags=add-agent-options-individual] ----- - [[metadata-support]] == JVM Reachability Metadata support diff --git a/docs/src/docs/asciidoc/index.adoc b/docs/src/docs/asciidoc/index.adoc index d25f3bdb0..091352487 100644 --- a/docs/src/docs/asciidoc/index.adoc +++ b/docs/src/docs/asciidoc/index.adoc @@ -14,6 +14,16 @@ If you are interested in contributing, please refer to our https://github.com/gr [[changelog]] == Changelog +=== Release 0.9.12 + +==== Gradle plugin +* Completely reworked agent support - **BREAKING CHANGE** +* The agent block is no longer tied to the target binary. +* The agent can now instrument any task that extends `JavaForkOptions`. +* Introduced the `metadataCopy` task. +* Introduced the concept of agent modes. +** Under the hood, the agent mode dictates what options are passed to the agent and how metadata produced by multiple runs get merged. + === Release 0.9.11 ==== Maven plugin diff --git a/docs/src/docs/snippets/gradle/groovy/build.gradle b/docs/src/docs/snippets/gradle/groovy/build.gradle index 91c9f9fbd..b83d64ad0 100644 --- a/docs/src/docs/snippets/gradle/groovy/build.gradle +++ b/docs/src/docs/snippets/gradle/groovy/build.gradle @@ -67,6 +67,49 @@ if (providers.environmentVariable("DISABLE_TOOLCHAIN").isPresent()) { // tag::all-config-options[] graalvmNative { + // Injects the native-image-agent into supported tasks if `-Pagent` is specified + agent { + defaultMode = "standard" // Default agent mode if one isn't specified using `-Pagent=mode_name` + + modes { + // The standard agent mode generates metadata without conditions. + standard { + } + // The conditional agent mode generates metadata with conditions. + conditional { + userCodeFilterPath = "path-to-filter.json" // Path to a filter file that determines classes which will be used in the metadata conditions. + extrFilterPath = "path-to-another-filter.json" // Optional, extra filter used to further filter the collected metadata. + } + // The direct agent mode allows users to directly pass options to the agent. + direct { + // {output_dir} is a special string expanded by the plugin to where the agent files would usually be output. + options.add("config-output-dir={output_dir}") + options.add("experimental-configuration-with-origins") + } + } + + callerFilterFiles.from("filter.json") + accessFilterFiles.from("filter.json") + builtinCallerFilter = true + builtinHeuristicFilter = true + enableExperimentalPredefinedClasses = false + enableExperimentalUnsafeAllocationTracing = false + trackReflectionMetadata = true + + // Copies metadata collected from tasks into the specified directories. + metadataCopy { + inputTaskNames.add("test") // Tasks previously executed with the agent attached. + outputDirectories.add("src/main/resources/META-INF/native-image") + mergeWithExisting = true // Instead of copying, merge with existing metadata in the output directories. + } + + /* + By default, if `-Pagent` is specified, all tasks that extend JavaForkOptions are instrumented. + This can be limited to only specific tasks that match this predicate. + */ + tasksToInstrumentPredicate = t -> true + } + binaries { main { // Main options @@ -87,11 +130,6 @@ graalvmNative { // Runtime options runtimeArgs.add('--help') // Passes '--help' to built image, during "nativeRun" task - // Development options - agent { - enabled = true // Enables the reflection agent. Can be also set on command line using '-Pagent' - } - useFatJar = true // Instead of passing each jar individually, builds a fat jar } } diff --git a/docs/src/docs/snippets/gradle/kotlin/build.gradle.kts b/docs/src/docs/snippets/gradle/kotlin/build.gradle.kts index 78db3e99a..70380760d 100644 --- a/docs/src/docs/snippets/gradle/kotlin/build.gradle.kts +++ b/docs/src/docs/snippets/gradle/kotlin/build.gradle.kts @@ -88,11 +88,6 @@ graalvmNative { // Runtime options runtimeArgs.add("--help") // Passes '--help' to built image, during "nativeRun" task - // Development options - agent { - enabled.set(true) // Enables the reflection agent. Can be also set on command line using '-Pagent' - } - useFatJar.set(true) // Instead of passing each jar individually, builds a fat jar } } @@ -138,31 +133,12 @@ graalvmNative { // tag::add-agent-options[] graalvmNative { - binaries.configureEach { - agent { - options.add("experimental-class-loader-support") - } + agent { + enableExperimentalPredefinedClasses = true } } // end::add-agent-options[] -// tag::add-agent-options-individual[] -graalvmNative { - binaries { - named("main") { - agent { - options.add("experimental-class-loader-support") - } - } - named("test") { - agent { - options.add("access-filter-file=${projectDir}/src/test/resources/access-filter.json") - } - } - } -} -// end::add-agent-options-individual[] - // tag::enable-metadata-repository[] graalvmNative { metadataRepository { 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 5339a29f3..473b47e24 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 @@ -54,6 +54,9 @@ @SuppressWarnings({"unused"}) public interface AgentOptions { + /** + * Contains configuration of supported agent modes. + */ @Nested AgentModeOptions getModes(); @@ -61,18 +64,63 @@ default void modes(Action spec) { spec.execute(getModes()); } + /** + * The default agent mode name when the agent is in use. + */ @Input @Optional Property getDefaultMode(); + /** + * Caller-filter files that will be passed to the agent. + */ @InputFiles @Optional ConfigurableFileCollection getCallerFilterFiles(); + /** + * Access-filter files that will be passed to the agent. + */ @InputFiles @Optional ConfigurableFileCollection getAccessFilterFiles(); + /** + * Toggles the builtin agent caller filter. + */ + @Optional + Property getBuiltinCallerFilter(); + + /** + * Toggles the builtin agent heuristic filter. + */ + @Optional + Property getBuiltinHeuristicFilter(); + + + /** + * Toggles the experimental support for predefined classes. + */ + @Optional + Property getEnableExperimentalPredefinedClasses(); + + + /** + * Toggles the experimental support for unsafe allocation tracing. + */ + @Optional + Property getEnableExperimentalUnsafeAllocationTracing(); + + + /** + * Toggles the distinction between queried and used metadata. + */ + @Optional + Property getTrackReflectionMetadata(); + + /** + * Configuration of the metadata copy task. + */ @Nested MetadataCopyOptions getMetadataCopy(); @@ -80,7 +128,11 @@ default void metadataCopy(Action spec) { spec.execute(getMetadataCopy()); } + /** + * Specifies prefixes that will be used to further filter files produced by the agent. + */ @Input + @Optional ListProperty getFilterableEntries(); /** 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 95e871b01..96e377b37 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 @@ -75,11 +75,17 @@ public DefaultGraalVmExtension(NamedDomainObjectContainer na getToolchainDetection().convention(true); nativeImages.configureEach(options -> options.getJavaLauncher().convention(defaultJavaLauncher)); getTestSupport().convention(true); - getAgent().getTasksToInstrumentPredicate().convention(t -> true); - getAgent().getDefaultMode().convention("standard"); - getAgent().getModes().getConditional().getParallel().convention(true); - getAgent().getMetadataCopy().getMergeWithExisting().convention(false); - getAgent().getFilterableEntries().convention(Arrays.asList("org.gradle.", "java.", "org.junit.")); + AgentOptions agentOpts = getAgent(); + agentOpts.getTasksToInstrumentPredicate().convention(t -> true); + agentOpts.getDefaultMode().convention("standard"); + agentOpts.getModes().getConditional().getParallel().convention(true); + agentOpts.getMetadataCopy().getMergeWithExisting().convention(false); + agentOpts.getFilterableEntries().convention(Arrays.asList("org.gradle.", "java.", "org.junit.")); + agentOpts.getBuiltinHeuristicFilter().convention(true); + agentOpts.getBuiltinCallerFilter().convention(true); + agentOpts.getEnableExperimentalPredefinedClasses().convention(false); + agentOpts.getEnableExperimentalUnsafeAllocationTracing().convention(true); + agentOpts.getTrackReflectionMetadata().convention(true); 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 3c1c45da5..277f175af 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 @@ -87,7 +87,14 @@ public static Provider getAgentConfiguration(Provider Date: Sun, 29 May 2022 01:55:30 +0200 Subject: [PATCH 10/10] Change default agent mode to conditional when using JavaLibraryPlugin --- .../java/org/graalvm/buildtools/gradle/NativeImagePlugin.java | 3 +++ .../org/graalvm/buildtools/gradle/dsl/agent/AgentOptions.java | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) 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 9b010a7c4..d70ed079b 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 @@ -88,6 +88,7 @@ import org.gradle.api.model.ObjectFactory; import org.gradle.api.plugins.ExtensionAware; import org.gradle.api.plugins.JavaApplication; +import org.gradle.api.plugins.JavaLibraryPlugin; import org.gradle.api.plugins.JavaPlugin; import org.gradle.api.plugins.JavaPluginConvention; import org.gradle.api.provider.ListProperty; @@ -173,6 +174,8 @@ public void apply(Project project) { project.getPlugins() .withType(JavaPlugin.class, javaPlugin -> configureJavaProject(project, nativeImageServiceProvider, graalExtension)); + project.getPlugins().withType(JavaLibraryPlugin.class, javaLibraryPlugin -> graalExtension.getAgent().getDefaultMode().convention("conditional")); + project.afterEvaluate(p -> instrumentTasksWithAgent(project, graalExtension)); } 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 473b47e24..590e5e274 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 @@ -47,6 +47,7 @@ import org.gradle.api.provider.Property; import org.gradle.api.tasks.Input; import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Internal; import org.gradle.api.tasks.Nested; import org.gradle.api.tasks.Optional; @@ -140,7 +141,7 @@ default void metadataCopy(Action spec) { * * @return Task predicate that accepts tasks during task configuration. */ - @Input + @Internal Property> getTasksToInstrumentPredicate(); }