Skip to content

Commit

Permalink
Merge pull request rockcrafters#12 from vpa1977/beryx-gradle
Browse files Browse the repository at this point in the history
feat: beryx jlink plugin support for gradle
  • Loading branch information
vpa1977 authored Oct 8, 2024
2 parents b9fa545 + 1b23bce commit 25f7023
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

import com.canonical.rockcraft.builder.RockCrafter;
import com.canonical.rockcraft.builder.RockcraftOptions;
import org.gradle.api.Task;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.tasks.TaskAction;

Expand All @@ -24,6 +25,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/**
* This task writes <i>rockcraft.yaml</i> file for the application.
Expand All @@ -43,12 +45,15 @@ public CreateRockcraftTask(RockcraftOptions options) {
/**
* Task action to write <i>rockcraft.yaml</i>
*/
@SuppressWarnings("unchecked")
@TaskAction
public void writeRockcraft() {
HashSet<File> artifacts = new HashSet<File>();
for (Configuration conf : getProject().getConfigurations()) {
for (File f : conf.getArtifacts().getFiles().getFiles()){
if (f.getName().endsWith("jar"))
Set<Object> dependsOn = getDependsOn();
for (Object entry : dependsOn) {
HashSet<Task> tasks = (HashSet<Task>) entry;
for (Task task : tasks) {
for (File f : task.getOutputs().getFiles().getFiles())
artifacts.add(f);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.canonical.rockcraft.gradle;

public interface ITaskNames {
public String JAR = "jar";
public String BOOT_JAR = "bootJar";
public String JLINK = "jlink";
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class RockSettingsFactory {
public static final RockProjectSettings createRockProjectSettings(Project project) {
return new RockProjectSettings("gradle", project.getName(),
String.valueOf(project.getVersion()), project.getProjectDir().toPath(),
project.getLayout().getBuildDirectory().getAsFile().get().toPath());
project.getLayout().getBuildDirectory().getAsFile().get().toPath(),
!project.getTasksByName(ITaskNames.JLINK, false).isEmpty());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,11 @@ public void apply(Project project) {
for (Task t : buildTasks)
t.finalizedBy(checkTask);

Set<Task> tasks = project.getTasksByName("bootJar", false);
Set<Task> tasks = project.getTasksByName(ITaskNames.JLINK, false);
if (tasks.isEmpty())
tasks = project.getTasksByName("jar", false);
tasks = project.getTasksByName(ITaskNames.BOOT_JAR, false);
if (tasks.isEmpty())
tasks = project.getTasksByName(ITaskNames.JAR, false);
if (tasks.isEmpty())
throw new UnsupportedOperationException("Rockcraft plugin requires bootJar or jar task");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ TaskOutcome getLastTaskOutcome(BuildResult r){

@BeforeEach
protected void setUp() throws IOException {
assertTrue(Paths.get(projectDir.getAbsolutePath(), "src", "main", "java").toFile().mkdirs());
assertTrue(getJavaSource().getParentFile().mkdirs());
writeString(getJavaSource(), getResource("default-test.in"));
writeString(getSettingsFile(), "");
writeString(getBuildFile(), getResource("default-build.in"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.canonical.rockcraft.gradle;

import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.TaskOutcome;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.yaml.snakeyaml.Yaml;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Map;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class BeryxJLinkTest extends BaseRockcraftTest {

protected File getJavaSource() {
return Paths.get(projectDir.getAbsolutePath(), "src", "main", "java", "beryxtest", "Test.java").toFile();
}

@BeforeEach
public void setUp() throws IOException {
super.setUp();
writeString(getJavaSource(), getResource("beryx-test-class.in"));
writeString(getBuildFile(), getResource("beryx-project-build.in"));
writeString(Paths.get(projectDir.getAbsolutePath(), "src", "main", "java", "module-info.java").toFile(),
getResource("beryx-module-info.in"));
}

/**
* Integration test - the rock should build successfully
*
* @throws IOException
*/
@Test
public void testBeryxJlinkBuild() throws IOException {
BuildResult result = runBuild("build-rock", "--stacktrace");
assertEquals(TaskOutcome.SUCCESS, getLastTaskOutcome(result)); // the build needs to succeed
}

@SuppressWarnings("unchecked")
@Test
public void testBeryxJlinkRockcraft() throws IOException {
BuildResult result = runBuild("create-rock", "--stacktrace");
assertEquals(TaskOutcome.SUCCESS, getLastTaskOutcome(result)); // the build needs to succeed
try (FileInputStream is = new FileInputStream(Paths.get(getProjectDir().getAbsolutePath(), "build", "rockcraft.yaml").toFile())) {
Yaml yaml = new Yaml();
Map<String, Object> parsed = yaml.load(is);
Map<String, Object> services = (Map<String, Object>)parsed.get("services");
assertTrue(services.containsKey("hello"));
Map<String, Object> helloService =(Map<String, Object>)services.get("hello");
assertEquals("/image/bin/hello", helloService.get("command"));

Map<String, Object> parts = (Map<String, Object>)parsed.get("parts");
Map<String, Object> dump0 = (Map<String, Object>)parts.get("gradle/rockcraft/dump0");
String overrideBuild = (String) dump0.get("override-build");
assertEquals("cp --archive --link --no-dereference image /", overrideBuild);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module test {
exports beryxtest;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
plugins {
id('java')
id('org.beryx.jlink') version "2.24.1"
id('io.rockcrafters.rockcraft')
}
version = 0.01

java.toolchain.languageVersion = JavaLanguageVersion.of(17)

jar {
manifest {
attributes 'Main-Class': 'beryxtest.Test'
}
}

jlink {
mainClass = 'beryxtest.Test'
mergedModule {
requires 'java.naming'
requires 'java.xml'
}
launcher {
name = 'hello'
}
}

rockcraft {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package beryxtest;

public class Test {
public static void main(String[] args) {
System.out.println("Hello!");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@ plugins {
id('application')
id('io.rockcrafters.rockcraft')
}

jar {
manifest {
attributes 'Main-Class': 'Test'
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class RockSettingsFactory {
public static final RockProjectSettings createRockProjectSettings(MavenProject project) {
return new RockProjectSettings("maven", project.getName(),
project.getVersion(), project.getBasedir().getAbsoluteFile().toPath(),
project.getArtifact().getFile().getParentFile().toPath());
project.getArtifact().getFile().getParentFile().toPath(),
false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand Down Expand Up @@ -77,12 +74,11 @@ protected String createRockcraft(Path root, List<File> files) throws IOException
continue;
filtered.add(file);
}
List<String> relativeJars = new ArrayList<String>();
List<String> relativeOutputs = new ArrayList<String>();
for (File file : filtered) {
relativeJars.add(root.relativize(file.toPath()).toString());
relativeOutputs.add(root.relativize(file.toPath()).toString());
}


HashMap<String, Object> rockcraft = new HashMap<String, Object>();
rockcraft.put(IRockcraftNames.ROCKCRAFT_NAME, settings.getName());
rockcraft.put(IRockcraftNames.ROCKCRAFT_VERSION, String.valueOf(settings.getVersion()));
Expand Down Expand Up @@ -110,19 +106,71 @@ protected String createRockcraft(Path root, List<File> files) throws IOException
yamlOutput.append("\n");
rockcraft.clear();

rockcraft.put("services", getProjectService(relativeJars));
if (settings.getBeryxJLink()) {
rockcraft.put("services", getImageProjectService(root, filtered));
} else {
rockcraft.put("services", getProjectService(relativeOutputs));
}

yamlOutput.append(yaml.dump(rockcraft));
yamlOutput.append("\n");
rockcraft.clear();

rockcraft.put("parts", getProjectParts(filtered, relativeJars));
if (settings.getBeryxJLink()) {
rockcraft.put("parts", getImageProjectParts(relativeOutputs));
} else {
rockcraft.put("parts", getProjectParts(filtered, relativeOutputs));
}

yamlOutput.append(yaml.dump(rockcraft));
yamlOutput.append("\n");
rockcraft.clear();

return yamlOutput.toString();
}

private Map<String,Object> getImageProjectParts(List<String> images) {
HashMap<String, Object> parts = new HashMap<String, Object>();
int id = 0;
for (String image : images) {
parts.put(String.format("%s/rockcraft/dump%d",settings.getGeneratorName(), id), getImageDumpPart(image));
++id;
}
parts.put(String.format("%s/rockcraft/deps", settings.getGeneratorName()) , getDepsPart());
return parts;
}

private Map<String,Object> getImageDumpPart(String image) {
Map<String,Object> part = new HashMap<String, Object>();
part.put("source", ".");
part.put("plugin", "nil");
part.put("override-build", String.format("cp --archive --link --no-dereference %s /", image));
return part;
}

private Map<String,Object> getImageProjectService(Path root, List<File> images) {
Map<String,Object> services = new HashMap<String,Object>();
for (File image : images) {
// workaround - read names of the .bat files to discover available launchers
File[] launchers = new File(image, "bin").listFiles(new FilenameFilter() {
@Override
public boolean accept(File file, String name) {
return name.endsWith(".bat");
}
});
for (File launcher : launchers) {
String serviceName = launcher.getName().split("\\.")[0];
Path relativeImage = root.relativize(Paths.get(image.getAbsolutePath()));
Map<String, Object> serviceDefinition = new HashMap<String, Object>();
serviceDefinition.put("override", "replace");
serviceDefinition.put("summary", serviceName);
serviceDefinition.put("command", String.format("/%s/bin/%s", relativeImage, serviceName));
services.put(serviceName, serviceDefinition);
}
}
return services;
}

private Map<String, Object> getPlatforms() {
HashMap<String, Object> archs = new HashMap<String, Object>();
for (RockcraftOptions.RockArchitecture a : getOptions().getArchitectures())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class RockProjectSettings {
private final Path projectPath;
private final String generatorName;
private final Path rockOutput;
private final boolean beryxJlink;

/**
* Constructs the rock project settings
Expand All @@ -21,12 +22,13 @@ public class RockProjectSettings {
* @param projectPath path to the rockcraft project
* @param rockOutput path to where to generate rockcraft.yaml
*/
public RockProjectSettings(String generatorName, String name, String version, Path projectPath, Path rockOutput) {
public RockProjectSettings(String generatorName, String name, String version, Path projectPath, Path rockOutput, boolean beryxJlink) {
this.generatorName = generatorName;
this.name = name;
this.version = version;
this.projectPath = projectPath;
this.rockOutput = rockOutput;
this.beryxJlink = beryxJlink;
}

/**
Expand Down Expand Up @@ -72,4 +74,10 @@ public Path getRockOutput() {
return rockOutput;
}

/**
* Get Beryx jlink plugin
*
* @return use Beryx Jlink plugin
*/
public boolean getBeryxJLink() { return beryxJlink; }
}

0 comments on commit 25f7023

Please sign in to comment.