diff --git a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JDepsExtension.java b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JDepsExtension.java new file mode 100644 index 0000000..eba7c14 --- /dev/null +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JDepsExtension.java @@ -0,0 +1,4 @@ +package org.xbib.gradle.plugin.jlink; + +public class JDepsExtension { +} diff --git a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkPlugin.java b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkPlugin.java index ba0e561..6567232 100644 --- a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkPlugin.java +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkPlugin.java @@ -42,6 +42,8 @@ public abstract class JLinkPlugin implements Plugin { jModExtension.getCompress().convention(6); // zip-6, default jModExtension.getCmds().unsetConvention(); jModExtension.getConfigs().unsetConvention(); + jModExtension.getHeaderFiles().unsetConvention(); + jModExtension.getLibs().unsetConvention(); JLinkExtension jLinkExtension = project.getExtensions().create("jlink", JLinkExtension.class); jLinkExtension.getJavaCompiler().convention(service.compilerFor(toolchain)); @@ -60,7 +62,7 @@ public abstract class JLinkPlugin implements Plugin { jLinkExtension.getAddModules().convention(List.of("java.base")); jLinkExtension.getLimitModules().convention(List.of()); jLinkExtension.getBindServices().convention(false); - jLinkExtension.getLauncher().unsetConvention(); + jLinkExtension.getLauncher().convention(project.getName()); jLinkExtension.getCompress().convention(6); // zip-6, default jLinkExtension.getStripDebug().convention(true); // same as jpackage default jLinkExtension.getStripNativeCommands().convention(false); // keep commands @@ -75,8 +77,14 @@ public abstract class JLinkPlugin implements Plugin { jPackageExtension.getModule().unsetConvention(); jPackageExtension.getInput().convention(project.getLayout().getBuildDirectory().dir("jlink")); jPackageExtension.getType().convention("rpm"); // Fedora/Red Hat Linux + jPackageExtension.getjLinkOptions().convention(List.of("--strip-native-commands", "--strip-debug", "--no-man-pages", "--no-header-files")); // same as jpackage default jPackageExtension.getAppName().convention(project.getName()); jPackageExtension.getAppVersion().convention(project.getVersion().toString()); + jPackageExtension.getAppVendor().unsetConvention(); + jPackageExtension.getAppCopyright().unsetConvention(); + jPackageExtension.getAppDescription().unsetConvention(); + jPackageExtension.getAppIcon().unsetConvention(); + jPackageExtension.getAppImage().unsetConvention(); // install the jmod task TaskProvider jModTask = project.getTasks().register("jmod", JModTask.class); @@ -90,6 +98,8 @@ public abstract class JLinkPlugin implements Plugin { it.compress.set(jModExtension.getCompress()); it.cmds.set(jModExtension.getCmds()); it.configs.set(jModExtension.getConfigs()); + it.headerFiles.set(jModExtension.getHeaderFiles()); + it.libs.set(jModExtension.getLibs()); }); // install the jdeps task @@ -120,6 +130,7 @@ public abstract class JLinkPlugin implements Plugin { it.noManPages.set(jLinkExtension.getNoManPages()); it.endian.set(jLinkExtension.getEndian()); }); + // depend jpackage on jlink task TaskProvider jPackageTask = project.getTasks().register("jpackage", JPackageTask.class); project.getTasks().withType(JPackageTask.class).forEach(it -> { @@ -132,9 +143,24 @@ public abstract class JLinkPlugin implements Plugin { it.module.set(jPackageExtension.getModule()); it.input.set(jPackageExtension.getInput()); it.type.set(jPackageExtension.getType()); + it.jLinkOptions.set(jPackageExtension.getjLinkOptions()); it.appName.set(jPackageExtension.getAppName()); it.appVersion.set(jPackageExtension.getAppVersion()); + it.appCopyright.set(jPackageExtension.getAppCopyright()); + it.appVendor.set(jPackageExtension.getAppVendor()); + it.appDescription.set(jPackageExtension.getAppDescription()); + it.appIcon.set(jPackageExtension.getAppIcon()); + it.appImage.set(jPackageExtension.getAppImage()); }); + + TaskProvider jRunTask = project.getTasks().register("jrun", JRunTask.class); + project.getTasks().withType(JRunTask.class).forEach(it -> { + it.setGroup("run"); + it.dependsOn(jLinkTask); + it.exec.set(jLinkExtension.getjLinkOutputDirectory().file("bin/" + + prefix("=", jLinkExtension.getLauncher().get()))); + }); + Configuration jLinkConfiguration = project.getConfigurations().create("jlink"); jLinkConfiguration.setCanBeConsumed(true); jLinkConfiguration.setCanBeResolved(false); @@ -150,4 +176,9 @@ public abstract class JLinkPlugin implements Plugin { project.getObjects().named(Usage.class, "jpackage"))); jPackageConfiguration.outgoing(o -> o.artifact(jPackageTask.flatMap(t -> t.jPackageOutputDirectory))); } + + private static String prefix(String delimiter, String string) { + String[] s = string.split(delimiter); + return s.length > 0 ? s[0] : string; + } } diff --git a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JModExtension.java b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JModExtension.java index 88ff873..f8f43b3 100644 --- a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JModExtension.java +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JModExtension.java @@ -5,6 +5,8 @@ import org.gradle.api.file.Directory; 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.Optional; import java.util.List; @@ -20,12 +22,18 @@ public class JModExtension { private final ListProperty configs; + private final ListProperty headerFiles; + + private final ListProperty libs; + public JModExtension(Project project) { jModDirectory = project.getObjects().directoryProperty(); moduleVersion = project.getObjects().property(String.class); compress = project.getObjects().property(Integer.class); cmds = project.getObjects().listProperty(String.class); configs = project.getObjects().listProperty(String.class); + headerFiles = project.getObjects().listProperty(String.class); + libs = project.getObjects().listProperty(String.class); } public void setjModDirectory(Directory jModDirectory) { @@ -67,4 +75,20 @@ public class JModExtension { public ListProperty getConfigs() { return configs; } + + public void setHeaderFiles(List headerFiles) { + this.headerFiles.set(headerFiles); + } + + public ListProperty getHeaderFiles() { + return headerFiles; + } + + public void setLibs(List libs) { + this.libs.set(libs); + } + + public ListProperty getLibs() { + return libs; + } } diff --git a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageExtension.java b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageExtension.java index 2d60aaa..77112e7 100644 --- a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageExtension.java +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageExtension.java @@ -6,6 +6,8 @@ import org.gradle.api.file.Directory; 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.Optional; import org.gradle.jvm.toolchain.JavaCompiler; public class JPackageExtension { @@ -20,18 +22,36 @@ public class JPackageExtension { private final Property type; + private final ListProperty jLinkOptions; + private final Property appName; private final Property appVersion; + private final Property appCopyright; + + private final Property appVendor; + + private final Property appDescription; + + private final Property appIcon; + + private final DirectoryProperty appImage; + public JPackageExtension(Project project) { jPackageOutputDirectory = project.getObjects().directoryProperty(); addModules = project.getObjects().listProperty(String.class); module = project.getObjects().property(String.class); input = project.getObjects().directoryProperty(); type = project.getObjects().property(String.class); + jLinkOptions = project.getObjects().listProperty(String.class); appName = project.getObjects().property(String.class); appVersion = project.getObjects().property(String.class); + appCopyright = project.getObjects().property(String.class); + appVendor = project.getObjects().property(String.class); + appDescription = project.getObjects().property(String.class); + appIcon = project.getObjects().property(String.class); + appImage = project.getObjects().directoryProperty(); } public void setjPackageOutputDirectory(Directory jPackageOutputDirectory) { @@ -74,6 +94,14 @@ public class JPackageExtension { return type; } + public void setjLinkOptions(List jLinkOptions) { + this.jLinkOptions.set(jLinkOptions); + } + + public ListProperty getjLinkOptions() { + return jLinkOptions; + } + public void setAppName(String appName) { this.appName.set(appName); } @@ -89,4 +117,44 @@ public class JPackageExtension { public Property getAppVersion() { return appVersion; } + + public void setAppCopyright(String appCopyright) { + this.appCopyright.set(appCopyright); + } + + public Property getAppCopyright() { + return appCopyright; + } + + public void setAppVendor(String appVendor) { + this.appVendor.set(appVendor); + } + + public Property getAppVendor() { + return appVendor; + } + + public void setAppDescription(String appDescription) { + this.appDescription.set(appDescription); + } + + public Property getAppDescription() { + return appDescription; + } + + public void setAppIcon(String appIcon) { + this.appIcon.set(appIcon); + } + + public Property getAppIcon() { + return appIcon; + } + + public void setAppImage(Directory appImage) { + this.appImage .set(appImage); + } + + public DirectoryProperty getAppImage() { + return appImage; + } } diff --git a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageTask.java b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageTask.java index bec0d4c..c13dab7 100644 --- a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageTask.java +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageTask.java @@ -43,10 +43,6 @@ public class JPackageTask extends AbstractExecTask { @Input Property module; - @Input - @Optional - Property appImage; - @InputDirectory @Optional DirectoryProperty input; @@ -55,6 +51,10 @@ public class JPackageTask extends AbstractExecTask { @Optional Property type; + @Input + @Optional + ListProperty jLinkOptions; + @Input @Optional Property appName; @@ -65,7 +65,11 @@ public class JPackageTask extends AbstractExecTask { @Input @Optional - Property copyright; + Property appCopyright; + + @Input + @Optional + Property appVendor; @Input @Optional @@ -73,7 +77,11 @@ public class JPackageTask extends AbstractExecTask { @Input @Optional - Property icon; + Property appIcon; + + @InputDirectory + @Optional + DirectoryProperty appImage; @Inject public JPackageTask() { @@ -84,14 +92,16 @@ public class JPackageTask extends AbstractExecTask { jPackageOutputDirectory = getProject().getObjects().directoryProperty(); addModules = getProject().getObjects().listProperty(String.class); module = getProject().getObjects().property(String.class); - appImage = getProject().getObjects().property(String.class); input = getProject().getObjects().directoryProperty(); type = getProject().getObjects().property(String.class); + jLinkOptions = getProject().getObjects().listProperty(String.class); appName = getProject().getObjects().property(String.class); appVersion = getProject().getObjects().property(String.class); - copyright = getProject().getObjects().property(String.class); + appCopyright = getProject().getObjects().property(String.class); + appVendor = getProject().getObjects().property(String.class); appDescription = getProject().getObjects().property(String.class); - icon = getProject().getObjects().property(String.class); + appIcon = getProject().getObjects().property(String.class); + appImage = getProject().getObjects().directoryProperty(); } @Override @@ -120,12 +130,12 @@ public class JPackageTask extends AbstractExecTask { args.add("--input"); args.add(input.getAsFile().get().getAbsolutePath()); } - if (appImage.isPresent()) { - args.add("--app-image"); - args.add(appImage.get()); - } args.add("--type"); args.add(type.get()); + if (jLinkOptions.isPresent() && !jLinkOptions.get().isEmpty()) { + args.add("--jlink-options"); + args.add(String.join(" ", jLinkOptions.get())); + } if (appName.isPresent()) { args.add("--name"); args.add(appName.get()); @@ -134,17 +144,25 @@ public class JPackageTask extends AbstractExecTask { args.add("--app-version"); args.add(appVersion.get()); } - if (copyright.isPresent()) { + if (appVendor.isPresent()) { + args.add("--vendor"); + args.add(appVendor.get()); + } + if (appCopyright.isPresent()) { args.add("--copyright"); - args.add(copyright.get()); + args.add(appCopyright.get()); } if (appDescription.isPresent()) { args.add("--description"); args.add(appDescription.get()); } - if (icon.isPresent()) { + if (appIcon.isPresent()) { args.add("--icon"); - args.add(icon.get()); + args.add(appIcon.get()); + } + if (appImage.isPresent()) { + args.add("--app-image"); + args.add(appImage.getAsFile().get().getAbsolutePath()); } setArgs(args); getLogger().log(LogLevel.INFO, "executing " + getExecutable() + " with " + getArgs()); @@ -191,14 +209,6 @@ public class JPackageTask extends AbstractExecTask { return module; } - public void setAppImage(String appImage) { - this.appImage .set(appImage); - } - - public Property getAppImage() { - return appImage; - } - public DirectoryProperty getInput() { return input; } @@ -211,6 +221,14 @@ public class JPackageTask extends AbstractExecTask { return type; } + public void setjLinkOptions(List jLinkOptions) { + this.jLinkOptions.set(jLinkOptions); + } + + public ListProperty getjLinkOptions() { + return jLinkOptions; + } + public void setAppName(String appName) { this.appName.set(appName); } @@ -227,12 +245,20 @@ public class JPackageTask extends AbstractExecTask { return appVersion; } - public void setCopyright(String copyright) { - this.copyright.set(copyright); + public void setAppCopyright(String appCopyright) { + this.appCopyright.set(appCopyright); } - public Property getCopyright() { - return copyright; + public Property getAppCopyright() { + return appCopyright; + } + + public void setAppVendor(String appVendor) { + this.appVendor.set(appVendor); + } + + public Property getAppVendor() { + return appVendor; } public void setAppDescription(String appDescription) { @@ -243,12 +269,20 @@ public class JPackageTask extends AbstractExecTask { return appDescription; } - public void setIcon(String icon) { - this.icon.set(icon); + public void setAppIcon(String appIcon) { + this.appIcon.set(appIcon); } - public Property getIcon() { - return icon; + public Property getAppIcon() { + return appIcon; + } + + public void setAppImage(Directory appImage) { + this.appImage .set(appImage); + } + + public DirectoryProperty getAppImage() { + return appImage; } private static void createDirectory(Path path) throws IOException { diff --git a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JRunTask.java b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JRunTask.java new file mode 100644 index 0000000..c75ab5b --- /dev/null +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JRunTask.java @@ -0,0 +1,34 @@ +package org.xbib.gradle.plugin.jlink; + +import org.gradle.api.file.RegularFile; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.tasks.AbstractExecTask; +import org.gradle.api.tasks.InputFile; + +import javax.inject.Inject; + +public class JRunTask extends AbstractExecTask { + + @InputFile + RegularFileProperty exec; + + @Inject + public JRunTask() { + super(JRunTask.class); + exec = getProject().getObjects().fileProperty(); + } + + @Override + public void exec() { + setExecutable(exec.get()); + super.exec(); + } + + public void setExec(RegularFile exec) { + this.exec.set(exec); + } + + public RegularFileProperty getExec() { + return exec; + } +} diff --git a/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JLinkTest.groovy b/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JLinkTest.groovy index 34a6337..060b1a9 100644 --- a/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JLinkTest.groovy +++ b/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JLinkTest.groovy @@ -21,7 +21,6 @@ class JLinkTest extends Specification { jlink { addModules.set(List.of("org.example.app")) launcher.set("app=org.example.app/org.example.app.Main") - stripDebug.set(true) } """ appModuleInfoFile << """ diff --git a/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JRunTest.groovy b/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JRunTest.groovy new file mode 100644 index 0000000..5c8984c --- /dev/null +++ b/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JRunTest.groovy @@ -0,0 +1,44 @@ +package org.xbib.gradle.plugin.jlink + +import spock.lang.Specification + +import static org.gradle.testkit.runner.TaskOutcome.FAILED +import static org.gradle.testkit.runner.TaskOutcome.SUCCESS +import static org.xbib.gradle.plugin.jlink.JLinkGradleBuild.runsOnLinux + +class JRunTest extends Specification { + + @Delegate + JLinkGradleBuild build = new JLinkGradleBuild() + + def "can use jlink plugin with jrun task"() { + given: + def taskToRun = ":app:jrun" + appBuildFile << """ + dependencies { + api "org.junit.jupiter:junit-jupiter-engine:5.10.2" + } + jlink { + addModules.set(List.of("org.example.app")) + launcher.set("app=org.example.app/org.example.app.Main") + } + """ + appModuleInfoFile << """ + module org.example.app { + exports org.example.app; + } + """ + + when: + def result = success ? build(taskToRun) : fail(taskToRun) + + then: + println result.output + result.task(taskToRun).outcome == (success ? SUCCESS : FAILED) + success + + where: + label | os | success + 'fedora' | 'linux' | runsOnLinux() + } +}