Skip to content

Commit ecff683

Browse files
author
Aleksandar Gradinac
committed
WIP
1 parent e2e54c4 commit ecff683

File tree

13 files changed

+424
-136
lines changed

13 files changed

+424
-136
lines changed

common/utils/src/main/java/org/graalvm/buildtools/agent/AgentConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ public static void appendOptionToValues(String option, List<String> values, List
7171
values.stream().map(value -> option + value).forEach(target::add);
7272
}
7373

74-
public List<String> getNativeImageConfigureOptions(List<String> inputDirectories, List<String> outputDirectories) {
75-
return agentMode.getNativeImageConfigureOptions(inputDirectories, outputDirectories);
74+
public AgentMode getAgentMode() {
75+
return agentMode;
7676
}
7777
}

native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/NativeImagePlugin.java

Lines changed: 96 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@
4343

4444
import org.graalvm.buildtools.VersionInfo;
4545
import org.graalvm.buildtools.agent.AgentConfiguration;
46+
import org.graalvm.buildtools.agent.AgentMode;
47+
import org.graalvm.buildtools.agent.StandardAgentMode;
4648
import org.graalvm.buildtools.gradle.dsl.GraalVMExtension;
4749
import org.graalvm.buildtools.gradle.dsl.JvmReachabilityMetadataRepositoryExtension;
4850
import org.graalvm.buildtools.gradle.dsl.NativeImageOptions;
@@ -56,11 +58,14 @@
5658
import org.graalvm.buildtools.gradle.internal.GradleUtils;
5759
import org.graalvm.buildtools.gradle.internal.JvmReachabilityMetadataService;
5860
import org.graalvm.buildtools.gradle.internal.NativeConfigurations;
59-
import org.graalvm.buildtools.gradle.internal.ProcessGeneratedGraalResourceFiles;
61+
import org.graalvm.buildtools.gradle.tasks.actions.CleanupAgentFilesAction;
62+
import org.graalvm.buildtools.gradle.tasks.actions.ProcessGeneratedGraalResourceFilesAction;
6063
import org.graalvm.buildtools.gradle.internal.agent.AgentConfigurationFactory;
6164
import org.graalvm.buildtools.gradle.tasks.BuildNativeImageTask;
65+
import org.graalvm.buildtools.gradle.tasks.CopyMetadataTask;
6266
import org.graalvm.buildtools.gradle.tasks.GenerateResourcesConfigFile;
6367
import org.graalvm.buildtools.gradle.tasks.NativeRunTask;
68+
import org.graalvm.buildtools.gradle.tasks.actions.MergeAgentFilesAction;
6469
import org.graalvm.buildtools.utils.SharedConstants;
6570
import org.gradle.api.Action;
6671
import org.gradle.api.NamedDomainObjectContainer;
@@ -92,7 +97,6 @@
9297
import org.gradle.api.tasks.OutputDirectory;
9398
import org.gradle.api.tasks.SourceSet;
9499
import org.gradle.api.tasks.SourceSetContainer;
95-
import org.gradle.api.tasks.TaskCollection;
96100
import org.gradle.api.tasks.TaskContainer;
97101
import org.gradle.api.tasks.TaskProvider;
98102
import org.gradle.api.tasks.bundling.AbstractArchiveTask;
@@ -112,11 +116,12 @@
112116
import java.nio.file.Path;
113117
import java.util.Arrays;
114118
import java.util.Collections;
119+
import java.util.List;
115120
import java.util.Locale;
116121
import java.util.Map;
117122
import java.util.Set;
118-
import java.util.concurrent.Callable;
119123
import java.util.function.Consumer;
124+
import java.util.function.Predicate;
120125
import java.util.stream.Collectors;
121126

122127
import static org.graalvm.buildtools.gradle.internal.GradleUtils.transitiveProjectArtifacts;
@@ -193,8 +198,18 @@ public void apply(Project project) {
193198
private void instrumentTasksWithAgent(Project project, DefaultGraalVmExtension graalExtension) {
194199
Provider<String> agentMode = agentProperty(project, graalExtension.getAgent());
195200
Provider<AgentConfiguration> agentConfiguration = AgentConfigurationFactory.getAgentConfiguration(agentMode, graalExtension.getAgent());
196-
TaskCollection<? extends JavaForkOptions> tasksToInstrument = graalExtension.getAgent().getInstrumentedTasks().get();
197-
tasksToInstrument.configureEach(t -> configureAgent(project, agentConfiguration, graalExtension.getToolchainDetection(), getExecOperations(), getFileOperations(), t, t));
201+
Predicate<? super Task> taskPredicate = graalExtension.getAgent().getTasksToInstrumentPredicate().get();
202+
project.getTasks().configureEach(t -> {
203+
if (isTaskInstrumentableByAgent(t) && taskPredicate.test(t)) {
204+
configureAgent(project, agentConfiguration, graalExtension.getToolchainDetection(), getExecOperations(), getFileOperations(), t, (JavaForkOptions) t);
205+
} else {
206+
logger.lifecycle("Skipping task: " + t.getName());
207+
}
208+
});
209+
}
210+
211+
private static boolean isTaskInstrumentableByAgent(Task task) {
212+
return task instanceof JavaForkOptions;
198213
}
199214

200215
private static String deriveTaskName(String name, String prefix, String suffix) {
@@ -236,6 +251,32 @@ private void configureJavaProject(Project project, Provider<NativeImageService>
236251
config.forTestTask(tasks.named("test", Test.class));
237252
config.usingSourceSet(GradleUtils.findSourceSet(project, SourceSet.TEST_SOURCE_SET_NAME));
238253
});
254+
255+
TaskProvider<CopyMetadataTask> copyMetadataTask = project.getTasks().register("copyMetadata", CopyMetadataTask.class, task -> {
256+
task.setGroup(LifecycleBasePlugin.BUILD_GROUP);
257+
task.setDescription("Copies metadata collected from tasks instrumented with the agent into target directories.");
258+
task.getInputTaskNames().set(graalExtension.getCopyMetadata().getInputTaskNames());
259+
task.getOutputDirectories().set(graalExtension.getCopyMetadata().getOutputDirectories());
260+
Provider<Boolean> isMergeEnabled = project.provider(() -> true);
261+
Provider<AgentMode> agentModeProvider = project.provider(StandardAgentMode::new);
262+
263+
Provider<List<String>> inputDirectories = task.getInputTaskNames().map(list ->
264+
list.stream()
265+
.map(taskName -> AgentConfigurationFactory.getAgentOutputDirectoryForTask(project, taskName))
266+
.map(dir -> dir.get().getAsFile().getAbsolutePath())
267+
.collect(Collectors.toList()));
268+
269+
task.doLast(new MergeAgentFilesAction(
270+
isMergeEnabled,
271+
agentModeProvider,
272+
project,
273+
graalvmHomeProvider(project.getProviders()),
274+
inputDirectories,
275+
task.getOutputDirectories(),
276+
graalExtension.getToolchainDetection(),
277+
getExecOperations(),
278+
task.getLogger()));
279+
});
239280
}
240281

241282
private void configureAutomaticTaskCreation(Project project,
@@ -299,18 +340,18 @@ private void configureJvmReachabilityConfigurationDirectories(Project project, G
299340
Set<String> excludedModules = repositoryExtension.getExcludedModules().getOrElse(Collections.emptySet());
300341
Map<String, String> forcedVersions = repositoryExtension.getModuleToConfigVersion().getOrElse(Collections.emptyMap());
301342
return serviceProvider.map(repo -> repo.findConfigurationDirectoriesFor(query -> classpath.getIncoming().getResolutionResult().allComponents(component -> {
302-
ModuleVersionIdentifier moduleVersion = component.getModuleVersion();
303-
String module = moduleVersion.getGroup() + ":" + moduleVersion.getName();
304-
if (!excludedModules.contains(module)) {
305-
query.forArtifact(artifact -> {
306-
artifact.gav(module + ":" + moduleVersion.getVersion());
307-
if (forcedVersions.containsKey(module)) {
308-
artifact.forceConfigVersion(forcedVersions.get(module));
343+
ModuleVersionIdentifier moduleVersion = component.getModuleVersion();
344+
String module = moduleVersion.getGroup() + ":" + moduleVersion.getName();
345+
if (!excludedModules.contains(module)) {
346+
query.forArtifact(artifact -> {
347+
artifact.gav(module + ":" + moduleVersion.getVersion());
348+
if (forcedVersions.containsKey(module)) {
349+
artifact.forceConfigVersion(forcedVersions.get(module));
350+
}
351+
});
309352
}
310-
});
311-
}
312-
query.useLatestConfigWhenVersionIsUntested();
313-
})).stream()
353+
query.useLatestConfigWhenVersionIsUntested();
354+
})).stream()
314355
.map(Path::toAbsolutePath)
315356
.map(Path::toFile)
316357
.collect(Collectors.toList()));
@@ -463,6 +504,9 @@ public void registerTestBinary(Project project,
463504
task.setOnlyIf(t -> graalExtension.getTestSupport().get());
464505
task.getTestListDirectory().set(testListDirectory);
465506
testTask.get();
507+
if (!agentProperty(project, graalExtension.getAgent()).get().equals("disabled")) {
508+
testOptions.getConfigurationFileDirectories().from(getProcessedAgentOutputFilesDirectory(project, testTask.get()));
509+
}
466510
ConfigurableFileCollection testList = project.getObjects().fileCollection();
467511
// Later this will be replaced by a dedicated task not requiring execution of tests
468512
testList.from(testListDirectory).builtBy(testTask);
@@ -498,13 +542,6 @@ private static Provider<String> agentProperty(Project project, AgentOptions opti
498542
.orElse(project.provider(() -> "disabled"));
499543
}
500544

501-
private static TaskProvider<ProcessGeneratedGraalResourceFiles> registerProcessAgentFilesTask(Project project, String name) {
502-
return project.getTasks().register(name, ProcessGeneratedGraalResourceFiles.class, task -> {
503-
task.getFilterableEntries().convention(Arrays.asList("org.gradle.", "java."));
504-
task.getOutputDirectory().convention(project.getLayout().getBuildDirectory().dir("native/processed/agent/" + name));
505-
});
506-
}
507-
508545
@SuppressWarnings("UnstableApiUsage")
509546
private static void registerServiceProvider(Project project, Provider<NativeImageService> nativeImageServiceProvider) {
510547
project.getTasks()
@@ -590,31 +627,52 @@ private static String postProcessTaskName(String taskName) {
590627
return PROCESS_AGENT_RESOURCES_TASK_NAME_PREFIX + capitalize(taskName) + PROCESS_AGENT_RESOURCES_TASK_NAME_SUFFIX;
591628
}
592629

593-
private static void configureAgent(Project project,
594-
Provider<AgentConfiguration> agentConfiguration,
595-
Provider<Boolean> disableToolchainDetection,
596-
ExecOperations execOperations,
597-
FileSystemOperations fileOperations,
598-
Task taskToInstrument,
599-
JavaForkOptions javaForkOptions) {
600-
TaskProvider<ProcessGeneratedGraalResourceFiles> postProcessingTask = registerProcessAgentFilesTask(project, postProcessTaskName(taskToInstrument.getName()));
630+
private static List<String> agentSessionDirectories(Directory outputDirectory) {
631+
return Arrays.stream(outputDirectory.getAsFile().listFiles(file -> file.isDirectory() && file.getName().startsWith("session-"))).map(File::getAbsolutePath).collect(Collectors.toList());
632+
}
633+
634+
private void configureAgent(Project project,
635+
Provider<AgentConfiguration> agentConfiguration,
636+
Provider<Boolean> disableToolchainDetection,
637+
ExecOperations execOperations,
638+
FileSystemOperations fileOperations,
639+
Task taskToInstrument,
640+
JavaForkOptions javaForkOptions) {
641+
logger.lifecycle("Instrumenting task: " + taskToInstrument.getName());
642+
601643
AgentCommandLineProvider cliProvider = project.getObjects().newInstance(AgentCommandLineProvider.class);
602644
cliProvider.getEnabled().set(agentConfiguration.map(AgentConfiguration::isEnabled));
603-
Provider<Directory> outputDir = project.getLayout().getBuildDirectory().dir(AGENT_OUTPUT_FOLDER + "/" + taskToInstrument.getName());
645+
Provider<Directory> outputDir = AgentConfigurationFactory.getAgentOutputDirectoryForTask(project, taskToInstrument.getName());
646+
Provider<Boolean> isMergingEnabled = agentConfiguration.map(AgentConfiguration::isEnabled);
647+
Provider<AgentMode> agentModeProvider = agentConfiguration.map(AgentConfiguration::getAgentMode);
648+
Provider<List<String>> mergeOutputDirs = outputDir.map(dir -> Collections.singletonList(dir.getAsFile().getAbsolutePath()));
649+
Provider<List<String>> mergeInputDirs = outputDir.map(NativeImagePlugin::agentSessionDirectories);
604650
cliProvider.getOutputDirectory().set(outputDir);
605651
cliProvider.getAgentOptions().set(agentConfiguration.map(AgentConfiguration::getAgentCommandLine));
606652
javaForkOptions.getJvmArgumentProviders().add(cliProvider);
607-
taskToInstrument.doLast(new MergeAgentFiles(
608-
agentConfiguration,
653+
654+
taskToInstrument.doLast(new MergeAgentFilesAction(
655+
isMergingEnabled,
656+
agentModeProvider,
609657
project,
610658
graalvmHomeProvider(project.getProviders()),
611-
outputDir,
659+
mergeInputDirs,
660+
mergeOutputDirs,
612661
disableToolchainDetection,
613662
execOperations,
614-
fileOperations,
615663
project.getLogger()));
616-
// Gradle won't let us configure from configure so we have to eagerly create the post-processing task :(
617-
postProcessingTask.get().getGeneratedFilesDir().set(outputDir);
664+
taskToInstrument.doLast(new CleanupAgentFilesAction(mergeInputDirs, fileOperations));
665+
666+
Provider<Directory> processedOutputDirectory = getProcessedAgentOutputFilesDirectory(project, taskToInstrument);
667+
taskToInstrument.doLast(new ProcessGeneratedGraalResourceFilesAction(
668+
outputDir,
669+
processedOutputDirectory,
670+
Arrays.asList("org.gradle.", "java.", "org.junit.")));
671+
}
672+
673+
private static Provider<Directory> getProcessedAgentOutputFilesDirectory(Project project, Task taskToInstrument) {
674+
String name = postProcessTaskName(taskToInstrument.getName());
675+
return project.getLayout().getBuildDirectory().dir("native/processed/agent/" + name);
618676
}
619677

620678
private static void injectTestPluginDependencies(Project project, Property<Boolean> testSupportEnabled) {

native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/GraalVMExtension.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
package org.graalvm.buildtools.gradle.dsl;
4343

4444
import org.graalvm.buildtools.gradle.dsl.agent.AgentOptions;
45+
import org.graalvm.buildtools.gradle.dsl.agent.CopyMetadataOptions;
4546
import org.gradle.api.Action;
4647
import org.gradle.api.NamedDomainObjectContainer;
4748
import org.gradle.api.file.DirectoryProperty;
@@ -69,6 +70,9 @@ public interface GraalVMExtension {
6970
@Nested
7071
AgentOptions getAgent();
7172

73+
@Nested
74+
CopyMetadataOptions getCopyMetadata();
75+
7276
void agent(Action<? super AgentOptions> spec);
7377

7478
DirectoryProperty getGeneratedResourcesDirectory();

native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/dsl/agent/AgentOptions.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
package org.graalvm.buildtools.gradle.dsl.agent;
4242

4343
import org.gradle.api.Action;
44+
import org.gradle.api.Task;
4445
import org.gradle.api.provider.ListProperty;
4546
import org.gradle.api.provider.Property;
4647
import org.gradle.api.provider.SetProperty;
@@ -52,6 +53,8 @@
5253
import org.gradle.api.tasks.TaskProvider;
5354
import org.gradle.process.JavaForkOptions;
5455

56+
import java.util.function.Predicate;
57+
5558
@SuppressWarnings({"unused"})
5659
public interface AgentOptions {
5760
@Nested
@@ -74,11 +77,10 @@ default void modes(Action<? super AgentModeOptions> spec) {
7477
ListProperty<String> getAccessFilterFiles();
7578

7679
/**
77-
* Configures the task which needs to be instrumented.
78-
*
79-
* @return the instrumented task.
80+
* Configures the tasks which needs to be instrumented
81+
* @return .
8082
*/
8183
@Input
82-
Property<TaskCollection<? extends JavaForkOptions>> getInstrumentedTasks();
84+
Property<Predicate<? super Task>> getTasksToInstrumentPredicate();
8385

8486
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
package org.graalvm.buildtools.gradle.dsl.agent;
42+
43+
import org.gradle.api.provider.ListProperty;
44+
import org.gradle.api.tasks.Input;
45+
import org.gradle.api.tasks.Optional;
46+
47+
public interface CopyMetadataOptions {
48+
49+
@Input
50+
@Optional
51+
ListProperty<String> getInputTaskNames();
52+
53+
@Input
54+
@Optional
55+
ListProperty<String> getOutputDirectories();
56+
57+
}

native-gradle-plugin/src/main/java/org/graalvm/buildtools/gradle/internal/DefaultGraalVmExtension.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@
5454
import org.gradle.jvm.toolchain.JavaLauncher;
5555
import org.gradle.jvm.toolchain.JavaToolchainService;
5656
import org.gradle.jvm.toolchain.JvmVendorSpec;
57-
import org.gradle.process.JavaForkOptions;
5857

5958
import javax.inject.Inject;
6059

@@ -64,12 +63,6 @@ public abstract class DefaultGraalVmExtension implements GraalVMExtension {
6463
private final Project project;
6564
private final Property<JavaLauncher> defaultJavaLauncher;
6665

67-
@SuppressWarnings("unchecked")
68-
/* javac forced our hand */
69-
private static <T, U> T iPromiseIKnowWhatImDoing(U u) {
70-
return (T) u;
71-
}
72-
7366
@Inject
7467
public DefaultGraalVmExtension(NamedDomainObjectContainer<NativeImageOptions> nativeImages,
7568
NativeImagePlugin plugin,
@@ -81,8 +74,7 @@ public DefaultGraalVmExtension(NamedDomainObjectContainer<NativeImageOptions> na
8174
getToolchainDetection().convention(true);
8275
nativeImages.configureEach(options -> options.getJavaLauncher().convention(defaultJavaLauncher));
8376
getTestSupport().convention(true);
84-
/* Can't use withType here because JavaForkOptions is not a subtype of Task */
85-
getAgent().getInstrumentedTasks().convention(project.provider(() -> iPromiseIKnowWhatImDoing(project.getTasks().matching(t -> t instanceof JavaForkOptions))));
77+
getAgent().getTasksToInstrumentPredicate().convention(t -> true);
8678
getAgent().getDefaultMode().convention("standard");
8779
getAgent().getModes().getConditional().getParallel().convention(true);
8880
configureToolchain();

0 commit comments

Comments
 (0)