|
43 | 43 |
|
44 | 44 | import org.graalvm.buildtools.VersionInfo; |
45 | 45 | import org.graalvm.buildtools.agent.AgentConfiguration; |
| 46 | +import org.graalvm.buildtools.agent.AgentMode; |
| 47 | +import org.graalvm.buildtools.agent.StandardAgentMode; |
46 | 48 | import org.graalvm.buildtools.gradle.dsl.GraalVMExtension; |
47 | 49 | import org.graalvm.buildtools.gradle.dsl.JvmReachabilityMetadataRepositoryExtension; |
48 | 50 | import org.graalvm.buildtools.gradle.dsl.NativeImageOptions; |
|
56 | 58 | import org.graalvm.buildtools.gradle.internal.GradleUtils; |
57 | 59 | import org.graalvm.buildtools.gradle.internal.JvmReachabilityMetadataService; |
58 | 60 | 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; |
60 | 63 | import org.graalvm.buildtools.gradle.internal.agent.AgentConfigurationFactory; |
61 | 64 | import org.graalvm.buildtools.gradle.tasks.BuildNativeImageTask; |
| 65 | +import org.graalvm.buildtools.gradle.tasks.CopyMetadataTask; |
62 | 66 | import org.graalvm.buildtools.gradle.tasks.GenerateResourcesConfigFile; |
63 | 67 | import org.graalvm.buildtools.gradle.tasks.NativeRunTask; |
| 68 | +import org.graalvm.buildtools.gradle.tasks.actions.MergeAgentFilesAction; |
64 | 69 | import org.graalvm.buildtools.utils.SharedConstants; |
65 | 70 | import org.gradle.api.Action; |
66 | 71 | import org.gradle.api.NamedDomainObjectContainer; |
|
92 | 97 | import org.gradle.api.tasks.OutputDirectory; |
93 | 98 | import org.gradle.api.tasks.SourceSet; |
94 | 99 | import org.gradle.api.tasks.SourceSetContainer; |
95 | | -import org.gradle.api.tasks.TaskCollection; |
96 | 100 | import org.gradle.api.tasks.TaskContainer; |
97 | 101 | import org.gradle.api.tasks.TaskProvider; |
98 | 102 | import org.gradle.api.tasks.bundling.AbstractArchiveTask; |
|
112 | 116 | import java.nio.file.Path; |
113 | 117 | import java.util.Arrays; |
114 | 118 | import java.util.Collections; |
| 119 | +import java.util.List; |
115 | 120 | import java.util.Locale; |
116 | 121 | import java.util.Map; |
117 | 122 | import java.util.Set; |
118 | | -import java.util.concurrent.Callable; |
119 | 123 | import java.util.function.Consumer; |
| 124 | +import java.util.function.Predicate; |
120 | 125 | import java.util.stream.Collectors; |
121 | 126 |
|
122 | 127 | import static org.graalvm.buildtools.gradle.internal.GradleUtils.transitiveProjectArtifacts; |
@@ -193,8 +198,18 @@ public void apply(Project project) { |
193 | 198 | private void instrumentTasksWithAgent(Project project, DefaultGraalVmExtension graalExtension) { |
194 | 199 | Provider<String> agentMode = agentProperty(project, graalExtension.getAgent()); |
195 | 200 | 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; |
198 | 213 | } |
199 | 214 |
|
200 | 215 | private static String deriveTaskName(String name, String prefix, String suffix) { |
@@ -236,6 +251,32 @@ private void configureJavaProject(Project project, Provider<NativeImageService> |
236 | 251 | config.forTestTask(tasks.named("test", Test.class)); |
237 | 252 | config.usingSourceSet(GradleUtils.findSourceSet(project, SourceSet.TEST_SOURCE_SET_NAME)); |
238 | 253 | }); |
| 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 | + }); |
239 | 280 | } |
240 | 281 |
|
241 | 282 | private void configureAutomaticTaskCreation(Project project, |
@@ -299,18 +340,18 @@ private void configureJvmReachabilityConfigurationDirectories(Project project, G |
299 | 340 | Set<String> excludedModules = repositoryExtension.getExcludedModules().getOrElse(Collections.emptySet()); |
300 | 341 | Map<String, String> forcedVersions = repositoryExtension.getModuleToConfigVersion().getOrElse(Collections.emptyMap()); |
301 | 342 | 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 | + }); |
309 | 352 | } |
310 | | - }); |
311 | | - } |
312 | | - query.useLatestConfigWhenVersionIsUntested(); |
313 | | - })).stream() |
| 353 | + query.useLatestConfigWhenVersionIsUntested(); |
| 354 | + })).stream() |
314 | 355 | .map(Path::toAbsolutePath) |
315 | 356 | .map(Path::toFile) |
316 | 357 | .collect(Collectors.toList())); |
@@ -463,6 +504,9 @@ public void registerTestBinary(Project project, |
463 | 504 | task.setOnlyIf(t -> graalExtension.getTestSupport().get()); |
464 | 505 | task.getTestListDirectory().set(testListDirectory); |
465 | 506 | testTask.get(); |
| 507 | + if (!agentProperty(project, graalExtension.getAgent()).get().equals("disabled")) { |
| 508 | + testOptions.getConfigurationFileDirectories().from(getProcessedAgentOutputFilesDirectory(project, testTask.get())); |
| 509 | + } |
466 | 510 | ConfigurableFileCollection testList = project.getObjects().fileCollection(); |
467 | 511 | // Later this will be replaced by a dedicated task not requiring execution of tests |
468 | 512 | testList.from(testListDirectory).builtBy(testTask); |
@@ -498,13 +542,6 @@ private static Provider<String> agentProperty(Project project, AgentOptions opti |
498 | 542 | .orElse(project.provider(() -> "disabled")); |
499 | 543 | } |
500 | 544 |
|
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 | | - |
508 | 545 | @SuppressWarnings("UnstableApiUsage") |
509 | 546 | private static void registerServiceProvider(Project project, Provider<NativeImageService> nativeImageServiceProvider) { |
510 | 547 | project.getTasks() |
@@ -590,31 +627,52 @@ private static String postProcessTaskName(String taskName) { |
590 | 627 | return PROCESS_AGENT_RESOURCES_TASK_NAME_PREFIX + capitalize(taskName) + PROCESS_AGENT_RESOURCES_TASK_NAME_SUFFIX; |
591 | 628 | } |
592 | 629 |
|
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 | + |
601 | 643 | AgentCommandLineProvider cliProvider = project.getObjects().newInstance(AgentCommandLineProvider.class); |
602 | 644 | 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); |
604 | 650 | cliProvider.getOutputDirectory().set(outputDir); |
605 | 651 | cliProvider.getAgentOptions().set(agentConfiguration.map(AgentConfiguration::getAgentCommandLine)); |
606 | 652 | javaForkOptions.getJvmArgumentProviders().add(cliProvider); |
607 | | - taskToInstrument.doLast(new MergeAgentFiles( |
608 | | - agentConfiguration, |
| 653 | + |
| 654 | + taskToInstrument.doLast(new MergeAgentFilesAction( |
| 655 | + isMergingEnabled, |
| 656 | + agentModeProvider, |
609 | 657 | project, |
610 | 658 | graalvmHomeProvider(project.getProviders()), |
611 | | - outputDir, |
| 659 | + mergeInputDirs, |
| 660 | + mergeOutputDirs, |
612 | 661 | disableToolchainDetection, |
613 | 662 | execOperations, |
614 | | - fileOperations, |
615 | 663 | 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); |
618 | 676 | } |
619 | 677 |
|
620 | 678 | private static void injectTestPluginDependencies(Project project, Property<Boolean> testSupportEnabled) { |
|
0 commit comments