From c814515f95768be253ada5968b2f4d8def3a6542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Prante?= Date: Wed, 6 Nov 2024 15:11:24 +0100 Subject: [PATCH] add jpackage task to jlink plugin --- .../xbib/gradle/plugin/jlink/JDepsTask.java | 10 +- .../gradle/plugin/jlink/JLinkExtension.java | 23 +- .../xbib/gradle/plugin/jlink/JLinkPlugin.java | 117 +++++--- .../xbib/gradle/plugin/jlink/JLinkTask.java | 31 +- .../plugin/jlink/JPackageExtension.java | 114 +++++++ .../gradle/plugin/jlink/JPackageTask.java | 279 ++++++++++++++++++ .../plugin/jlink/JLinkGradleBuild.groovy | 8 +- .../xbib/gradle/plugin/jlink/JLinkTest.groovy | 2 +- .../gradle/plugin/jlink/JPackageTest.groovy | 45 +++ 9 files changed, 570 insertions(+), 59 deletions(-) create mode 100644 gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageExtension.java create mode 100644 gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageTask.java create mode 100644 gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JPackageTest.groovy diff --git a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JDepsTask.java b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JDepsTask.java index a8fc162..de3b396 100644 --- a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JDepsTask.java +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JDepsTask.java @@ -1,5 +1,6 @@ package org.xbib.gradle.plugin.jlink; +import java.io.File; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -48,9 +49,9 @@ public class JDepsTask extends AbstractExecTask { @Inject public JDepsTask() { super(JDepsTask.class); - javaCompiler = getProject().getObjects().property(JavaCompiler.class); JavaToolchainSpec toolchain = getProject().getExtensions().getByType(JavaPluginExtension.class).getToolchain(); JavaToolchainService service = getProject().getExtensions().getByType(JavaToolchainService.class); + javaCompiler = getProject().getObjects().property(JavaCompiler.class); javaCompiler.convention(service.compilerFor(toolchain)); Provider modulePathProvider = javaCompiler.map(it -> { Directory jmods = it.getMetadata().getInstallationPath().dir("jmods"); @@ -87,9 +88,9 @@ public class JDepsTask extends AbstractExecTask { args.add("--module-path"); args.add(modulePath.get().getAsFile().getAbsolutePath()); args.add("--module-path"); - args.add(String.join(";", jarFiles)); // jdeps does not understand jmod files + args.add(String.join(File.pathSeparator, jarFiles)); // jdeps does not understand jmod files args.add("--class-path"); - args.add(String.join(";", jarFiles)); + args.add(String.join(File.pathSeparator, jarFiles)); if (printModuleDeps.get()) { args.add("--print-module-deps"); } @@ -99,6 +100,9 @@ public class JDepsTask extends AbstractExecTask { if (verbose.get()) { args.add("-v"); // verbose, list deps for each class } + args.add("--multi-release"); + String version = javaCompiler.get().getMetadata().getLanguageVersion().toString(); + args.add(version); args.add(jarTask.get().getArchiveFile().get().getAsFile().getAbsolutePath()); setArgs(args); getLogger().log(LogLevel.INFO, "executing " + getExecutable() + " with " + args); diff --git a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkExtension.java b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkExtension.java index 4fd265f..0da8027 100644 --- a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkExtension.java +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkExtension.java @@ -15,7 +15,7 @@ public class JLinkExtension { private final DirectoryProperty modulePath; - private final DirectoryProperty outputDirectory; + private final DirectoryProperty jLinkOutputDirectory; private final ListProperty addModules; @@ -29,6 +29,8 @@ public class JLinkExtension { private final Property stripDebug; + private final Property stripNativeCommands; + private final Property noHeaderFiles; private final Property noManPages; @@ -48,13 +50,14 @@ public class JLinkExtension { public JLinkExtension(Project project) { javaCompiler = project.getObjects().property(JavaCompiler.class); modulePath = project.getObjects().directoryProperty(); - outputDirectory = project.getObjects().directoryProperty(); + jLinkOutputDirectory = project.getObjects().directoryProperty(); addModules = project.getObjects().listProperty(String.class); limitModules = project.getObjects().listProperty(String.class); bindServices = project.getObjects().property(Boolean.class); launcher = project.getObjects().property(String.class); compress = project.getObjects().property(Integer.class); stripDebug = project.getObjects().property(Boolean.class); + stripNativeCommands = project.getObjects().property(Boolean.class); noHeaderFiles = project.getObjects().property(Boolean.class); noManPages = project.getObjects().property(Boolean.class); endian = project.getObjects().property(Endian.class); @@ -78,12 +81,12 @@ public class JLinkExtension { return modulePath; } - public void setOutputDirectory(Directory outputDirectory) { - this.outputDirectory.set(outputDirectory); + public void setjLinkOutputDirectory(Directory jLinkOutputDirectory) { + this.jLinkOutputDirectory.set(jLinkOutputDirectory); } - public DirectoryProperty getOutputDirectory() { - return outputDirectory; + public DirectoryProperty getjLinkOutputDirectory() { + return jLinkOutputDirectory; } public void setAddModules(List addModules) { @@ -134,6 +137,14 @@ public class JLinkExtension { return stripDebug; } + public void setStripNativeCommands(Boolean stripNativeCommands) { + this.stripNativeCommands.set(stripNativeCommands); + } + + public Property getStripNativeCommands() { + return stripNativeCommands; + } + public void setNoHeaderFiles(Boolean noHeaderFiles) { this.noHeaderFiles.set(noHeaderFiles); } 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 feb24c3..46f0945 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 @@ -29,11 +29,11 @@ public abstract class JLinkPlugin implements Plugin { throw new GradleException("this plugin is only available for Linux"); } project.getPluginManager().apply(JavaLibraryPlugin.class); - JLinkExtension extension = project.getExtensions().create("jlink", JLinkExtension.class); JavaToolchainSpec toolchain = project.getExtensions().getByType(JavaPluginExtension.class).getToolchain(); JavaToolchainService service = project.getExtensions().getByType(JavaToolchainService.class); - extension.getJavaCompiler().convention(service.compilerFor(toolchain)); - Provider modulePathProvider = extension.getJavaCompiler().map(it -> { + JLinkExtension jLinkExtension = project.getExtensions().create("jlink", JLinkExtension.class); + jLinkExtension.getJavaCompiler().convention(service.compilerFor(toolchain)); + Provider modulePathProvider = jLinkExtension.getJavaCompiler().map(it -> { Directory jmods = it.getMetadata().getInstallationPath().dir("jmods"); if (jmods.getAsFile().exists()) { project.getLogger().log(LogLevel.INFO, "using jmods directory found in installation for module path"); @@ -43,59 +43,98 @@ public abstract class JLinkPlugin implements Plugin { return null; } }); - extension.getModulePath().convention(modulePathProvider); - extension.getOutputDirectory().convention(project.getLayout().getBuildDirectory().dir("jlink")); - extension.getAddModules().convention(List.of("java.base")); - extension.getLimitModules().convention(List.of()); - extension.getBindServices().convention(false); - extension.getLauncher().unsetConvention(); - extension.getCompress().convention(6); // zip-6, default - extension.getStripDebug().convention(false); - extension.getNoHeaderFiles().convention(true); - extension.getNoManPages().convention(true); - extension.getEndian().convention(JLinkExtension.Endian.NATIVE); - extension.getIncludeLocales().unsetConvention(); - extension.getModuleVersion().convention(project.getVersion().toString()); + jLinkExtension.getModulePath().convention(modulePathProvider); + jLinkExtension.getjLinkOutputDirectory().convention(project.getLayout().getBuildDirectory().dir("jlink")); + jLinkExtension.getAddModules().convention(List.of("java.base")); + jLinkExtension.getLimitModules().convention(List.of()); + jLinkExtension.getBindServices().convention(false); + jLinkExtension.getLauncher().unsetConvention(); + jLinkExtension.getCompress().convention(6); // zip-6, default + jLinkExtension.getStripDebug().convention(true); // same as jpackage default + jLinkExtension.getStripNativeCommands().convention(false); + jLinkExtension.getNoHeaderFiles().convention(true); // same as jpackage default + jLinkExtension.getNoManPages().convention(true); // same as jpackage default + jLinkExtension.getEndian().convention(JLinkExtension.Endian.NATIVE); + jLinkExtension.getIncludeLocales().unsetConvention(); + jLinkExtension.getModuleVersion().convention(project.getVersion().toString()); + + JPackageExtension jPackageExtension = project.getExtensions().create("jpackage", JPackageExtension.class); + jPackageExtension.getJavaCompiler().convention(service.compilerFor(toolchain)); + jPackageExtension.getModulePath().convention(modulePathProvider); + jPackageExtension.getjPackageOutputDirectory().convention(project.getLayout().getBuildDirectory().dir("jpackage")); + jPackageExtension.getAddModules().convention(List.of("java.base")); + jPackageExtension.getModule().unsetConvention(); + jPackageExtension.getInput().convention(project.getLayout().getBuildDirectory().dir("jlink")); + jPackageExtension.getType().convention("rpm"); // Fedora/Red Hat Linux + jPackageExtension.getAppName().convention(project.getName()); + jPackageExtension.getAppVersion().convention(project.getVersion().toString()); + // get the jar task TaskProvider jarTask = project.getTasks().named("jar", Jar.class); Objects.requireNonNull(jarTask, "jar task required to be present"); TaskProvider jModTask = project.getTasks().register("jmod", JModTask.class); project.getTasks().withType(JModTask.class).forEach(it -> { + it.setGroup("build"); it.dependsOn(jarTask); - it.javaCompiler.set(extension.getJavaCompiler()); - it.moduleVersion.set(extension.getModuleVersion()); + it.javaCompiler.set(jLinkExtension.getJavaCompiler()); + it.moduleVersion.set(jLinkExtension.getModuleVersion()); }); // install the jdeps task TaskProvider jDepsTask = project.getTasks().register("jdeps", JDepsTask.class); project.getTasks().withType(JDepsTask.class).forEach(it -> { + it.setGroup("build"); it.dependsOn(jModTask); - it.modulePath.set(extension.getModulePath()); + it.javaCompiler.set(jLinkExtension.getJavaCompiler()); + it.modulePath.set(jLinkExtension.getModulePath()); }); Objects.requireNonNull(jModTask, "jmod task required to be present"); - // depend jlink on jdeps and jmod task + // depend jlink on jdeps task TaskProvider jLinkTask = project.getTasks().register("jlink", JLinkTask.class); - Objects.requireNonNull(jLinkTask, "jlink task required to be present"); project.getTasks().withType(JLinkTask.class).forEach(it -> { + it.setGroup("build"); it.dependsOn(jDepsTask); - it.javaCompiler.set(extension.getJavaCompiler()); - it.modulePath.set(extension.getModulePath()); - it.outputDirectory.set(extension.getOutputDirectory()); - it.addModules.set(extension.getAddModules()); - it.limitModules.set(extension.getLimitModules()); - it.bindServices.set(extension.getBindServices()); - it.launcher.set(extension.getLauncher()); - it.compress.set(extension.getCompress()); - it.stripDebug.set(extension.getStripDebug()); - it.noHeaderFiles.set(extension.getNoHeaderFiles()); - it.noManPages.set(extension.getNoManPages()); - it.endian.set(extension.getEndian()); + it.javaCompiler.set(jLinkExtension.getJavaCompiler()); + it.modulePath.set(jLinkExtension.getModulePath()); + it.jLinkOutputDirectory.set(jLinkExtension.getjLinkOutputDirectory()); + it.addModules.set(jLinkExtension.getAddModules()); + it.limitModules.set(jLinkExtension.getLimitModules()); + it.bindServices.set(jLinkExtension.getBindServices()); + it.launcher.set(jLinkExtension.getLauncher()); + it.compress.set(jLinkExtension.getCompress()); + it.stripDebug.set(jLinkExtension.getStripDebug()); + it.stripNativeCommands.set(jLinkExtension.getStripNativeCommands()); + it.noHeaderFiles.set(jLinkExtension.getNoHeaderFiles()); + it.noManPages.set(jLinkExtension.getNoManPages()); + it.endian.set(jLinkExtension.getEndian()); }); - Configuration configuration = project.getConfigurations().create("jlink"); - configuration.setCanBeConsumed(true); - configuration.setCanBeResolved(false); - configuration.setVisible(false); - configuration.attributes(a -> a.attribute(Usage.USAGE_ATTRIBUTE, + // depend jpackage on jlink task + TaskProvider jPackageTask = project.getTasks().register("jpackage", JPackageTask.class); + project.getTasks().withType(JPackageTask.class).forEach(it -> { + it.setGroup("build"); + it.dependsOn(jLinkTask); + it.javaCompiler.set(jPackageExtension.getJavaCompiler()); + it.modulePath.set(jPackageExtension.getModulePath()); + it.jPackageOutputDirectory.set(jPackageExtension.getjPackageOutputDirectory()); + it.addModules.set(jPackageExtension.getAddModules()); + it.module.set(jPackageExtension.getModule()); + it.input.set(jPackageExtension.getInput()); + it.type.set(jPackageExtension.getType()); + it.appName.set(jPackageExtension.getAppName()); + it.appVersion.set(jPackageExtension.getAppVersion()); + }); + Configuration jLinkConfiguration = project.getConfigurations().create("jlink"); + jLinkConfiguration.setCanBeConsumed(true); + jLinkConfiguration.setCanBeResolved(false); + jLinkConfiguration.setVisible(false); + jLinkConfiguration.attributes(a -> a.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, "jlink"))); - configuration.outgoing(o -> o.artifact(jLinkTask.flatMap(t -> t.outputDirectory))); + jLinkConfiguration.outgoing(o -> o.artifact(jLinkTask.flatMap(t -> t.jLinkOutputDirectory))); + Configuration jPackageConfiguration = project.getConfigurations().create("jpackage"); + jPackageConfiguration.setCanBeConsumed(true); + jPackageConfiguration.setCanBeResolved(false); + jPackageConfiguration.setVisible(false); + jPackageConfiguration.attributes(a -> a.attribute(Usage.USAGE_ATTRIBUTE, + project.getObjects().named(Usage.class, "jpackage"))); + jPackageConfiguration.outgoing(o -> o.artifact(jPackageTask.flatMap(t -> t.jPackageOutputDirectory))); } } diff --git a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkTask.java b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkTask.java index 8893dce..c19c9d2 100644 --- a/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkTask.java +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JLinkTask.java @@ -36,7 +36,7 @@ public class JLinkTask extends AbstractExecTask { DirectoryProperty modulePath; @OutputDirectory - DirectoryProperty outputDirectory; + DirectoryProperty jLinkOutputDirectory; @Input ListProperty addModules; @@ -57,6 +57,10 @@ public class JLinkTask extends AbstractExecTask { @Optional Property compress; + @Input + @Optional + Property stripNativeCommands; + @Input @Optional Property stripDebug; @@ -82,13 +86,14 @@ public class JLinkTask extends AbstractExecTask { super(JLinkTask.class); javaCompiler = getProject().getObjects().property(JavaCompiler.class); modulePath = getProject().getObjects().directoryProperty(); - outputDirectory = getProject().getObjects().directoryProperty(); + jLinkOutputDirectory = getProject().getObjects().directoryProperty(); addModules = getProject().getObjects().listProperty(String.class); limitModules = getProject().getObjects().listProperty(String.class); bindServices = getProject().getObjects().property(Boolean.class); launcher = getProject().getObjects().property(String.class); compress = getProject().getObjects().property(Integer.class); stripDebug = getProject().getObjects().property(Boolean.class); + stripNativeCommands = getProject().getObjects().property(Boolean.class); noHeaderFiles = getProject().getObjects().property(Boolean.class); noManPages = getProject().getObjects().property(Boolean.class); endian = getProject().getObjects().property(JLinkExtension.Endian.class); @@ -98,7 +103,7 @@ public class JLinkTask extends AbstractExecTask { @Override public void exec() { setExecutable(javaCompiler.get().getMetadata().getInstallationPath().file("bin/jlink")); - File jlinkOutput = outputDirectory.get().getAsFile(); + File jlinkOutput = jLinkOutputDirectory.get().getAsFile(); try { createDirectory(jlinkOutput.toPath()); } catch (IOException e) { @@ -122,10 +127,12 @@ public class JLinkTask extends AbstractExecTask { } if (stripDebug.get()) { args.add("--strip-debug"); - //args.add("--strip-native-debug-symbols=keep-debuginfo-files"); args.add("--strip-native-debug-symbols=exclude-debuginfo-files"); args.add("--strip-java-debug-attributes"); } + if (stripNativeCommands.get()) { + args.add("--strip-native-commands"); + } if (noHeaderFiles.get()) { args.add("--no-header-files"); } @@ -169,12 +176,12 @@ public class JLinkTask extends AbstractExecTask { return modulePath; } - public void setOutputDirectory(Directory outputDirectory) { - this.outputDirectory.set(outputDirectory); + public void setjLinkOutputDirectory(Directory jLinkOutputDirectory) { + this.jLinkOutputDirectory.set(jLinkOutputDirectory); } - public DirectoryProperty getOutputDirectory() { - return outputDirectory; + public DirectoryProperty getjLinkOutputDirectory() { + return jLinkOutputDirectory; } public void setAddModules(List addModules) { @@ -225,6 +232,14 @@ public class JLinkTask extends AbstractExecTask { return stripDebug; } + public void setStripNativeCommands(Boolean stripNativeCommands) { + this.stripNativeCommands.set(stripNativeCommands); + } + + public Property getStripNativeCommands() { + return stripNativeCommands; + } + public void setNoHeaderFiles(Boolean noHeaderFiles) { this.noHeaderFiles.set(noHeaderFiles); } 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 new file mode 100644 index 0000000..bd1acc3 --- /dev/null +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageExtension.java @@ -0,0 +1,114 @@ +package org.xbib.gradle.plugin.jlink; + +import java.util.List; +import org.gradle.api.Project; +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.jvm.toolchain.JavaCompiler; + +public class JPackageExtension { + + private final Property javaCompiler; + + private final DirectoryProperty modulePath; + + private final DirectoryProperty jPackageOutputDirectory; + + private final ListProperty addModules; + + private final Property module; + + private final DirectoryProperty input; + + private final Property type; + + private final Property appName; + + private final Property appVersion; + + public JPackageExtension(Project project) { + javaCompiler = project.getObjects().property(JavaCompiler.class); + modulePath = project.getObjects().directoryProperty(); + 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); + appName = project.getObjects().property(String.class); + appVersion = project.getObjects().property(String.class); + } + + public void setJavaCompiler(JavaCompiler javaCompiler) { + this.javaCompiler.set(javaCompiler); + } + + public Property getJavaCompiler() { + return javaCompiler; + } + + public void setModulePath(Directory modulePath) { + this.modulePath.set(modulePath); + } + + public DirectoryProperty getModulePath() { + return modulePath; + } + + public void setjPackageOutputDirectory(Directory jPackageOutputDirectory) { + this.jPackageOutputDirectory.set(jPackageOutputDirectory); + } + + public DirectoryProperty getjPackageOutputDirectory() { + return jPackageOutputDirectory; + } + + public void setAddModules(List addModules) { + this.addModules.set(addModules); + } + + public ListProperty getAddModules() { + return addModules; + } + + public void setModule(String module) { + this.module.set(module); + } + + public Property getModule() { + return module; + } + + public void setInput(Directory input) { + this.input.set(input); + } + + public DirectoryProperty getInput() { + return input; + } + + public void setType(String type) { + this.type.set(type); + } + + public Property getType() { + return type; + } + + public void setAppName(String appName) { + this.appName.set(appName); + } + + public Property getAppName() { + return appName; + } + + public void setAppVersion(String appVersion) { + this.appVersion.set(appVersion); + } + + public Property getAppVersion() { + return appVersion; + } +} 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 new file mode 100644 index 0000000..64eec43 --- /dev/null +++ b/gradle-plugin-jlink/src/main/java/org/xbib/gradle/plugin/jlink/JPackageTask.java @@ -0,0 +1,279 @@ +package org.xbib.gradle.plugin.jlink; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import javax.inject.Inject; +import org.gradle.api.file.Directory; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.logging.LogLevel; +import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.AbstractExecTask; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.Nested; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.TaskProvider; +import org.gradle.jvm.toolchain.JavaCompiler; + +public class JPackageTask extends AbstractExecTask { + + @Nested + Property javaCompiler; + + @InputDirectory + @Optional + DirectoryProperty modulePath; + + @OutputDirectory + DirectoryProperty jPackageOutputDirectory; + + @Input + ListProperty addModules; + + @Input + Property module; + + @Input + @Optional + Property appImage; + + @InputDirectory + @Optional + DirectoryProperty input; + + @Input + @Optional + Property type; + + @Input + @Optional + Property appName; + + @Input + @Optional + Property appVersion; + + @Input + @Optional + Property copyright; + + @Input + @Optional + Property appDescription; + + @Input + @Optional + Property icon; + + @Inject + public JPackageTask() { + super(JPackageTask.class); + javaCompiler = getProject().getObjects().property(JavaCompiler.class); + modulePath = getProject().getObjects().directoryProperty(); + modulePath = getProject().getObjects().directoryProperty(); + 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); + appName = getProject().getObjects().property(String.class); + appVersion = getProject().getObjects().property(String.class); + copyright = getProject().getObjects().property(String.class); + appDescription = getProject().getObjects().property(String.class); + icon = getProject().getObjects().property(String.class); + } + + @Override + protected void exec() { + setExecutable(javaCompiler.get().getMetadata().getInstallationPath().file("bin/jpackage")); + File jPackageOutput = jPackageOutputDirectory.get().getAsFile(); + try { + createDirectory(jPackageOutput.toPath()); + } catch (IOException e) { + throw new RuntimeException(e); + } + List args = new ArrayList<>(); + args.add("--module-path"); + args.add(modulePath.get().getAsFile().getAbsolutePath()); + args.add("--module-path"); + TaskProvider jmodTask = getProject().getTasks().named("jmod", JModTask.class); + Objects.requireNonNull(jmodTask, "jmod task must be present"); + args.add(jmodTask.get().jModDirectory.getAsFile().get().getAbsolutePath()); + args.add("--dest"); + args.add(jPackageOutput.getAbsolutePath()); + args.add("--add-modules"); + args.add(String.join(",", addModules.get())); + args.add("--module"); + args.add(module.get()); + if (input.isPresent()) { + 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 (appName.isPresent()) { + args.add("--name"); + args.add(appName.get()); + } + if (appVersion.isPresent()) { + args.add("--app-version"); + args.add(appVersion.get()); + } + if (copyright.isPresent()) { + args.add("--copyright"); + args.add(copyright.get()); + } + if (appDescription.isPresent()) { + args.add("--description"); + args.add(appDescription.get()); + } + if (icon.isPresent()) { + args.add("--icon"); + args.add(icon.get()); + } + setArgs(args); + System.err.println("executing " + getExecutable() + " with " + args); + getLogger().log(LogLevel.INFO, "executing " + getExecutable() + " with " + args); + super.exec(); + } + + public void setJavaCompiler(JavaCompiler javaCompiler) { + this.javaCompiler.set(javaCompiler); + } + + public Property getJavaCompiler() { + return javaCompiler; + } + + public void setModulePath(Directory modulePath) { + this.modulePath.set(modulePath); + } + + public DirectoryProperty getModulePath() { + return modulePath; + } + + public void setjPackageOutputDirectory(Directory jPackageOutputDirectory) { + this.jPackageOutputDirectory.set(jPackageOutputDirectory); + } + + public DirectoryProperty getjPackageOutputDirectory() { + return jPackageOutputDirectory; + } + + public void setAddModules(List addModules) { + this.addModules.set(addModules); + } + + public ListProperty getAddModules() { + return addModules; + } + + public void setModule(String module) { + this.module.set(module); + } + + public Property getModule() { + return module; + } + + public void setAppImage(String appImage) { + this.appImage .set(appImage); + } + + public Property getAppImage() { + return appImage; + } + + /*public void setInput(DirectoryProperty input) { + this.input = input; + }*/ + + public DirectoryProperty getInput() { + return input; + } + + public void setType(String type) { + this.type.set(type); + } + + public Property getType() { + return type; + } + + public void setAppName(String appName) { + this.appName.set(appName); + } + + public Property getAppName() { + return appName; + } + + public void setAppVersion(String appVersion) { + this.appVersion.set(appVersion); + } + + public Property getAppVersion() { + return appVersion; + } + + public void setCopyright(String copyright) { + this.copyright.set(copyright); + } + + public Property getCopyright() { + return copyright; + } + + public void setAppDescription(String appDescription) { + this.appDescription.set(appDescription); + } + + public Property getAppDescription() { + return appDescription; + } + + public void setIcon(String icon) { + this.icon.set(icon); + } + + public Property getIcon() { + return icon; + } + + private static void createDirectory(Path path) throws IOException { + if (Files.exists(path)) { + Files.walkFileTree(path, new SimpleFileVisitor<>() { + @Override + public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException { + Files.delete(dir); + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + Files.delete(file); + return FileVisitResult.CONTINUE; + } + }); + Files.deleteIfExists(path); + } + // jpackage bails out if directory is created, so we create the parent + Files.createDirectories(path.getParent()); + } +} diff --git a/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JLinkGradleBuild.groovy b/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JLinkGradleBuild.groovy index 1916e1f..383afb3 100644 --- a/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JLinkGradleBuild.groovy +++ b/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JLinkGradleBuild.groovy @@ -6,6 +6,7 @@ import org.gradle.testkit.runner.GradleRunner class JLinkGradleBuild { final File projectDir + final File propertiesFile final File settingsFile final File appBuildFile final File appModuleInfoFile @@ -16,11 +17,16 @@ class JLinkGradleBuild { JLinkGradleBuild() { this.projectDir = createDirectory('build/jlink-gradle-build') + this.propertiesFile = tapFile("gradle.properties") this.settingsFile = tapFile('settings.gradle') this.appBuildFile = tapFile('app/build.gradle') this.appModuleInfoFile = tapFile('app/src/main/java/module-info.java') this.libBuildFile = tapFile('lib/build.gradle') this.libModuleInfoFile = tapFile('lib/src/main/java/module-info.java') + propertiesFile << ''' + group = "org.example" + version = 1.0 +''' settingsFile << ''' dependencyResolutionManagement { repositories.mavenCentral() } includeBuild(".") @@ -31,7 +37,6 @@ class JLinkGradleBuild { plugins { id "org.xbib.gradle.plugin.jlink" } - group = "org.example" ''' tapFile("app/src/main/java/org/example/app/Main.java") << ''' package org.example.app; @@ -57,7 +62,6 @@ class JLinkGradleBuild { plugins { id("org.xbib.gradle.plugin.jlink") } - group = "org.example" ''' } 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 ce3ea0e..34a6337 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 @@ -11,7 +11,7 @@ class JLinkTest extends Specification { @Delegate JLinkGradleBuild build = new JLinkGradleBuild() - def "can use jlink plugin"() { + def "can use jlink plugin with jlink task"() { given: def taskToRun = ":app:jlink" appBuildFile << """ diff --git a/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JPackageTest.groovy b/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JPackageTest.groovy new file mode 100644 index 0000000..a58924c --- /dev/null +++ b/gradle-plugin-jlink/src/test/groovy/org/xbib/gradle/plugin/jlink/JPackageTest.groovy @@ -0,0 +1,45 @@ +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 JPackageTest extends Specification { + + @Delegate + JLinkGradleBuild build = new JLinkGradleBuild() + + def "can use jlink plugin with jpackage task"() { + given: + def taskToRun = ":app:jpackage" + appBuildFile << """ + dependencies { + api "org.junit.jupiter:junit-jupiter-engine:5.10.2" + } + jpackage { + addModules.set(List.of("org.example.app")) + module.set("org.example.app/org.example.app.Main") + appName.set("helloworld") + } + """ + 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() + } +}