Skip to content

Commit c2967bf

Browse files
committed
Support adding additional resources to app bundle
1 parent ab94c4f commit c2967bf

File tree

3 files changed

+86
-43
lines changed

3 files changed

+86
-43
lines changed

src/main/java/org/gradlex/javamodule/packaging/JavaModulePackagingExtension.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.gradle.api.attributes.LibraryElements;
2828
import org.gradle.api.attributes.Usage;
2929
import org.gradle.api.attributes.java.TargetJvmEnvironment;
30+
import org.gradle.api.file.ConfigurableFileCollection;
3031
import org.gradle.api.file.DirectoryProperty;
3132
import org.gradle.api.model.ObjectFactory;
3233
import org.gradle.api.plugins.ApplicationPlugin;
@@ -65,7 +66,8 @@ abstract public class JavaModulePackagingExtension {
6566
abstract public Property<String> getApplicationDescription();
6667
abstract public Property<String> getVendor();
6768
abstract public Property<String> getCopyright();
68-
abstract public DirectoryProperty getApplicationResources();
69+
abstract public DirectoryProperty getJpackageResources();
70+
abstract public ConfigurableFileCollection getResources();
6971

7072
@Inject
7173
abstract protected JavaToolchainService getJavaToolchains();
@@ -92,8 +94,6 @@ public void target(String label, Action<? super Target> action) {
9294
return Collections.emptyList();
9395
}));
9496

95-
96-
9797
ConfigurationContainer configurations = getProject().getConfigurations();
9898
SourceSetContainer sourceSets = getProject().getExtensions().getByType(SourceSetContainer.class);
9999

@@ -169,13 +169,14 @@ private void registerTargetSpecificTasks(Target target, String applicationJarTas
169169
t.getModulePath().from(runtimeClasspath);
170170

171171
t.getApplicationName().convention(getApplicationName());
172-
t.getApplicationResources().convention(getApplicationResources().dir(target.getOperatingSystem()));
172+
t.getJpackageResources().convention(getJpackageResources().dir(target.getOperatingSystem()));
173173
t.getApplicationDescription().convention(getApplicationDescription());
174174
t.getVendor().convention(getVendor());
175175
t.getCopyright().convention(getCopyright());
176176
t.getJavaOptions().convention(application.getApplicationDefaultJvmArgs());
177177
t.getOptions().convention(target.getOptions());
178178
t.getPackageTypes().convention(target.getPackageTypes());
179+
t.getResources().from(getResources());
179180

180181
t.getDestination().convention(getProject().getLayout().getBuildDirectory().dir("packages/" + target.getLabel()));
181182
});

src/main/java/org/gradlex/javamodule/packaging/JavaModulePackagingPlugin.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ public void apply(Project project) {
4343
JavaModulePackagingExtension javaModulePackaging = project.getExtensions().create("javaModulePackaging", JavaModulePackagingExtension.class);
4444
javaModulePackaging.getApplicationName().convention(project.getName());
4545
javaModulePackaging.getApplicationVersion().convention(project.provider(() -> (String) project.getVersion()));
46-
javaModulePackaging.getApplicationResources().convention(project.getLayout().getProjectDirectory().dir("resources"));
46+
javaModulePackaging.getJpackageResources().convention(project.getLayout().getProjectDirectory().dir("resources"));
4747
}
4848
}

src/main/java/org/gradlex/javamodule/packaging/tasks/Jpackage.java

Lines changed: 80 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.gradle.api.tasks.Classpath;
2828
import org.gradle.api.tasks.Input;
2929
import org.gradle.api.tasks.InputDirectory;
30+
import org.gradle.api.tasks.InputFiles;
3031
import org.gradle.api.tasks.Nested;
3132
import org.gradle.api.tasks.Optional;
3233
import org.gradle.api.tasks.OutputDirectory;
@@ -42,6 +43,9 @@
4243
import java.nio.file.Files;
4344
import java.security.MessageDigest;
4445
import java.security.NoSuchAlgorithmException;
46+
import java.util.Arrays;
47+
import java.util.List;
48+
import java.util.stream.Collectors;
4549

4650
import static java.util.Objects.requireNonNull;
4751
import static org.gradle.nativeplatform.OperatingSystemFamily.WINDOWS;
@@ -76,7 +80,11 @@ abstract public class Jpackage extends DefaultTask {
7680

7781
@InputDirectory
7882
@PathSensitive(PathSensitivity.RELATIVE)
79-
abstract public DirectoryProperty getApplicationResources();
83+
abstract public DirectoryProperty getJpackageResources();
84+
85+
@InputFiles
86+
@PathSensitive(PathSensitivity.RELATIVE)
87+
abstract public ConfigurableFileCollection getResources();
8088

8189
@Input
8290
@Optional
@@ -95,11 +103,9 @@ abstract public class Jpackage extends DefaultTask {
95103
@Input
96104
abstract public ListProperty<String> getPackageTypes();
97105

98-
99106
@OutputDirectory
100107
abstract public DirectoryProperty getDestination();
101108

102-
103109
@Inject
104110
abstract protected FileOperations getFiles();
105111

@@ -117,64 +123,100 @@ public void runJpackage() throws Exception {
117123

118124
validateHostSystem(arch, hostArch, os, hostOs);
119125

120-
Directory resourcesDir = getDestination().dir("additional-resources").get();
126+
Directory tmpDir = getDestination().dir("tmp").get();
127+
Directory resourcesDir = tmpDir.dir("jpackage-resources");
128+
Directory appImageParent = tmpDir.dir("app-image");
129+
//noinspection ResultOfMethodCallIgnored
130+
resourcesDir.getAsFile().mkdirs();
131+
121132
getFiles().copy(c -> {
122-
c.from(getApplicationResources());
133+
c.from(getJpackageResources());
123134
c.into(resourcesDir);
124135
c.rename(f -> f.replace("icon", getApplicationName().get()));
125136
});
126-
//noinspection ResultOfMethodCallIgnored
127-
resourcesDir.getAsFile().mkdirs(); // if no files were copied, make sure there is an empty directory
128137

129-
String executable = WINDOWS.equals(os) ? "bin/jpackage.exe" : "bin/jpackage";
138+
String executableName = WINDOWS.equals(os) ? "jpackage.exe" : "jpackage";
139+
String jpackage = getJavaInstallation().get().getInstallationPath().file("bin/" + executableName).getAsFile().getAbsolutePath();
140+
141+
// create app image folder
142+
getExec().exec(e -> {
143+
e.commandLine(
144+
jpackage,
145+
"--type",
146+
"app-image",
147+
"--module",
148+
getMainModule().get(),
149+
"--resource-dir",
150+
resourcesDir.getAsFile().getPath(),
151+
"--app-version",
152+
getVersion().get(),
153+
"--module-path",
154+
getModulePath().getAsPath(),
155+
"--name",
156+
getApplicationName().get(),
157+
"--dest",
158+
appImageParent.getAsFile().getPath()
159+
);
160+
if (getApplicationDescription().isPresent()) {
161+
e.args("--description", getApplicationDescription().get());
162+
}
163+
if (getVendor().isPresent()) {
164+
e.args("--vendor", getVendor().get());
165+
}
166+
if (getCopyright().isPresent()) {
167+
e.args("--copyright", getCopyright().get());
168+
}
169+
for (String option : getOptions().get()) {
170+
e.args(option);
171+
}
172+
for (String javaOption : getJavaOptions().get()) {
173+
e.args("--java-options", javaOption);
174+
}
175+
});
176+
177+
File appImageFolder = requireNonNull(appImageParent.getAsFile().listFiles())[0];
178+
File appResourcesFolder;
179+
if (os.contains("macos")) {
180+
appResourcesFolder = new File(appImageFolder, "Contents/app");
181+
} else if (os.contains("windows")) {
182+
appResourcesFolder = new File(appImageFolder, "app");
183+
} else {
184+
appResourcesFolder = new File(appImageFolder, "lib/app");
185+
}
186+
187+
// copy additional resource into app-image folder
188+
getFiles().copy(c -> {
189+
c.from(getResources());
190+
c.into(appResourcesFolder);
191+
});
192+
193+
// package with additional resources
130194
getPackageTypes().get().forEach(packageType ->
131195
getExec().exec(e -> {
132196
e.commandLine(
133-
getJavaInstallation().get().getInstallationPath().file(executable).getAsFile().getAbsolutePath(),
197+
jpackage,
134198
"--type",
135199
packageType,
136-
"--module",
137-
getMainModule().get(),
138-
"--resource-dir",
139-
resourcesDir,
140-
"--app-version",
141-
getVersion().get(),
142-
"--module-path",
143-
getModulePath().getAsPath(),
144-
"--name",
145-
getApplicationName().get(),
200+
"--app-image",
201+
appImageFolder.getPath(),
146202
"--dest",
147203
getDestination().get().getAsFile().getPath()
148204
);
149-
if (getApplicationDescription().isPresent()) {
150-
e.args("--description", getApplicationDescription().get());
151-
}
152-
if (getVendor().isPresent()) {
153-
e.args("--vendor", getVendor().get());
154-
}
155-
if (getCopyright().isPresent()) {
156-
e.args("--copyright", getCopyright().get());
157-
}
158-
for (String option : getOptions().get()) {
159-
e.args(option);
160-
}
161-
for (String javaOption : getJavaOptions().get()) {
162-
e.args("--java-options", javaOption);
163-
}
164205
})
165206
);
166207

167-
getFiles().delete(resourcesDir);
208+
// getFiles().delete(tmpDir);
168209

169210
generateChecksums();
170211
}
171212

172213
private void generateChecksums() throws NoSuchAlgorithmException, IOException {
173-
File dest = getDestination().get().getAsFile();
174-
for (File result : requireNonNull(dest.listFiles())) {
214+
File destination = getDestination().get().getAsFile();
215+
List<File> allFiles = Arrays.stream(requireNonNull(destination.listFiles())).filter(File::isFile).collect(Collectors.toList());
216+
for (File result : allFiles) {
175217
MessageDigest digest = MessageDigest.getInstance("SHA-256");
176218
byte[] encoded = digest.digest(Files.readAllBytes(result.toPath()));
177-
Files.write(new File(dest, result.getName() + ".sha256").toPath(), bytesToHex(encoded).getBytes());
219+
Files.write(new File(destination, result.getName() + ".sha256").toPath(), bytesToHex(encoded).getBytes());
178220
}
179221
}
180222

0 commit comments

Comments
 (0)