first jmod/jlink Hello world project, successful test
This commit is contained in:
parent
20f5a45db9
commit
e91f776db2
7 changed files with 496 additions and 48 deletions
|
@ -12,6 +12,8 @@ apply from: rootProject.file('gradle/test/junit5.gradle')
|
||||||
dependencies {
|
dependencies {
|
||||||
api gradleApi()
|
api gradleApi()
|
||||||
testImplementation gradleTestKit()
|
testImplementation gradleTestKit()
|
||||||
|
testImplementation testLibs.spock.core
|
||||||
|
testImplementation testLibs.spock.junit4
|
||||||
}
|
}
|
||||||
|
|
||||||
if (project.hasProperty('gradle.publish.key')) {
|
if (project.hasProperty('gradle.publish.key')) {
|
||||||
|
|
|
@ -1,25 +1,85 @@
|
||||||
package org.xbib.gradle.plugin.jlink;
|
package org.xbib.gradle.plugin.jlink;
|
||||||
|
|
||||||
|
import org.gradle.api.Project;
|
||||||
import org.gradle.api.provider.ListProperty;
|
import org.gradle.api.provider.ListProperty;
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class JLinkExtension {
|
public class JLinkExtension {
|
||||||
|
|
||||||
ListProperty<String> modules;
|
private final ListProperty<String> modules;
|
||||||
|
|
||||||
Property<Integer> compress;
|
private final Property<Integer> compress;
|
||||||
|
|
||||||
Property<Boolean> stripDebug;
|
private final Property<Boolean> stripDebug;
|
||||||
|
|
||||||
Property<Boolean> noHeaderFiles;
|
private final Property<Boolean> noHeaderFiles;
|
||||||
|
|
||||||
Property<Boolean> noManPages;
|
private final Property<Boolean> noManPages;
|
||||||
|
|
||||||
Property<Endian> endian;
|
private final Property<Endian> endian;
|
||||||
|
|
||||||
enum Endian {
|
public enum Endian {
|
||||||
LITTLE,
|
LITTLE,
|
||||||
BIG,
|
BIG,
|
||||||
NATIVE,
|
NATIVE,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JLinkExtension(Project project) {
|
||||||
|
this.modules = project.getObjects().listProperty(String.class);
|
||||||
|
this.compress = project.getObjects().property(Integer.class);
|
||||||
|
this.stripDebug = project.getObjects().property(Boolean.class);
|
||||||
|
this.noHeaderFiles = project.getObjects().property(Boolean.class);
|
||||||
|
this.noManPages = project.getObjects().property(Boolean.class);
|
||||||
|
this.endian = project.getObjects().property(Endian.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModules(List<String> modules) {
|
||||||
|
this.modules.set(modules);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListProperty<String> getModules() {
|
||||||
|
return modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompress(Integer compress) {
|
||||||
|
this.compress.set(compress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<Integer> getCompress() {
|
||||||
|
return compress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStripDebug(Boolean stripDebug) {
|
||||||
|
this.stripDebug.set(stripDebug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<Boolean> getStripDebug() {
|
||||||
|
return stripDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNoHeaderFiles(Boolean noHeaderFiles) {
|
||||||
|
this.noHeaderFiles.set(noHeaderFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<Boolean> getNoHeaderFiles() {
|
||||||
|
return noHeaderFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNoManPages(Boolean noManPages) {
|
||||||
|
this.noManPages.set(noManPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<Boolean> getNoManPages() {
|
||||||
|
return noManPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndian(Endian endian) {
|
||||||
|
this.endian.set(endian);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<Endian> getEndian() {
|
||||||
|
return endian;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,10 @@ import org.gradle.api.artifacts.Configuration;
|
||||||
import org.gradle.api.attributes.Usage;
|
import org.gradle.api.attributes.Usage;
|
||||||
import org.gradle.api.plugins.JavaPlugin;
|
import org.gradle.api.plugins.JavaPlugin;
|
||||||
import org.gradle.api.tasks.TaskProvider;
|
import org.gradle.api.tasks.TaskProvider;
|
||||||
|
import org.gradle.jvm.tasks.Jar;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public abstract class JLinkPlugin implements Plugin<Project> {
|
public abstract class JLinkPlugin implements Plugin<Project> {
|
||||||
|
|
||||||
|
@ -15,30 +17,35 @@ public abstract class JLinkPlugin implements Plugin<Project> {
|
||||||
public void apply(Project project) {
|
public void apply(Project project) {
|
||||||
project.getPluginManager().apply(JavaPlugin.class);
|
project.getPluginManager().apply(JavaPlugin.class);
|
||||||
JLinkExtension extension = project.getExtensions().create("jlink", JLinkExtension.class);
|
JLinkExtension extension = project.getExtensions().create("jlink", JLinkExtension.class);
|
||||||
extension.modules.convention(List.of("java.base"));
|
extension.getModules().convention(List.of("java.base"));
|
||||||
extension.compress.convention(2);
|
extension.getCompress().convention(6); // zip-6, default
|
||||||
extension.stripDebug.convention(true);
|
extension.getStripDebug().convention(true);
|
||||||
extension.noHeaderFiles.convention(true);
|
extension.getNoHeaderFiles().convention(true);
|
||||||
extension.noManPages.convention(true);
|
extension.getNoManPages().convention(true);
|
||||||
extension.endian.convention(JLinkExtension.Endian.NATIVE);
|
extension.getEndian().convention(JLinkExtension.Endian.NATIVE);
|
||||||
TaskProvider<JLinkTask> jlinkTask = project.getTasks().register("jlink", JLinkTask.class);
|
TaskProvider<Jar> jarTask = project.getTasks().named("jar", Jar.class);
|
||||||
|
Objects.requireNonNull(jarTask);
|
||||||
|
TaskProvider<JModTask> jModTask = project.getTasks().register("jmod", JModTask.class);
|
||||||
|
project.getTasks().withType(JModTask.class).forEach(it -> {
|
||||||
|
it.dependsOn(jarTask);
|
||||||
|
});
|
||||||
|
Objects.requireNonNull(jModTask);
|
||||||
|
TaskProvider<JLinkTask> jLinkTask = project.getTasks().register("jlink", JLinkTask.class);
|
||||||
project.getTasks().withType(JLinkTask.class).forEach(it -> {
|
project.getTasks().withType(JLinkTask.class).forEach(it -> {
|
||||||
it.modules.set(extension.modules);
|
it.dependsOn(jModTask);
|
||||||
it.compress.set(extension.compress);
|
it.modules.set(extension.getModules());
|
||||||
it.stripDebug.set(extension.stripDebug);
|
it.compress.set(extension.getCompress());
|
||||||
it.noHeaderFiles.set(extension.noHeaderFiles);
|
it.stripDebug.set(extension.getStripDebug());
|
||||||
it.noManPages.set(extension.noManPages);
|
it.noHeaderFiles.set(extension.getNoHeaderFiles());
|
||||||
it.endian.set(extension.endian);
|
it.noManPages.set(extension.getNoManPages());
|
||||||
|
it.endian.set(extension.getEndian());
|
||||||
});
|
});
|
||||||
Configuration configuration = project.getConfigurations().create("jlink");
|
Configuration configuration = project.getConfigurations().create("jlink");
|
||||||
configuration.setCanBeConsumed(true);
|
configuration.setCanBeConsumed(true);
|
||||||
configuration.setCanBeResolved(false);
|
configuration.setCanBeResolved(false);
|
||||||
configuration.setVisible(false);
|
configuration.setVisible(false);
|
||||||
configuration.attributes(a -> {
|
configuration.attributes(a -> a.attribute(Usage.USAGE_ATTRIBUTE,
|
||||||
a.attribute(Usage.USAGE_ATTRIBUTE, project.getObjects().named(Usage.class, "jlink"));
|
project.getObjects().named(Usage.class, "jlink")));
|
||||||
});
|
configuration.outgoing(o -> o.artifact(jLinkTask.flatMap(t -> t.outputDirectory)));
|
||||||
configuration.outgoing(o -> {
|
|
||||||
o.artifact(jlinkTask.flatMap(t -> t.outputDirectory));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package org.xbib.gradle.plugin.jlink;
|
package org.xbib.gradle.plugin.jlink;
|
||||||
|
|
||||||
|
import org.gradle.api.file.Directory;
|
||||||
import org.gradle.api.file.DirectoryProperty;
|
import org.gradle.api.file.DirectoryProperty;
|
||||||
|
import org.gradle.api.logging.LogLevel;
|
||||||
import org.gradle.api.plugins.JavaPluginExtension;
|
import org.gradle.api.plugins.JavaPluginExtension;
|
||||||
import org.gradle.api.provider.ListProperty;
|
import org.gradle.api.provider.ListProperty;
|
||||||
import org.gradle.api.provider.Property;
|
import org.gradle.api.provider.Property;
|
||||||
|
@ -9,11 +11,14 @@ import org.gradle.api.tasks.AbstractExecTask;
|
||||||
import org.gradle.api.tasks.Input;
|
import org.gradle.api.tasks.Input;
|
||||||
import org.gradle.api.tasks.InputDirectory;
|
import org.gradle.api.tasks.InputDirectory;
|
||||||
import org.gradle.api.tasks.Nested;
|
import org.gradle.api.tasks.Nested;
|
||||||
|
import org.gradle.api.tasks.Optional;
|
||||||
import org.gradle.api.tasks.OutputDirectory;
|
import org.gradle.api.tasks.OutputDirectory;
|
||||||
|
import org.gradle.api.tasks.TaskProvider;
|
||||||
import org.gradle.jvm.toolchain.JavaCompiler;
|
import org.gradle.jvm.toolchain.JavaCompiler;
|
||||||
import org.gradle.jvm.toolchain.JavaToolchainService;
|
import org.gradle.jvm.toolchain.JavaToolchainService;
|
||||||
import org.gradle.jvm.toolchain.JavaToolchainSpec;
|
import org.gradle.jvm.toolchain.JavaToolchainSpec;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileVisitResult;
|
import java.nio.file.FileVisitResult;
|
||||||
|
@ -26,25 +31,32 @@ import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class JLinkTask extends AbstractExecTask<JLinkTask> {
|
public class JLinkTask extends AbstractExecTask<JLinkTask> {
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
Property<JavaCompiler> javaCompiler;
|
Property<JavaCompiler> javaCompiler;
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
|
@Optional
|
||||||
ListProperty<String> modules;
|
ListProperty<String> modules;
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
|
@Optional
|
||||||
Property<Integer> compress;
|
Property<Integer> compress;
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
|
@Optional
|
||||||
Property<Boolean> stripDebug;
|
Property<Boolean> stripDebug;
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
|
@Optional
|
||||||
Property<Boolean> noHeaderFiles;
|
Property<Boolean> noHeaderFiles;
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
|
@Optional
|
||||||
Property<Boolean> noManPages;
|
Property<Boolean> noManPages;
|
||||||
|
|
||||||
@Input
|
@Input
|
||||||
|
@Optional
|
||||||
Property<JLinkExtension.Endian> endian;
|
Property<JLinkExtension.Endian> endian;
|
||||||
|
|
||||||
@InputDirectory
|
@InputDirectory
|
||||||
|
@ -53,33 +65,54 @@ public class JLinkTask extends AbstractExecTask<JLinkTask> {
|
||||||
@OutputDirectory
|
@OutputDirectory
|
||||||
DirectoryProperty outputDirectory;
|
DirectoryProperty outputDirectory;
|
||||||
|
|
||||||
public JLinkTask(Class<JLinkTask> taskType) {
|
@Inject
|
||||||
super(taskType);
|
public JLinkTask() {
|
||||||
|
super(JLinkTask.class);
|
||||||
|
this.javaCompiler = getProject().getObjects().property(JavaCompiler.class);
|
||||||
|
this.modules = getProject().getObjects().listProperty(String.class);
|
||||||
|
this.compress = getProject().getObjects().property(Integer.class);
|
||||||
|
this.stripDebug = getProject().getObjects().property(Boolean.class);
|
||||||
|
this.noHeaderFiles = getProject().getObjects().property(Boolean.class);
|
||||||
|
this.noManPages = getProject().getObjects().property(Boolean.class);
|
||||||
|
this.endian = getProject().getObjects().property(JLinkExtension.Endian.class);
|
||||||
|
this.modulePath = getProject().getObjects().directoryProperty();
|
||||||
|
this.outputDirectory = getProject().getObjects().directoryProperty();
|
||||||
JavaToolchainSpec toolchain = getProject().getExtensions().getByType(JavaPluginExtension.class).getToolchain();
|
JavaToolchainSpec toolchain = getProject().getExtensions().getByType(JavaPluginExtension.class).getToolchain();
|
||||||
JavaToolchainService service = getProject().getExtensions().getByType(JavaToolchainService.class);
|
JavaToolchainService service = getProject().getExtensions().getByType(JavaToolchainService.class);
|
||||||
Provider<JavaCompiler> defaultJlinkTool = service.compilerFor(toolchain);
|
javaCompiler.convention(service.compilerFor(toolchain));
|
||||||
javaCompiler.convention(defaultJlinkTool);
|
|
||||||
modules.convention(List.of("java.base"));
|
modules.convention(List.of("java.base"));
|
||||||
modulePath.convention(javaCompiler.map(it -> it.getMetadata().getInstallationPath().dir("jmods")));
|
Provider<Directory> modulePathProvider = javaCompiler.map(it -> {
|
||||||
outputDirectory.convention(getProject().getLayout().getBuildDirectory().dir("jlink-jre"));
|
Directory jmods = it.getMetadata().getInstallationPath().dir("jmods");
|
||||||
|
if (jmods.getAsFile().exists()) {
|
||||||
|
return jmods;
|
||||||
|
} else {
|
||||||
|
getLogger().log(LogLevel.WARN, "directory " + jmods + " does not exist! Is jmods package installed?");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
modulePath.convention(modulePathProvider);
|
||||||
|
outputDirectory.convention(getProject().getLayout().getBuildDirectory().dir("jlink"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void exec() {
|
public void exec() {
|
||||||
setExecutable(javaCompiler.get().getMetadata().getInstallationPath().file("bin/jlink"));
|
setExecutable(javaCompiler.get().getMetadata().getInstallationPath().file("bin/jlink"));
|
||||||
File jlinkOutput = outputDirectory.dir("jre").get().getAsFile();
|
TaskProvider<JModTask> jmodTask = getProject().getTasks().named("jmod", JModTask.class);
|
||||||
|
File jlinkOutput = outputDirectory.dir("jlink-output").get().getAsFile();
|
||||||
try {
|
try {
|
||||||
delete(jlinkOutput.toPath());
|
createDirectory(jlinkOutput.toPath());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
List<String> args = new ArrayList<>(List.of(
|
List<String> args = new ArrayList<>(List.of(
|
||||||
"--module-path",
|
"--module-path",
|
||||||
modulePath.get().getAsFile().getAbsolutePath(),
|
modulePath.get().getAsFile().getAbsolutePath(),
|
||||||
|
"--module-path",
|
||||||
|
jmodTask.get().jmodFile.getAsFile().get().getAbsolutePath(),
|
||||||
"--add-modules",
|
"--add-modules",
|
||||||
String.join(",", modules.get()),
|
String.join(",", modules.get()),
|
||||||
"--compress",
|
"--compress",
|
||||||
"${compress.get()}",
|
"zip-" + compress.get(),
|
||||||
"--output",
|
"--output",
|
||||||
jlinkOutput.getAbsolutePath()
|
jlinkOutput.getAbsolutePath()
|
||||||
));
|
));
|
||||||
|
@ -97,22 +130,100 @@ public class JLinkTask extends AbstractExecTask<JLinkTask> {
|
||||||
args.add(endian.get().toString().toLowerCase(Locale.ROOT));
|
args.add(endian.get().toString().toLowerCase(Locale.ROOT));
|
||||||
}
|
}
|
||||||
setArgs(args);
|
setArgs(args);
|
||||||
|
System.err.println( "executing " + getExecutable() + " with " + args);
|
||||||
super.exec();
|
super.exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void delete(Path path) throws IOException {
|
public void setJavaCompiler(JavaCompiler javaCompiler) {
|
||||||
Files.walkFileTree(path, new SimpleFileVisitor<>() {
|
this.javaCompiler.set(javaCompiler);
|
||||||
@Override
|
}
|
||||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
|
|
||||||
Files.delete(dir);
|
|
||||||
return FileVisitResult.CONTINUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public Property<JavaCompiler> getJavaCompiler() {
|
||||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
return javaCompiler;
|
||||||
Files.delete(file);
|
}
|
||||||
return FileVisitResult.CONTINUE;
|
|
||||||
}
|
public void setModules(List<String> modules) {
|
||||||
});
|
this.modules.set(modules);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ListProperty<String> getModules() {
|
||||||
|
return modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCompress(Integer compress) {
|
||||||
|
this.compress.set(compress);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<Integer> getCompress() {
|
||||||
|
return compress;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStripDebug(Boolean stripDebug) {
|
||||||
|
this.stripDebug.set(stripDebug);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<Boolean> getStripDebug() {
|
||||||
|
return stripDebug;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNoHeaderFiles(Boolean noHeaderFiles) {
|
||||||
|
this.noHeaderFiles.set(noHeaderFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<Boolean> getNoHeaderFiles() {
|
||||||
|
return noHeaderFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNoManPages(Boolean noManPages) {
|
||||||
|
this.noManPages.set(noManPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<Boolean> getNoManPages() {
|
||||||
|
return noManPages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndian(JLinkExtension.Endian endian) {
|
||||||
|
this.endian.set(endian);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<JLinkExtension.Endian> getEndian() {
|
||||||
|
return endian;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModulePath(Directory modulePath) {
|
||||||
|
this.modulePath.set(modulePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DirectoryProperty getModulePath() {
|
||||||
|
return modulePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOutputDirectory(Directory outputDirectory) {
|
||||||
|
this.outputDirectory.set(outputDirectory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DirectoryProperty getOutputDirectory() {
|
||||||
|
return outputDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.delete(path);
|
||||||
|
}
|
||||||
|
// create only parent, jlink aborts if output directory exists
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
package org.xbib.gradle.plugin.jlink;
|
||||||
|
|
||||||
|
import org.gradle.api.file.RegularFile;
|
||||||
|
import org.gradle.api.file.RegularFileProperty;
|
||||||
|
import org.gradle.api.plugins.JavaPluginExtension;
|
||||||
|
import org.gradle.api.provider.Property;
|
||||||
|
import org.gradle.api.tasks.AbstractExecTask;
|
||||||
|
import org.gradle.api.tasks.InputFile;
|
||||||
|
import org.gradle.api.tasks.Nested;
|
||||||
|
import org.gradle.api.tasks.OutputFile;
|
||||||
|
import org.gradle.api.tasks.TaskProvider;
|
||||||
|
import org.gradle.jvm.tasks.Jar;
|
||||||
|
import org.gradle.jvm.toolchain.JavaCompiler;
|
||||||
|
import org.gradle.jvm.toolchain.JavaToolchainService;
|
||||||
|
import org.gradle.jvm.toolchain.JavaToolchainSpec;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class JModTask extends AbstractExecTask<JModTask> {
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
Property<JavaCompiler> javaCompiler;
|
||||||
|
|
||||||
|
@InputFile
|
||||||
|
RegularFileProperty jarFile;
|
||||||
|
|
||||||
|
@OutputFile
|
||||||
|
RegularFileProperty jmodFile;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public JModTask() {
|
||||||
|
super(JModTask.class);
|
||||||
|
javaCompiler = getProject().getObjects().property(JavaCompiler.class);
|
||||||
|
JavaToolchainSpec toolchain = getProject().getExtensions().getByType(JavaPluginExtension.class).getToolchain();
|
||||||
|
JavaToolchainService service = getProject().getExtensions().getByType(JavaToolchainService.class);
|
||||||
|
javaCompiler.convention(service.compilerFor(toolchain));
|
||||||
|
jarFile = getProject().getObjects().fileProperty();
|
||||||
|
TaskProvider<Jar> jarTask = getProject().getTasks().named("jar", Jar.class);
|
||||||
|
Objects.requireNonNull(jarTask);
|
||||||
|
jarFile.convention(jarTask.get().getArchiveFile());
|
||||||
|
jmodFile = getProject().getObjects().fileProperty();
|
||||||
|
jmodFile.convention(getProject().getLayout().getBuildDirectory()
|
||||||
|
.dir("jmod").get().file(getProject().getName() + ".jmod"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exec() {
|
||||||
|
setExecutable(javaCompiler.get().getMetadata().getInstallationPath().file("bin/jmod"));
|
||||||
|
try {
|
||||||
|
createDirectory(jmodFile.getAsFile().get().toPath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
List<String> args = new ArrayList<>(List.of(
|
||||||
|
"create",
|
||||||
|
"--class-path",
|
||||||
|
jarFile.get().getAsFile().getAbsolutePath(),
|
||||||
|
jmodFile.get().getAsFile().getAbsolutePath()
|
||||||
|
));
|
||||||
|
setArgs(args);
|
||||||
|
System.err.println( "executing " + getExecutable() + " with " + args);
|
||||||
|
super.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJavaCompiler(JavaCompiler javaCompiler) {
|
||||||
|
this.javaCompiler.set(javaCompiler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Property<JavaCompiler> getJavaCompiler() {
|
||||||
|
return javaCompiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJarFile(RegularFile jarFile) {
|
||||||
|
this.jarFile.set(jarFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegularFileProperty getJarFile() {
|
||||||
|
return jarFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setJmodFile(RegularFile jmodFile) {
|
||||||
|
this.jmodFile.set(jmodFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegularFileProperty getJmodFile() {
|
||||||
|
return jmodFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
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.delete(path);
|
||||||
|
}
|
||||||
|
// create only parent
|
||||||
|
Files.createDirectories(path.getParent());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,110 @@
|
||||||
|
package org.xbib.gradle.plugin.jlink
|
||||||
|
|
||||||
|
import org.gradle.testkit.runner.BuildResult
|
||||||
|
import org.gradle.testkit.runner.GradleRunner
|
||||||
|
|
||||||
|
class JLinkGradleBuild {
|
||||||
|
|
||||||
|
final File projectDir
|
||||||
|
final File settingsFile
|
||||||
|
final File appBuildFile
|
||||||
|
final File appModuleInfoFile
|
||||||
|
final File libBuildFile
|
||||||
|
final File libModuleInfoFile
|
||||||
|
|
||||||
|
final String gradleVersionUnderTest = System.getProperty('gradleVersionUnderTest')
|
||||||
|
|
||||||
|
JLinkGradleBuild() {
|
||||||
|
this.projectDir = createDirectory('build/jlink-gradle-build')
|
||||||
|
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')
|
||||||
|
settingsFile << '''
|
||||||
|
dependencyResolutionManagement { repositories.mavenCentral() }
|
||||||
|
includeBuild(".")
|
||||||
|
rootProject.name = "test-project"
|
||||||
|
include("app", "lib")
|
||||||
|
'''
|
||||||
|
appBuildFile << '''
|
||||||
|
plugins {
|
||||||
|
id("org.xbib.gradle.plugin.jlink")
|
||||||
|
}
|
||||||
|
group = "org.example"
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(21))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
tapFile("app/src/main/java/org/example/app/Main.java") << '''
|
||||||
|
package org.example.app;
|
||||||
|
public class Main {
|
||||||
|
public static void main(String... args) {
|
||||||
|
System.out.println("Hello world");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
tapFile("app/src/test/java/org/example/app/test/MainTest.java") << '''
|
||||||
|
package org.example.app.test;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.example.app.Main;
|
||||||
|
public class MainTest {
|
||||||
|
@Test
|
||||||
|
void testApp() {
|
||||||
|
Main main = new Main();
|
||||||
|
main.main();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
libBuildFile << '''
|
||||||
|
plugins {
|
||||||
|
id("org.xbib.gradle.plugin.jlink")
|
||||||
|
}
|
||||||
|
group = "org.example"
|
||||||
|
'''
|
||||||
|
}
|
||||||
|
|
||||||
|
static File createDirectory(String path) {
|
||||||
|
File f = new File(path)
|
||||||
|
if (f.exists()) {
|
||||||
|
f.deleteDir()
|
||||||
|
}
|
||||||
|
f.mkdirs()
|
||||||
|
f
|
||||||
|
}
|
||||||
|
|
||||||
|
File tapFile(String path) {
|
||||||
|
new File(projectDir, path).tap {
|
||||||
|
it.getParentFile().mkdirs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static boolean runsOnLinux() {
|
||||||
|
hostOs().contains('linux')
|
||||||
|
}
|
||||||
|
|
||||||
|
static String hostOs() {
|
||||||
|
System.getProperty("os.name").replace(" ", "").toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildResult build(taskToRun) {
|
||||||
|
runner(taskToRun).build()
|
||||||
|
}
|
||||||
|
|
||||||
|
BuildResult fail(taskToRun) {
|
||||||
|
runner(taskToRun).buildAndFail()
|
||||||
|
}
|
||||||
|
|
||||||
|
GradleRunner runner(String... args) {
|
||||||
|
GradleRunner.create()
|
||||||
|
.forwardOutput()
|
||||||
|
.withPluginClasspath()
|
||||||
|
.withProjectDir(projectDir)
|
||||||
|
.withArguments(Arrays.asList(args))
|
||||||
|
.with {
|
||||||
|
gradleVersionUnderTest ? it.withGradleVersion(gradleVersionUnderTest) : it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
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 JLinkTest extends Specification {
|
||||||
|
|
||||||
|
@Delegate
|
||||||
|
JLinkGradleBuild build = new JLinkGradleBuild()
|
||||||
|
|
||||||
|
def "can use jlink plugin with success=#success"() {
|
||||||
|
given:
|
||||||
|
def taskToRun = ":app:jlink"
|
||||||
|
appBuildFile << """
|
||||||
|
jlink {
|
||||||
|
modules.set(List.of("org.example.app"))
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
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()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue