added jdeps plugin
All checks were successful
CI / build (push) Successful in 2m26s

This commit is contained in:
2025-04-15 22:04:50 +08:00
parent 0d32fb5ba9
commit 3f6627465c
9 changed files with 321 additions and 12 deletions

View File

@@ -27,9 +27,6 @@ public class JlinkPlugin implements Plugin<Project> {
project.getPluginManager().apply(JavaLibraryPlugin.class);
ExtensionContainer extensionContainer = project.getExtensions();
BasePluginExtension basePluginExtension = extensionContainer.getByType(BasePluginExtension.class);
JavaApplication javaApplicationExtension =
Optional.ofNullable(extensionContainer.findByType(JavaApplication.class))
.orElseGet(() -> extensionContainer.create("application", JavaApplication.class));
TaskContainer tasks = project.getTasks();
Provider<JlinkTask> jlinTaskProvider = tasks.register(JLINK_TASK_NAME, JlinkTask.class, jlinkTask -> {

View File

@@ -1,6 +1,7 @@
package net.woggioni.gradle.graalvm;
import lombok.SneakyThrows;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.file.Directory;
import org.gradle.api.file.DirectoryProperty;
@@ -8,6 +9,7 @@ import org.gradle.api.file.FileCollection;
import org.gradle.api.file.ProjectLayout;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.model.ObjectFactory;
import org.gradle.api.plugins.BasePluginExtension;
import org.gradle.api.plugins.ExtensionContainer;
import org.gradle.api.plugins.JavaApplication;
@@ -25,6 +27,8 @@ import org.gradle.internal.jvm.JavaModuleDetector;
import org.gradle.jvm.toolchain.JavaInstallationMetadata;
import org.gradle.jvm.toolchain.JavaLauncher;
import org.gradle.jvm.toolchain.JavaToolchainService;
import org.gradle.jvm.toolchain.JavaToolchainSpec;
import org.gradle.jvm.toolchain.internal.DefaultToolchainSpec;
import org.gradle.process.CommandLineArgumentProvider;
import javax.inject.Inject;
@@ -42,6 +46,13 @@ import static net.woggioni.gradle.graalvm.Constants.GRAALVM_TASK_GROUP;
public abstract class JlinkTask extends Exec {
private final JavaToolchainSpec toolchain;
public JavaToolchainSpec toolchain(Action<? super JavaToolchainSpec> action) {
action.execute(toolchain);
return toolchain;
}
@Classpath
public abstract Property<FileCollection> getClasspath();
@@ -59,9 +70,24 @@ public abstract class JlinkTask extends Exec {
@Input
public abstract ListProperty<String> getAdditionalModules();
@Input
public abstract ListProperty<String> getLimitModules();
@Input
public abstract Property<Boolean> getBindServices();
@Input
public abstract Property<Boolean> getIncludeHeaderFiles();
@Input
public abstract Property<Boolean> getIncludeManPages();
@Input
public abstract Property<Boolean> getStripDebug();
@Input
public abstract Property<Boolean> getGenerateCdsArchive();
@Input
@Optional
public abstract Property<Integer> getCompressionLevel();
@@ -74,7 +100,8 @@ public abstract class JlinkTask extends Exec {
private static final Logger log = Logging.getLogger(JlinkTask.class);
public JlinkTask() {
@Inject
public JlinkTask(ObjectFactory objects) {
Project project = getProject();
setGroup(GRAALVM_TASK_GROUP);
setDescription(
@@ -86,17 +113,26 @@ public abstract class JlinkTask extends Exec {
getMainClass().convention(javaApplication.getMainClass());
getMainModule().convention(javaApplication.getMainModule());
}
getIncludeManPages().convention(false);
getIncludeHeaderFiles().convention(false);
getGenerateCdsArchive().convention(true);
getStripDebug().convention(true);
getClasspath().convention(project.files());
ProjectLayout layout = project.getLayout();
toolchain = getObjectFactory().newInstance(DefaultToolchainSpec.class);
JavaToolchainService javaToolchainService = ext.findByType(JavaToolchainService.class);
JavaPluginExtension javaPluginExtension = ext.findByType(JavaPluginExtension.class);
Provider<Directory> graalHomeDirectoryProvider = ofNullable(javaPluginExtension.getToolchain()).map(javaToolchainSpec ->
javaToolchainService.launcherFor(javaToolchainSpec)
).map(javaLauncher ->
javaLauncher.map(JavaLauncher::getMetadata).map(JavaInstallationMetadata::getInstallationPath)
).orElseGet(() -> layout.dir(project.provider(() ->project.file(System.getProperty("java.home")))));
Provider<Directory> graalHomeDirectoryProvider = javaToolchainService.launcherFor(it -> {
it.getLanguageVersion().set(toolchain.getLanguageVersion());
it.getVendor().set(toolchain.getVendor());
it.getImplementation().set(toolchain.getImplementation());
}).map(javaLauncher ->
javaLauncher.getMetadata().getInstallationPath()
).orElse(layout.dir(project.provider(() -> project.file(System.getProperty("java.home")))));
getGraalVmHome().convention(graalHomeDirectoryProvider);
getGraalVmHome().convention(graalHomeDirectoryProvider);
getAdditionalModules().convention(new ArrayList<>());
getLimitModules().convention(new ArrayList<>());
getBindServices().convention(false);
BasePluginExtension basePluginExtension =
@@ -118,7 +154,7 @@ public abstract class JlinkTask extends Exec {
@SneakyThrows
public Iterable<String> asArguments() {
List<String> result = new ArrayList<>();
final Property<Integer> compressionLevelProperty= getCompressionLevel();
final Property<Integer> compressionLevelProperty = getCompressionLevel();
if(compressionLevelProperty.isPresent()) {
result.add(String.format("--compress=zip-%d", compressionLevelProperty.get()));
}
@@ -152,6 +188,28 @@ public abstract class JlinkTask extends Exec {
result.add(String.join(",", modules2BeAdded));
}
}
List<String> limitModules = getLimitModules().get();
if(!limitModules.isEmpty()) {
result.add("--limit-modules");
final List<String> modules2BeAdded = new ArrayList<>();
modules2BeAdded.addAll(limitModules);
if(!modules2BeAdded.isEmpty()) {
result.add(String.join(",", modules2BeAdded));
}
}
if(getStripDebug().getOrElse(false)) {
result.add("--strip-debug");
}
if(getGenerateCdsArchive().getOrElse(false)) {
result.add("--generate-cds-archive");
}
if(!getIncludeHeaderFiles().getOrElse(true)) {
result.add("--no-header-files");
}
if(!getIncludeManPages().getOrElse(true)) {
result.add("--no-man-pages");
}
return Collections.unmodifiableList(result);
}
};

View File

@@ -1,5 +1,5 @@
lys.catalog.version=2025.02.05
version.myGradlePlugins=2025.04.15
version.myGradlePlugins=2025.04.16
version.gradle=8.12
gitea.maven.url = https://gitea.woggioni.net/api/packages/woggioni/maven

13
jdeps/build.gradle Normal file
View File

@@ -0,0 +1,13 @@
plugins {
id 'java-gradle-plugin'
}
gradlePlugin {
plugins {
create("JdepsPlugin") {
id = 'net.woggioni.gradle.jdeps'
implementationClass = "net.woggioni.gradle.jdeps.JdepsPlugin"
}
}
}

View File

@@ -0,0 +1,5 @@
package net.woggioni.gradle.jdeps;
public class Constants {
public static final String JDEPS_TASK_GROUP = "jdeps";
}

View File

@@ -0,0 +1,26 @@
package net.woggioni.gradle.jdeps;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.file.FileCollection;
import org.gradle.api.plugins.JavaLibraryPlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.TaskContainer;
public class JdepsPlugin implements Plugin<Project> {
public static final String JDEPS_TASK_NAME = "jdeps";
@Override
public void apply(Project project) {
project.getPluginManager().apply(JavaLibraryPlugin.class);
TaskContainer tasks = project.getTasks();
Provider<JdepsTask> jdepsTaskProvider = tasks.register(JDEPS_TASK_NAME, JdepsTask.class, jdepsTask -> {
ConfigurationContainer configurations = project.getConfigurations();
FileCollection classpath = project.files(configurations.getByName(JavaPlugin.RUNTIME_CLASSPATH_CONFIGURATION_NAME));
jdepsTask.getClasspath().set(classpath);
jdepsTask.getArchives().set(project.files(tasks.named(JavaPlugin.JAR_TASK_NAME)));
});
}
}

View File

@@ -0,0 +1,209 @@
package net.woggioni.gradle.jdeps;
import lombok.SneakyThrows;
import org.gradle.api.Action;
import org.gradle.api.Project;
import org.gradle.api.file.Directory;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.ProjectLayout;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.plugins.BasePluginExtension;
import org.gradle.api.plugins.ExtensionContainer;
import org.gradle.api.plugins.JavaApplication;
import org.gradle.api.provider.ListProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.Provider;
import org.gradle.api.reporting.ReportingExtension;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.Exec;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.internal.jvm.JavaModuleDetector;
import org.gradle.jvm.toolchain.JavaToolchainService;
import org.gradle.jvm.toolchain.JavaToolchainSpec;
import org.gradle.jvm.toolchain.internal.DefaultToolchainSpec;
import org.gradle.process.CommandLineArgumentProvider;
import javax.inject.Inject;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import static java.util.Optional.ofNullable;
import static net.woggioni.gradle.jdeps.Constants.JDEPS_TASK_GROUP;
public abstract class JdepsTask extends Exec {
private final JavaToolchainSpec toolchain;
public JavaToolchainSpec toolchain(Action<? super JavaToolchainSpec> action) {
action.execute(toolchain);
return toolchain;
}
@Classpath
public abstract Property<FileCollection> getClasspath();
@Classpath
public abstract Property<FileCollection> getArchives();
@InputDirectory
public abstract DirectoryProperty getJavaHome();
@Input
@Optional
public abstract Property<String> getMainClass();
@Input
@Optional
public abstract Property<String> getMainModule();
@Input
public abstract ListProperty<String> getAdditionalModules();
@Inject
protected abstract JavaModuleDetector getJavaModuleDetector();
@OutputDirectory
public abstract DirectoryProperty getOutputDir();
@Optional
@OutputDirectory
public abstract DirectoryProperty getDotOutput();
@Input
@Optional
public abstract Property<Integer> getJavaRelease();
@Input
public abstract Property<Boolean> getRecursive();
private static final Logger log = Logging.getLogger(JdepsTask.class);
public JdepsTask() {
Project project = getProject();
setGroup(JDEPS_TASK_GROUP);
setDescription(
"Generates a custom Java runtime image that contains only the platform modules" +
" that are required for a given application");
ExtensionContainer ext = project.getExtensions();
JavaApplication javaApplication = ext.findByType(JavaApplication.class);
if (!Objects.isNull(javaApplication)) {
getMainClass().convention(javaApplication.getMainClass());
getMainModule().convention(javaApplication.getMainModule());
}
getClasspath().convention(project.files());
getRecursive().convention(true);
ProjectLayout layout = project.getLayout();
toolchain = getObjectFactory().newInstance(DefaultToolchainSpec.class);
JavaToolchainService javaToolchainService = ext.findByType(JavaToolchainService.class);
Provider<Directory> graalHomeDirectoryProvider = javaToolchainService.launcherFor(it -> {
it.getLanguageVersion().set(toolchain.getLanguageVersion());
it.getVendor().set(toolchain.getVendor());
it.getImplementation().set(toolchain.getImplementation());
}).map(javaLauncher ->
javaLauncher.getMetadata().getInstallationPath()
).orElse(layout.dir(project.provider(() -> project.file(System.getProperty("java.home")))));
getJavaHome().convention(graalHomeDirectoryProvider);
getJavaHome().convention(graalHomeDirectoryProvider);
getAdditionalModules().convention(new ArrayList<>());
ReportingExtension reporting = ext.getByType(ReportingExtension.class);
getOutputDir().convention(
reporting.getBaseDirectory()
.dir(project.getName() +
ofNullable(project.getVersion()).map(it -> "-" + it).orElse(""))
);
getDotOutput().convention(getOutputDir().dir("graphviz"));
Object executableProvider = new Object() {
@Override
public String toString() {
return getJavaHome().get() + "/bin/jdeps";
}
};
executable(executableProvider);
CommandLineArgumentProvider argumentProvider = new CommandLineArgumentProvider() {
@Override
@SneakyThrows
public Iterable<String> asArguments() {
List<String> result = new ArrayList<>();
JavaModuleDetector javaModuleDetector = getJavaModuleDetector();
FileCollection classpath = getClasspath().get();
FileCollection mp = javaModuleDetector.inferModulePath(true, classpath);
if (!mp.isEmpty()) {
result.add("--module-path");
result.add(mp.getAsPath());
}
FileCollection cp = classpath.minus(mp);
if(!cp.isEmpty()) {
result.add("-cp");
result.add(cp.getAsPath());
}
List<String> additionalModules = getAdditionalModules().get();
if (!additionalModules.isEmpty()) {
result.add("--add-modules");
final List<String> modules2BeAdded = new ArrayList<>();
modules2BeAdded.addAll(additionalModules);
if (!modules2BeAdded.isEmpty()) {
result.add(String.join(",", modules2BeAdded));
}
}
if (getDotOutput().isPresent()) {
result.add("-dotoutput");
result.add(getDotOutput().get().getAsFile().toString());
}
if(getRecursive().get()) {
result.add("--recursive");
} else {
result.add("--no-recursive");
}
if (getMainModule().isPresent()) {
result.add("-m");
result.add(getMainModule().get());
}
if (getJavaRelease().isPresent()) {
result.add("--multi-release");
result.add(getJavaRelease().get().toString());
}
for (File archive : getArchives().get()) {
result.add(archive.toString());
}
return Collections.unmodifiableList(result);
}
};
getArgumentProviders().add(argumentProvider);
}
@Override
@SneakyThrows
protected void exec() {
Files.walk(getOutputDir().get().getAsFile().toPath())
.sorted(Comparator.reverseOrder())
.forEach(new Consumer<Path>() {
@Override
@SneakyThrows
public void accept(Path path) {
Files.delete(path);
}
});
super.exec();
}
}

View File

@@ -27,3 +27,4 @@ include 'osgi-app:osgi-simple-bootstrapper-application'
include 'wildfly'
include 'sambal'
include 'graalvm'
include 'jdeps'