mirror of
https://github.com/openjdk/jdk.git
synced 2026-03-14 18:03:44 +00:00
8370969: --launcher-as-service option is ignored when used with --app-image option
Reviewed-by: almatvee
This commit is contained in:
parent
13b3d2fca1
commit
f7f4f903cf
@ -67,6 +67,7 @@ import jdk.jpackage.internal.model.Application;
|
||||
import jdk.jpackage.internal.model.ApplicationLaunchers;
|
||||
import jdk.jpackage.internal.model.ApplicationLayout;
|
||||
import jdk.jpackage.internal.model.ConfigException;
|
||||
import jdk.jpackage.internal.model.ExternalApplication;
|
||||
import jdk.jpackage.internal.model.ExternalApplication.LauncherInfo;
|
||||
import jdk.jpackage.internal.model.Launcher;
|
||||
import jdk.jpackage.internal.model.LauncherShortcut;
|
||||
@ -116,7 +117,7 @@ final class FromParams {
|
||||
if (hasPredefinedAppImage(params)) {
|
||||
final var appImageFile = PREDEFINED_APP_IMAGE_FILE.fetchFrom(params);
|
||||
appBuilder.initFromExternalApplication(appImageFile, launcherInfo -> {
|
||||
var launcherParams = mapLauncherInfo(launcherInfo);
|
||||
var launcherParams = mapLauncherInfo(appImageFile, launcherInfo);
|
||||
return launcherMapper.apply(mergeParams(params, launcherParams));
|
||||
});
|
||||
} else {
|
||||
@ -220,10 +221,14 @@ final class FromParams {
|
||||
return new ApplicationLaunchers(mainLauncher, additionalLaunchers);
|
||||
}
|
||||
|
||||
private static Map<String, ? super Object> mapLauncherInfo(LauncherInfo launcherInfo) {
|
||||
private static Map<String, ? super Object> mapLauncherInfo(ExternalApplication appImageFile, LauncherInfo launcherInfo) {
|
||||
Map<String, ? super Object> launcherParams = new HashMap<>();
|
||||
launcherParams.put(NAME.getID(), launcherInfo.name());
|
||||
launcherParams.put(LAUNCHER_AS_SERVICE.getID(), Boolean.toString(launcherInfo.service()));
|
||||
if (!appImageFile.getLauncherName().equals(launcherInfo.name())) {
|
||||
// This is not the main launcher, accept the value
|
||||
// of "launcher-as-service" from the app image file (.jpackage.xml).
|
||||
launcherParams.put(LAUNCHER_AS_SERVICE.getID(), Boolean.toString(launcherInfo.service()));
|
||||
}
|
||||
launcherParams.putAll(launcherInfo.extra());
|
||||
return launcherParams;
|
||||
}
|
||||
|
||||
@ -101,6 +101,11 @@ public final class AdditionalLauncher {
|
||||
return this;
|
||||
}
|
||||
|
||||
public AdditionalLauncher removeProperty(String name) {
|
||||
rawProperties.remove(Objects.requireNonNull(name));
|
||||
return this;
|
||||
}
|
||||
|
||||
public AdditionalLauncher setShortcuts(boolean menu, boolean desktop) {
|
||||
if (TKit.isLinux()) {
|
||||
setShortcut(LINUX_SHORTCUT, desktop);
|
||||
|
||||
@ -22,7 +22,6 @@
|
||||
*/
|
||||
package jdk.jpackage.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
@ -34,6 +33,7 @@ import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.jpackage.internal.util.function.ThrowingFunction;
|
||||
|
||||
|
||||
public final class CfgFile {
|
||||
@ -116,7 +116,7 @@ public final class CfgFile {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CfgFile load(Path path) throws IOException {
|
||||
public static CfgFile load(Path path) {
|
||||
TKit.trace(String.format("Read [%s] jpackage cfg file", path));
|
||||
|
||||
final Pattern sectionBeginRegex = Pattern.compile( "\\s*\\[([^]]*)\\]\\s*");
|
||||
@ -126,7 +126,7 @@ public final class CfgFile {
|
||||
|
||||
String currentSectionName = null;
|
||||
List<Map.Entry<String, String>> currentSection = new ArrayList<>();
|
||||
for (String line : Files.readAllLines(path)) {
|
||||
for (String line : ThrowingFunction.<Path, List<String>>toFunction(Files::readAllLines).apply(path)) {
|
||||
Matcher matcher = sectionBeginRegex.matcher(line);
|
||||
if (matcher.find()) {
|
||||
if (currentSectionName != null) {
|
||||
|
||||
@ -29,7 +29,6 @@ import static jdk.jpackage.test.ApplicationLayout.platformAppImage;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
@ -214,22 +213,9 @@ final class ConfigFilesStasher {
|
||||
}
|
||||
|
||||
private static boolean isWithServices(JPackageCommand cmd) {
|
||||
boolean[] withServices = new boolean[1];
|
||||
withServices[0] = cmd.hasArgument("--launcher-as-service");
|
||||
if (!withServices[0]) {
|
||||
AdditionalLauncher.forEachAdditionalLauncher(cmd, (launcherName, propertyFilePath) -> {
|
||||
try {
|
||||
final var launcherAsService = new AdditionalLauncher.PropertyFile(propertyFilePath)
|
||||
.findBooleanProperty("launcher-as-service").orElse(false);
|
||||
if (launcherAsService) {
|
||||
withServices[0] = true;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
return withServices[0];
|
||||
return cmd.launcherNames(true).stream().anyMatch(launcherName -> {
|
||||
return LauncherAsServiceVerifier.launcherAsService(cmd, launcherName);
|
||||
});
|
||||
}
|
||||
|
||||
private static List<String> listAppImage(Path to) {
|
||||
|
||||
@ -39,6 +39,7 @@ import java.nio.file.Path;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
@ -573,6 +574,24 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
return appLayout().runtimeDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the main launcher. It will read the name of the main
|
||||
* launcher from the external app image if such is specified.
|
||||
*
|
||||
* @return the name of the main launcher
|
||||
*
|
||||
* @throws IllegalArgumentException if the command is configured for packaging
|
||||
* Java runtime
|
||||
*/
|
||||
public String mainLauncherName() {
|
||||
verifyNotRuntime();
|
||||
return name();
|
||||
}
|
||||
|
||||
boolean isMainLauncher(String launcherName) {
|
||||
return launcherName == null || mainLauncherName().equals(launcherName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns path for application launcher with the given name.
|
||||
*
|
||||
@ -589,7 +608,7 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
public Path appLauncherPath(String launcherName) {
|
||||
verifyNotRuntime();
|
||||
if (launcherName == null) {
|
||||
launcherName = name();
|
||||
launcherName = mainLauncherName();
|
||||
}
|
||||
|
||||
if (TKit.isWindows()) {
|
||||
@ -607,15 +626,54 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns names of all additional launchers or empty list if none
|
||||
* configured.
|
||||
* Returns names of additional launchers or an empty list if none configured.
|
||||
* <p>
|
||||
* If {@code lookupInPrederfinedAppImage} is {@code true} and the command is
|
||||
* configured with an external app image, it will read names of the additional
|
||||
* launchers from the external app image.
|
||||
*
|
||||
* @param lookupInPrederfinedAppImage if to read names of additional launchers
|
||||
* from an external app image
|
||||
*
|
||||
* @return the names of additional launchers
|
||||
*/
|
||||
public List<String> addLauncherNames() {
|
||||
public List<String> addLauncherNames(boolean lookupInPrederfinedAppImage) {
|
||||
if (isRuntime()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<String> names = new ArrayList<>();
|
||||
if (lookupInPrederfinedAppImage) {
|
||||
Optional.ofNullable(getArgumentValue("--app-image"))
|
||||
.map(Path::of)
|
||||
.map(AppImageFile::load)
|
||||
.map(AppImageFile::addLaunchers)
|
||||
.map(Map::keySet)
|
||||
.ifPresent(names::addAll);
|
||||
}
|
||||
forEachAdditionalLauncher(this, (launcherName, propFile) -> {
|
||||
names.add(launcherName);
|
||||
});
|
||||
return names;
|
||||
return Collections.unmodifiableList(names);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns names of all launchers.
|
||||
* <p>
|
||||
* If the list is not empty, the first element is {@code null} referencing the
|
||||
* main launcher. In the case of runtime packaging, the list is empty.
|
||||
*
|
||||
* @return the names of all launchers
|
||||
*/
|
||||
public List<String> launcherNames(boolean lookupInPrederfinedAppImage) {
|
||||
if (isRuntime()) {
|
||||
return List.of();
|
||||
}
|
||||
|
||||
List<String> names = new ArrayList<>();
|
||||
names.add(null);
|
||||
names.addAll(addLauncherNames(lookupInPrederfinedAppImage));
|
||||
return Collections.unmodifiableList(names);
|
||||
}
|
||||
|
||||
private void verifyNotRuntime() {
|
||||
@ -639,7 +697,7 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
public Path appLauncherCfgPath(String launcherName) {
|
||||
verifyNotRuntime();
|
||||
if (launcherName == null) {
|
||||
launcherName = name();
|
||||
launcherName = mainLauncherName();
|
||||
}
|
||||
return appLayout().appDirectory().resolve(launcherName + ".cfg");
|
||||
}
|
||||
@ -1244,7 +1302,7 @@ public class JPackageCommand extends CommandArguments<JPackageCommand> {
|
||||
// a predefined app image.
|
||||
if (!hasArgument("--app-image")) {
|
||||
TKit.assertStringListEquals(
|
||||
addLauncherNames().stream().sorted().toList(),
|
||||
addLauncherNames(false).stream().sorted().toList(),
|
||||
aif.addLaunchers().keySet().stream().sorted().toList(),
|
||||
"Check additional launcher names");
|
||||
}
|
||||
|
||||
@ -22,20 +22,19 @@
|
||||
*/
|
||||
package jdk.jpackage.test;
|
||||
|
||||
import static jdk.jpackage.internal.util.function.ThrowingBiConsumer.toBiConsumer;
|
||||
import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer;
|
||||
import static jdk.jpackage.test.AdditionalLauncher.forEachAdditionalLauncher;
|
||||
import static jdk.jpackage.test.PackageType.LINUX;
|
||||
import static jdk.jpackage.test.PackageType.MAC_PKG;
|
||||
import static jdk.jpackage.test.PackageType.WINDOWS;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.FileSystemException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@ -44,8 +43,8 @@ import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.jpackage.internal.util.PathUtils;
|
||||
import jdk.jpackage.internal.util.function.ThrowingFunction;
|
||||
import jdk.jpackage.internal.util.function.ThrowingRunnable;
|
||||
import jdk.jpackage.test.AdditionalLauncher.PropertyFile;
|
||||
import jdk.jpackage.test.LauncherVerifier.Action;
|
||||
|
||||
public final class LauncherAsServiceVerifier {
|
||||
@ -67,26 +66,56 @@ public final class LauncherAsServiceVerifier {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAppOutputFileNamePrefix(String v) {
|
||||
appOutputFileNamePrefix = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder appendAppOutputFileNamePrefix(String v) {
|
||||
return setAppOutputFileNamePrefix(appOutputFileNamePrefix() + Objects.requireNonNull(v));
|
||||
}
|
||||
|
||||
public Builder setAppOutputFileNamePrefixToAppName() {
|
||||
return setAppOutputFileNamePrefix(TKit.getCurrentDefaultAppName());
|
||||
}
|
||||
|
||||
public Builder setAdditionalLauncherCallback(Consumer<AdditionalLauncher> v) {
|
||||
additionalLauncherCallback = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LauncherAsServiceVerifier create() {
|
||||
Objects.requireNonNull(expectedValue);
|
||||
return new LauncherAsServiceVerifier(launcherName, appOutputFileName,
|
||||
expectedValue,
|
||||
launcherName != null ? additionalLauncherCallback : null);
|
||||
public Builder mutate(Consumer<Builder> mutator) {
|
||||
mutator.accept(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder applyTo(PackageTest pkg) {
|
||||
create().applyTo(pkg);
|
||||
public LauncherAsServiceVerifier create() {
|
||||
Objects.requireNonNull(expectedValue);
|
||||
return new LauncherAsServiceVerifier(
|
||||
launcherName,
|
||||
appOutputFileNamePrefix()
|
||||
+ Optional.ofNullable(appOutputFileName).orElse("launcher-as-service.txt"),
|
||||
expectedValue,
|
||||
Optional.ofNullable(additionalLauncherCallback));
|
||||
}
|
||||
|
||||
public Builder applyTo(PackageTest test) {
|
||||
return applyTo(new ConfigurationTarget(test));
|
||||
}
|
||||
|
||||
public Builder applyTo(ConfigurationTarget target) {
|
||||
create().applyTo(target);
|
||||
return this;
|
||||
}
|
||||
|
||||
private String appOutputFileNamePrefix() {
|
||||
return Optional.ofNullable(appOutputFileNamePrefix).orElse("");
|
||||
}
|
||||
|
||||
private String launcherName;
|
||||
private String expectedValue;
|
||||
private String appOutputFileName = "launcher-as-service.txt";
|
||||
private String appOutputFileName;
|
||||
private String appOutputFileNamePrefix;
|
||||
private Consumer<AdditionalLauncher> additionalLauncherCallback;
|
||||
}
|
||||
|
||||
@ -97,41 +126,50 @@ public final class LauncherAsServiceVerifier {
|
||||
private LauncherAsServiceVerifier(String launcherName,
|
||||
String appOutputFileName,
|
||||
String expectedArgValue,
|
||||
Consumer<AdditionalLauncher> additionalLauncherCallback) {
|
||||
this.expectedValue = expectedArgValue;
|
||||
Optional<Consumer<AdditionalLauncher>> additionalLauncherCallback) {
|
||||
|
||||
if (launcherName == null && additionalLauncherCallback.isPresent()) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
this.expectedValue = Objects.requireNonNull(expectedArgValue);
|
||||
this.launcherName = launcherName;
|
||||
this.appOutputFileName = Path.of(appOutputFileName);
|
||||
this.additionalLauncherCallback = additionalLauncherCallback;
|
||||
}
|
||||
|
||||
public void applyTo(PackageTest pkg) {
|
||||
public void applyTo(ConfigurationTarget target) {
|
||||
if (launcherName == null) {
|
||||
pkg.forTypes(WINDOWS, () -> {
|
||||
pkg.addInitializer(cmd -> {
|
||||
// Remove parameter added to jpackage command line in HelloApp.addTo()
|
||||
cmd.removeArgument("--win-console");
|
||||
});
|
||||
target.addInitializer(cmd -> {
|
||||
// Remove parameter added to jpackage command line in HelloApp.addTo()
|
||||
cmd.removeArgument("--win-console");
|
||||
});
|
||||
applyToMainLauncher(pkg);
|
||||
applyToMainLauncher(target);
|
||||
} else {
|
||||
applyToAdditionalLauncher(pkg);
|
||||
applyToAdditionalLauncher(target);
|
||||
}
|
||||
pkg.addInstallVerifier(this::verifyLauncherExecuted);
|
||||
target.test().ifPresent(pkg -> {
|
||||
pkg.addInstallVerifier(this::verifyLauncherExecuted);
|
||||
});
|
||||
}
|
||||
|
||||
static void verify(JPackageCommand cmd) {
|
||||
cmd.verifyIsOfType(SUPPORTED_PACKAGES);
|
||||
|
||||
var launcherNames = getLaunchersAsServices(cmd);
|
||||
var partitionedLauncherNames = partitionLaunchers(cmd);
|
||||
|
||||
launcherNames.forEach(toConsumer(launcherName -> {
|
||||
verify(cmd, launcherName);
|
||||
}));
|
||||
var launcherAsServiceNames = partitionedLauncherNames.get(true);
|
||||
|
||||
for (var launcherAsService : List.of(true, false)) {
|
||||
partitionedLauncherNames.get(launcherAsService).forEach(launcherName -> {
|
||||
verify(cmd, launcherName, launcherAsService);
|
||||
});
|
||||
}
|
||||
|
||||
if (WINDOWS.contains(cmd.packageType()) && !cmd.isRuntime()) {
|
||||
Path serviceInstallerPath = cmd.appLayout().launchersDirectory().resolve(
|
||||
"service-installer.exe");
|
||||
if (launcherNames.isEmpty()) {
|
||||
if (launcherAsServiceNames.isEmpty()) {
|
||||
TKit.assertPathExists(serviceInstallerPath, false);
|
||||
} else {
|
||||
TKit.assertFileExists(serviceInstallerPath);
|
||||
@ -146,16 +184,16 @@ public final class LauncherAsServiceVerifier {
|
||||
|
||||
if (cmd.isPackageUnpacked()) {
|
||||
servicesSpecificFolders.add(MacHelper.getServicePlistFilePath(
|
||||
cmd, null).getParent());
|
||||
cmd, "foo").getParent());
|
||||
}
|
||||
} else if (LINUX.contains(cmd.packageType())) {
|
||||
if (cmd.isPackageUnpacked()) {
|
||||
servicesSpecificFolders.add(LinuxHelper.getServiceUnitFilePath(
|
||||
cmd, null).getParent());
|
||||
cmd, "foo").getParent());
|
||||
}
|
||||
}
|
||||
|
||||
if (launcherNames.isEmpty() || cmd.isRuntime()) {
|
||||
if (launcherAsServiceNames.isEmpty() || cmd.isRuntime()) {
|
||||
servicesSpecificFiles.forEach(path -> TKit.assertPathExists(path,
|
||||
false));
|
||||
servicesSpecificFolders.forEach(path -> TKit.assertPathExists(path,
|
||||
@ -187,22 +225,46 @@ public final class LauncherAsServiceVerifier {
|
||||
}
|
||||
|
||||
static List<String> getLaunchersAsServices(JPackageCommand cmd) {
|
||||
List<String> launcherNames = new ArrayList<>();
|
||||
|
||||
if (cmd.hasArgument("--launcher-as-service")) {
|
||||
launcherNames.add(null);
|
||||
}
|
||||
|
||||
forEachAdditionalLauncher(cmd, toBiConsumer((launcherName, propFilePath) -> {
|
||||
if (new PropertyFile(propFilePath).findBooleanProperty("launcher-as-service").orElse(false)) {
|
||||
launcherNames.add(launcherName);
|
||||
}
|
||||
}));
|
||||
|
||||
return launcherNames;
|
||||
return Objects.requireNonNull(partitionLaunchers(cmd).get(true));
|
||||
}
|
||||
|
||||
private boolean canVerifyInstall(JPackageCommand cmd) throws IOException {
|
||||
private static Map<Boolean, List<String>> partitionLaunchers(JPackageCommand cmd) {
|
||||
if (cmd.isRuntime()) {
|
||||
return Map.of(true, List.of(), false, List.of());
|
||||
} else {
|
||||
return cmd.launcherNames(true).stream().collect(Collectors.partitioningBy(launcherName -> {
|
||||
return launcherAsService(cmd, launcherName);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
static boolean launcherAsService(JPackageCommand cmd, String launcherName) {
|
||||
if (cmd.isMainLauncher(launcherName)) {
|
||||
return PropertyFinder.findLauncherProperty(cmd, null,
|
||||
PropertyFinder.cmdlineBooleanOption("--launcher-as-service"),
|
||||
PropertyFinder.nop(),
|
||||
PropertyFinder.nop()
|
||||
).map(Boolean::parseBoolean).orElse(false);
|
||||
} else {
|
||||
var mainLauncherValue = PropertyFinder.findLauncherProperty(cmd, null,
|
||||
PropertyFinder.cmdlineBooleanOption("--launcher-as-service"),
|
||||
PropertyFinder.nop(),
|
||||
PropertyFinder.nop()
|
||||
).map(Boolean::parseBoolean).orElse(false);
|
||||
|
||||
var value = PropertyFinder.findLauncherProperty(cmd, launcherName,
|
||||
PropertyFinder.nop(),
|
||||
PropertyFinder.launcherPropertyFile("launcher-as-service"),
|
||||
PropertyFinder.appImageFileLauncher(cmd, launcherName, "service").defaultValue(Boolean.FALSE.toString())
|
||||
).map(Boolean::parseBoolean);
|
||||
|
||||
return value.orElse(mainLauncherValue);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canVerifyInstall(JPackageCommand cmd) {
|
||||
cmd.verifyIsOfType(SUPPORTED_PACKAGES);
|
||||
|
||||
String msg = String.format(
|
||||
"Not verifying contents of test output file [%s] for %s launcher",
|
||||
appOutputFilePathInitialize(),
|
||||
@ -221,8 +283,8 @@ public final class LauncherAsServiceVerifier {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void applyToMainLauncher(PackageTest pkg) {
|
||||
pkg.addInitializer(cmd -> {
|
||||
private void applyToMainLauncher(ConfigurationTarget target) {
|
||||
target.addInitializer(cmd -> {
|
||||
cmd.addArgument("--launcher-as-service");
|
||||
cmd.addArguments("--arguments",
|
||||
JPackageCommand.escapeAndJoin(expectedValue));
|
||||
@ -232,7 +294,7 @@ public final class LauncherAsServiceVerifier {
|
||||
});
|
||||
}
|
||||
|
||||
private void applyToAdditionalLauncher(PackageTest pkg) {
|
||||
private void applyToAdditionalLauncher(ConfigurationTarget target) {
|
||||
var al = new AdditionalLauncher(launcherName)
|
||||
.setProperty("launcher-as-service", true)
|
||||
.addJavaOptions("-Djpackage.test.appOutput=" + appOutputFilePathInitialize().toString())
|
||||
@ -240,16 +302,16 @@ public final class LauncherAsServiceVerifier {
|
||||
.addDefaultArguments(expectedValue)
|
||||
.withoutVerifyActions(Action.EXECUTE_LAUNCHER);
|
||||
|
||||
Optional.ofNullable(additionalLauncherCallback).ifPresent(v -> v.accept(al));
|
||||
additionalLauncherCallback.ifPresent(v -> v.accept(al));
|
||||
|
||||
al.applyTo(pkg);
|
||||
target.add(al);
|
||||
}
|
||||
|
||||
private void verifyLauncherExecuted(JPackageCommand cmd) throws IOException {
|
||||
public void verifyLauncherExecuted(JPackageCommand cmd) {
|
||||
if (canVerifyInstall(cmd)) {
|
||||
delayInstallVerify();
|
||||
Path outputFilePath = appOutputFilePathVerify(cmd);
|
||||
HelloApp.assertApp(cmd.appLauncherPath())
|
||||
HelloApp.assertApp(cmd.appLauncherPath(launcherName))
|
||||
.addParam("jpackage.test.appOutput", outputFilePath.toString())
|
||||
.addDefaultArguments(expectedValue)
|
||||
.verifyOutput();
|
||||
@ -257,31 +319,41 @@ public final class LauncherAsServiceVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
private static void deleteOutputFile(Path file) throws IOException {
|
||||
private static void deleteOutputFile(Path file) {
|
||||
try {
|
||||
TKit.deleteIfExists(file);
|
||||
} catch (FileSystemException ex) {
|
||||
if (TKit.isLinux() || TKit.isOSX()) {
|
||||
// Probably "Operation no permitted" error. Try with "sudo" as the
|
||||
// file is created by a launcher started under root account.
|
||||
Executor.of("sudo", "rm", "-f").addArgument(file.toString()).
|
||||
execute();
|
||||
Executor.of("sudo", "rm", "-f").addArgument(file.toString()).execute();
|
||||
} else {
|
||||
throw ex;
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void verify(JPackageCommand cmd, String launcherName, boolean launcherAsService) {
|
||||
if (LINUX.contains(cmd.packageType())) {
|
||||
if (launcherAsService) {
|
||||
verifyLinuxUnitFile(cmd, launcherName);
|
||||
} else {
|
||||
var serviceUnitFile = LinuxHelper.getServiceUnitFilePath(cmd, launcherName);
|
||||
TKit.assertPathExists(serviceUnitFile, false);
|
||||
}
|
||||
} else if (MAC_PKG.equals(cmd.packageType())) {
|
||||
if (launcherAsService) {
|
||||
verifyMacDaemonPlistFile(cmd, launcherName);
|
||||
} else {
|
||||
var servicePlistFile = MacHelper.getServicePlistFilePath(cmd, launcherName);
|
||||
TKit.assertPathExists(servicePlistFile, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void verify(JPackageCommand cmd, String launcherName) throws IOException {
|
||||
if (LINUX.contains(cmd.packageType())) {
|
||||
verifyLinuxUnitFile(cmd, launcherName);
|
||||
} else if (MAC_PKG.equals(cmd.packageType())) {
|
||||
verifyMacDaemonPlistFile(cmd, launcherName);
|
||||
}
|
||||
}
|
||||
|
||||
private static void verifyLinuxUnitFile(JPackageCommand cmd,
|
||||
String launcherName) throws IOException {
|
||||
private static void verifyLinuxUnitFile(JPackageCommand cmd, String launcherName) {
|
||||
|
||||
var serviceUnitFile = LinuxHelper.getServiceUnitFilePath(cmd, launcherName);
|
||||
|
||||
@ -296,11 +368,10 @@ public final class LauncherAsServiceVerifier {
|
||||
TKit.assertTextStream("ExecStart=" + execStartValue)
|
||||
.label("unit file")
|
||||
.predicate(String::equals)
|
||||
.apply(Files.readAllLines(serviceUnitFile));
|
||||
.apply(ThrowingFunction.<Path, List<String>>toFunction(Files::readAllLines).apply(serviceUnitFile));
|
||||
}
|
||||
|
||||
private static void verifyMacDaemonPlistFile(JPackageCommand cmd,
|
||||
String launcherName) throws IOException {
|
||||
private static void verifyMacDaemonPlistFile(JPackageCommand cmd, String launcherName) {
|
||||
|
||||
var servicePlistFile = MacHelper.getServicePlistFilePath(cmd, launcherName);
|
||||
|
||||
@ -348,7 +419,7 @@ public final class LauncherAsServiceVerifier {
|
||||
private final String expectedValue;
|
||||
private final String launcherName;
|
||||
private final Path appOutputFileName;
|
||||
private final Consumer<AdditionalLauncher> additionalLauncherCallback;
|
||||
private final Optional<Consumer<AdditionalLauncher>> additionalLauncherCallback;
|
||||
|
||||
static final Set<PackageType> SUPPORTED_PACKAGES = Stream.of(
|
||||
LINUX,
|
||||
|
||||
@ -103,9 +103,7 @@ public enum LauncherShortcut {
|
||||
Optional<StartupDirectory> expectShortcut(JPackageCommand cmd, Optional<AppImageFile> predefinedAppImage, String launcherName) {
|
||||
Objects.requireNonNull(predefinedAppImage);
|
||||
|
||||
final var name = Optional.ofNullable(launcherName).orElseGet(cmd::name);
|
||||
|
||||
if (name.equals(cmd.name())) {
|
||||
if (cmd.isMainLauncher(launcherName)) {
|
||||
return findMainLauncherShortcut(cmd);
|
||||
} else {
|
||||
String[] propertyName = new String[1];
|
||||
|
||||
@ -45,7 +45,6 @@ import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Matcher;
|
||||
@ -101,7 +100,7 @@ public final class LinuxHelper {
|
||||
return cmd.pathToUnpackedPackageFile(
|
||||
Path.of("/lib/systemd/system").resolve(getServiceUnitFileName(
|
||||
getPackageName(cmd),
|
||||
Optional.ofNullable(launcherName).orElseGet(cmd::name))));
|
||||
Optional.ofNullable(launcherName).orElseGet(cmd::mainLauncherName))));
|
||||
}
|
||||
|
||||
static String getBundleName(JPackageCommand cmd) {
|
||||
@ -371,12 +370,11 @@ public final class LinuxHelper {
|
||||
cmd.verifyIsOfType(PackageType.LINUX);
|
||||
|
||||
final var desktopFiles = getDesktopFiles(cmd);
|
||||
final var predefinedAppImage = Optional.ofNullable(cmd.getArgumentValue("--app-image")).map(Path::of).map(AppImageFile::load);
|
||||
|
||||
return desktopFiles.stream().map(desktopFile -> {
|
||||
var systemDesktopFile = getSystemDesktopFilesFolder().resolve(desktopFile.getFileName());
|
||||
return new InvokeShortcutSpec.Stub(
|
||||
launcherNameFromDesktopFile(cmd, predefinedAppImage, desktopFile),
|
||||
launcherNameFromDesktopFile(cmd, desktopFile),
|
||||
LauncherShortcut.LINUX_SHORTCUT,
|
||||
new DesktopFile(systemDesktopFile, false).findQuotedValue("Path").map(Path::of),
|
||||
List.of("gtk-launch", PathUtils.replaceSuffix(systemDesktopFile.getFileName(), "").toString()));
|
||||
@ -532,16 +530,11 @@ public final class LinuxHelper {
|
||||
TKit.assertEquals(List.of(), unreferencedIconFiles, "Check there are no unreferenced icon files in the package");
|
||||
}
|
||||
|
||||
private static String launcherNameFromDesktopFile(JPackageCommand cmd, Optional<AppImageFile> predefinedAppImage, Path desktopFile) {
|
||||
private static String launcherNameFromDesktopFile(JPackageCommand cmd, Path desktopFile) {
|
||||
Objects.requireNonNull(cmd);
|
||||
Objects.requireNonNull(predefinedAppImage);
|
||||
Objects.requireNonNull(desktopFile);
|
||||
|
||||
return predefinedAppImage.map(v -> {
|
||||
return v.launchers().keySet().stream();
|
||||
}).orElseGet(() -> {
|
||||
return Stream.concat(Stream.of(cmd.name()), cmd.addLauncherNames().stream());
|
||||
}).filter(name-> {
|
||||
return Stream.concat(Stream.of(cmd.mainLauncherName()), cmd.addLauncherNames(true).stream()).filter(name-> {
|
||||
return getDesktopFile(cmd, name).equals(desktopFile);
|
||||
}).findAny().orElseThrow(() -> {
|
||||
TKit.assertUnexpected(String.format("Failed to find launcher corresponding to [%s] file", desktopFile));
|
||||
@ -557,7 +550,7 @@ public final class LinuxHelper {
|
||||
|
||||
TKit.trace(String.format("Check [%s] file BEGIN", desktopFile));
|
||||
|
||||
var launcherName = launcherNameFromDesktopFile(cmd, predefinedAppImage, desktopFile);
|
||||
var launcherName = launcherNameFromDesktopFile(cmd, desktopFile);
|
||||
|
||||
var data = new DesktopFile(desktopFile, true);
|
||||
|
||||
@ -887,8 +880,9 @@ public final class LinuxHelper {
|
||||
return arch;
|
||||
}
|
||||
|
||||
private static String getServiceUnitFileName(String packageName,
|
||||
String launcherName) {
|
||||
private static String getServiceUnitFileName(String packageName, String launcherName) {
|
||||
Objects.requireNonNull(packageName);
|
||||
Objects.requireNonNull(launcherName);
|
||||
try {
|
||||
return getServiceUnitFileName.invoke(null, packageName, launcherName).toString();
|
||||
} catch (InvocationTargetException | IllegalAccessException ex) {
|
||||
|
||||
@ -56,6 +56,7 @@ import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.UnaryOperator;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
@ -662,16 +663,21 @@ public final class MacHelper {
|
||||
}
|
||||
|
||||
private static String getPackageId(JPackageCommand cmd) {
|
||||
return cmd.getArgumentValue("--mac-package-identifier", () -> {
|
||||
return cmd.getArgumentValue("--main-class", cmd::name, className -> {
|
||||
var packageName = ClassDesc.of(className).packageName();
|
||||
if (packageName.isEmpty()) {
|
||||
return className;
|
||||
} else {
|
||||
return packageName;
|
||||
}
|
||||
});
|
||||
});
|
||||
UnaryOperator<String> getPackageIdFromClassName = className -> {
|
||||
var packageName = ClassDesc.of(className).packageName();
|
||||
if (packageName.isEmpty()) {
|
||||
return className;
|
||||
} else {
|
||||
return packageName;
|
||||
}
|
||||
};
|
||||
|
||||
return PropertyFinder.findAppProperty(cmd,
|
||||
PropertyFinder.cmdlineOptionWithValue("--mac-package-identifier").or(
|
||||
PropertyFinder.cmdlineOptionWithValue("--main-class").map(getPackageIdFromClassName)
|
||||
),
|
||||
PropertyFinder.appImageFile(AppImageFile::mainLauncherClassName).map(getPackageIdFromClassName)
|
||||
).orElseGet(cmd::name);
|
||||
}
|
||||
|
||||
public static boolean isXcodeDevToolsInstalled() {
|
||||
|
||||
@ -61,11 +61,9 @@ public final class MacSignVerify {
|
||||
|
||||
assertSigned(bundleRoot, certRequest);
|
||||
|
||||
if (!cmd.isRuntime()) {
|
||||
cmd.addLauncherNames().stream().map(cmd::appLauncherPath).forEach(launcherPath -> {
|
||||
assertSigned(launcherPath, certRequest);
|
||||
});
|
||||
}
|
||||
cmd.addLauncherNames(true).stream().map(cmd::appLauncherPath).forEach(launcherPath -> {
|
||||
assertSigned(launcherPath, certRequest);
|
||||
});
|
||||
|
||||
// Set to "null" if the sign origin is not found, instead of bailing out with an exception.
|
||||
// Let is fail in the following TKit.assertEquals() call with a proper log message.
|
||||
|
||||
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jpackage.test;
|
||||
import static jdk.jpackage.test.AdditionalLauncher.getAdditionalLauncherProperties;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.UnaryOperator;
|
||||
import jdk.jpackage.test.AdditionalLauncher.PropertyFile;
|
||||
|
||||
final class PropertyFinder {
|
||||
|
||||
@FunctionalInterface
|
||||
static interface Finder<T> {
|
||||
Optional<String> find(T target);
|
||||
|
||||
default Finder<T> defaultValue(String v) {
|
||||
return target -> {
|
||||
return Optional.of(find(target).orElse(v));
|
||||
};
|
||||
}
|
||||
|
||||
default Finder<T> map(UnaryOperator<String> v) {
|
||||
Objects.requireNonNull(v);
|
||||
return target -> {
|
||||
return find(target).map(v);
|
||||
};
|
||||
}
|
||||
|
||||
default Finder<T> or(Finder<T> other) {
|
||||
return target -> {
|
||||
return find(target).or(() -> {
|
||||
return other.find(target);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static <T> Finder<T> nop() {
|
||||
return target -> {
|
||||
return Optional.empty();
|
||||
};
|
||||
}
|
||||
|
||||
static Finder<AppImageFile> appImageFileLauncher(JPackageCommand cmd, String launcherName, String propertyName) {
|
||||
Objects.requireNonNull(propertyName);
|
||||
if (cmd.isMainLauncher(launcherName)) {
|
||||
return target -> {
|
||||
return Optional.ofNullable(target.launchers().get(target.mainLauncherName()).get(propertyName));
|
||||
};
|
||||
} else {
|
||||
return target -> {
|
||||
return Optional.ofNullable(target.addLaunchers().get(launcherName).get(propertyName));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static Finder<AppImageFile> appImageFile(Function<AppImageFile, String> propertyGetter) {
|
||||
Objects.requireNonNull(propertyGetter);
|
||||
return target -> {
|
||||
return Optional.of(propertyGetter.apply(target));
|
||||
};
|
||||
}
|
||||
|
||||
static Finder<AppImageFile> appImageFileOptional(Function<AppImageFile, Optional<String>> propertyGetter) {
|
||||
Objects.requireNonNull(propertyGetter);
|
||||
return target -> {
|
||||
return propertyGetter.apply(target);
|
||||
};
|
||||
}
|
||||
|
||||
static Finder<PropertyFile> launcherPropertyFile(String propertyName) {
|
||||
return target -> {
|
||||
return target.findProperty(propertyName);
|
||||
};
|
||||
}
|
||||
|
||||
static Finder<JPackageCommand> cmdlineBooleanOption(String optionName) {
|
||||
return target -> {
|
||||
return Optional.of(target.hasArgument(optionName)).map(Boolean::valueOf).map(Object::toString);
|
||||
};
|
||||
}
|
||||
|
||||
static Finder<JPackageCommand> cmdlineOptionWithValue(String optionName) {
|
||||
return target -> {
|
||||
return Optional.ofNullable(target.getArgumentValue(optionName));
|
||||
};
|
||||
}
|
||||
|
||||
static Optional<String> findAppProperty(
|
||||
JPackageCommand cmd,
|
||||
Finder<JPackageCommand> cmdlineFinder,
|
||||
Finder<AppImageFile> appImageFileFinder) {
|
||||
|
||||
Objects.requireNonNull(cmd);
|
||||
Objects.requireNonNull(cmdlineFinder);
|
||||
Objects.requireNonNull(appImageFileFinder);
|
||||
|
||||
var reply = cmdlineFinder.find(cmd);
|
||||
if (reply.isPresent()) {
|
||||
return reply;
|
||||
} else {
|
||||
var appImageFilePath = Optional.ofNullable(cmd.getArgumentValue("--app-image")).map(Path::of);
|
||||
return appImageFilePath.map(AppImageFile::load).flatMap(appImageFileFinder::find);
|
||||
}
|
||||
}
|
||||
|
||||
static Optional<String> findLauncherProperty(
|
||||
JPackageCommand cmd,
|
||||
String launcherName,
|
||||
Finder<JPackageCommand> cmdlineFinder,
|
||||
Finder<PropertyFile> addLauncherPropertyFileFinder,
|
||||
Finder<AppImageFile> appImageFileFinder) {
|
||||
|
||||
Objects.requireNonNull(cmd);
|
||||
Objects.requireNonNull(cmdlineFinder);
|
||||
Objects.requireNonNull(addLauncherPropertyFileFinder);
|
||||
Objects.requireNonNull(appImageFileFinder);
|
||||
|
||||
var mainLauncher = cmd.isMainLauncher(launcherName);
|
||||
|
||||
var appImageFilePath = Optional.ofNullable(cmd.getArgumentValue("--app-image")).map(Path::of);
|
||||
|
||||
Optional<String> reply;
|
||||
|
||||
if (mainLauncher) {
|
||||
reply = cmdlineFinder.find(cmd);
|
||||
} else if (appImageFilePath.isEmpty()) {
|
||||
var props = getAdditionalLauncherProperties(cmd, launcherName);
|
||||
reply = addLauncherPropertyFileFinder.find(props);
|
||||
} else {
|
||||
reply = Optional.empty();
|
||||
}
|
||||
|
||||
if (reply.isPresent()) {
|
||||
return reply;
|
||||
} else {
|
||||
return appImageFilePath.map(AppImageFile::load).flatMap(appImageFileFinder::find);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -314,8 +314,11 @@ public final class TKit {
|
||||
public static void createTextFile(Path filename, Stream<String> lines) {
|
||||
trace(String.format("Create [%s] text file...",
|
||||
filename.toAbsolutePath().normalize()));
|
||||
ThrowingRunnable.toRunnable(() -> Files.write(filename,
|
||||
lines.peek(TKit::trace).collect(Collectors.toList()))).run();
|
||||
try {
|
||||
Files.write(filename, lines.peek(TKit::trace).toList());
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
trace("Done");
|
||||
}
|
||||
|
||||
@ -323,16 +326,24 @@ public final class TKit {
|
||||
Collection<Map.Entry<String, String>> props) {
|
||||
trace(String.format("Create [%s] properties file...",
|
||||
propsFilename.toAbsolutePath().normalize()));
|
||||
ThrowingRunnable.toRunnable(() -> Files.write(propsFilename,
|
||||
props.stream().map(e -> String.join("=", e.getKey(),
|
||||
e.getValue())).peek(TKit::trace).collect(Collectors.toList()))).run();
|
||||
try {
|
||||
Files.write(propsFilename, props.stream().map(e -> {
|
||||
return String.join("=", e.getKey(), e.getValue());
|
||||
}).peek(TKit::trace).toList());
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
trace("Done");
|
||||
}
|
||||
|
||||
public static void traceFileContents(Path path, String label) throws IOException {
|
||||
public static void traceFileContents(Path path, String label) {
|
||||
assertFileExists(path);
|
||||
trace(String.format("Dump [%s] %s...", path, label));
|
||||
Files.readAllLines(path).forEach(TKit::trace);
|
||||
try {
|
||||
Files.readAllLines(path).forEach(TKit::trace);
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
trace("Done");
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@
|
||||
package jdk.jpackage.test;
|
||||
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
import static java.util.stream.Collectors.toUnmodifiableMap;
|
||||
import static jdk.jpackage.test.LauncherShortcut.WIN_DESKTOP_SHORTCUT;
|
||||
import static jdk.jpackage.test.LauncherShortcut.WIN_START_MENU_SHORTCUT;
|
||||
import static jdk.jpackage.test.WindowsHelper.getInstallationSubDirectory;
|
||||
@ -32,7 +33,6 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -51,7 +51,7 @@ public final class WinShortcutVerifier {
|
||||
static void verifyBundleShortcuts(JPackageCommand cmd) {
|
||||
cmd.verifyIsOfType(PackageType.WIN_MSI);
|
||||
|
||||
if (Stream.of("--win-menu", "--win-shortcut").noneMatch(cmd::hasArgument) && cmd.addLauncherNames().isEmpty()) {
|
||||
if (Stream.of("--win-menu", "--win-shortcut").noneMatch(cmd::hasArgument) && cmd.addLauncherNames(true).isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -170,7 +170,7 @@ public final class WinShortcutVerifier {
|
||||
private static Shortcut createLauncherShortcutSpec(JPackageCommand cmd, String launcherName,
|
||||
SpecialFolder installRoot, Path workDir, ShortcutType type) {
|
||||
|
||||
var name = Optional.ofNullable(launcherName).orElseGet(cmd::name);
|
||||
var name = Optional.ofNullable(launcherName).orElseGet(cmd::mainLauncherName);
|
||||
|
||||
var appLayout = ApplicationLayout.windowsAppImage().resolveAt(
|
||||
Path.of(installRoot.getMsiPropertyName()).resolve(getInstallationSubDirectory(cmd)));
|
||||
@ -250,22 +250,19 @@ public final class WinShortcutVerifier {
|
||||
}
|
||||
|
||||
private static Map<String, Collection<Shortcut>> expectShortcuts(JPackageCommand cmd) {
|
||||
Map<String, Collection<Shortcut>> expectedShortcuts = new HashMap<>();
|
||||
|
||||
var predefinedAppImage = Optional.ofNullable(cmd.getArgumentValue("--app-image")).map(Path::of).map(AppImageFile::load);
|
||||
|
||||
predefinedAppImage.map(v -> {
|
||||
return v.launchers().keySet().stream();
|
||||
}).orElseGet(() -> {
|
||||
return Stream.concat(Stream.of(cmd.name()), cmd.addLauncherNames().stream());
|
||||
}).forEach(launcherName -> {
|
||||
return cmd.launcherNames(true).stream().map(launcherName -> {
|
||||
return Optional.ofNullable(launcherName).orElseGet(cmd::mainLauncherName);
|
||||
}).map(launcherName -> {
|
||||
var shortcuts = expectLauncherShortcuts(cmd, predefinedAppImage, launcherName);
|
||||
if (!shortcuts.isEmpty()) {
|
||||
expectedShortcuts.put(launcherName, shortcuts);
|
||||
if (shortcuts.isEmpty()) {
|
||||
return null;
|
||||
} else {
|
||||
return Map.entry(launcherName, shortcuts);
|
||||
}
|
||||
});
|
||||
|
||||
return expectedShortcuts;
|
||||
}).filter(Objects::nonNull).collect(toUnmodifiableMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
}
|
||||
|
||||
private static InvokeShortcutSpec convert(JPackageCommand cmd, String launcherName, Shortcut shortcut) {
|
||||
|
||||
@ -21,18 +21,26 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import static jdk.jpackage.test.PackageType.MAC_DMG;
|
||||
import static jdk.jpackage.test.PackageType.WINDOWS;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HexFormat;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.jpackage.test.PackageTest;
|
||||
import jdk.jpackage.test.AdditionalLauncher;
|
||||
import jdk.jpackage.test.Annotations.Parameter;
|
||||
import jdk.jpackage.test.Annotations.Test;
|
||||
import jdk.jpackage.test.ConfigurationTarget;
|
||||
import jdk.jpackage.test.JPackageCommand;
|
||||
import jdk.jpackage.test.JavaTool;
|
||||
import jdk.jpackage.test.LauncherAsServiceVerifier;
|
||||
import static jdk.jpackage.test.PackageType.MAC_DMG;
|
||||
import static jdk.jpackage.test.PackageType.WINDOWS;
|
||||
import jdk.jpackage.test.LauncherVerifier.Action;
|
||||
import jdk.jpackage.test.PackageTest;
|
||||
import jdk.jpackage.test.RunnablePackageTest;
|
||||
import jdk.jpackage.test.TKit;
|
||||
|
||||
@ -47,11 +55,26 @@ import jdk.jpackage.test.TKit;
|
||||
* @library /test/jdk/tools/jpackage/helpers
|
||||
* @build jdk.jpackage.test.*
|
||||
* @key jpackagePlatformPackage
|
||||
* @requires (jpackage.test.SQETest != null)
|
||||
* @compile -Xlint:all -Werror ServiceTest.java
|
||||
* @run main/othervm/timeout=360 -Xmx512m
|
||||
* @run main/othervm/timeout=2880 -Xmx512m
|
||||
* jdk.jpackage.test.Main
|
||||
* --jpt-run=ServiceTest.test,ServiceTest.testUpdate
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @summary Launcher as service packaging test
|
||||
* @library /test/jdk/tools/jpackage/helpers
|
||||
* @build jdk.jpackage.test.*
|
||||
* @key jpackagePlatformPackage
|
||||
* @requires (jpackage.test.SQETest == null)
|
||||
* @compile -Xlint:all -Werror ServiceTest.java
|
||||
* @run main/othervm/timeout=2880 -Xmx512m
|
||||
* jdk.jpackage.test.Main
|
||||
* --jpt-run=ServiceTest
|
||||
*/
|
||||
|
||||
public class ServiceTest {
|
||||
|
||||
public ServiceTest() {
|
||||
@ -86,10 +109,9 @@ public class ServiceTest {
|
||||
|
||||
@Test
|
||||
public void test() throws Throwable {
|
||||
var testInitializer = createTestInitializer();
|
||||
var pkg = createPackageTest().addHelloAppInitializer("com.foo.ServiceTest");
|
||||
LauncherAsServiceVerifier.build().setExpectedValue("A1").applyTo(pkg);
|
||||
testInitializer.applyTo(pkg);
|
||||
createTestInitializer().applyTo(pkg);
|
||||
pkg.run();
|
||||
}
|
||||
|
||||
@ -132,6 +154,108 @@ public class ServiceTest {
|
||||
new PackageTest.Group(pkg, pkg2).run();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Parameter("true")
|
||||
@Parameter("false")
|
||||
public void testAddL(boolean mainLauncherAsService) {
|
||||
|
||||
final var uniqueOutputFile = uniqueOutputFile();
|
||||
|
||||
createPackageTest()
|
||||
.addHelloAppInitializer("com.buz.AddLaunchersServiceTest")
|
||||
.mutate(test -> {
|
||||
if (mainLauncherAsService) {
|
||||
LauncherAsServiceVerifier.build()
|
||||
.mutate(uniqueOutputFile).appendAppOutputFileNamePrefix("-")
|
||||
.setExpectedValue("Main").applyTo(test);
|
||||
}
|
||||
})
|
||||
// Regular launcher. The installer should not automatically execute it.
|
||||
.mutate(new AdditionalLauncher("notservice")
|
||||
.withoutVerifyActions(Action.EXECUTE_LAUNCHER)
|
||||
.setProperty("launcher-as-service", Boolean.FALSE)
|
||||
.addJavaOptions("-Djpackage.test.noexit=true")::applyTo)
|
||||
// Additional launcher with explicit "launcher-as-service=true" property in the property file.
|
||||
.mutate(LauncherAsServiceVerifier.build()
|
||||
.mutate(uniqueOutputFile).appendAppOutputFileNamePrefix("-A1-")
|
||||
.setLauncherName("AL1")
|
||||
.setExpectedValue("AL1")::applyTo)
|
||||
.mutate(test -> {
|
||||
if (mainLauncherAsService) {
|
||||
// Additional launcher without "launcher-as-service" property in the property file.
|
||||
// Still, should be installed as a service.
|
||||
LauncherAsServiceVerifier.build()
|
||||
.mutate(uniqueOutputFile).appendAppOutputFileNamePrefix("-A2-")
|
||||
.setLauncherName("AL2")
|
||||
.setExpectedValue("AL2")
|
||||
.setAdditionalLauncherCallback(al -> {
|
||||
al.removeProperty("launcher-as-service");
|
||||
})
|
||||
.applyTo(test);
|
||||
}
|
||||
})
|
||||
.mutate(createTestInitializer()::applyTo)
|
||||
.run();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Parameter("true")
|
||||
@Parameter("false")
|
||||
public void testAddLFromAppImage(boolean mainLauncherAsService) {
|
||||
|
||||
var uniqueOutputFile = uniqueOutputFile();
|
||||
|
||||
var appImageCmd = new ConfigurationTarget(JPackageCommand.helloAppImage("com.bar.AddLaunchersFromAppImageServiceTest"));
|
||||
|
||||
if (RunnablePackageTest.hasAction(RunnablePackageTest.Action.INSTALL)) {
|
||||
// Ensure launchers are executable because the output bundle will be installed
|
||||
// and we want to verify launchers are automatically started by the installer.
|
||||
appImageCmd.addInitializer(JPackageCommand::ignoreFakeRuntime);
|
||||
}
|
||||
|
||||
if (mainLauncherAsService) {
|
||||
LauncherAsServiceVerifier.build()
|
||||
.mutate(uniqueOutputFile).appendAppOutputFileNamePrefix("-")
|
||||
.setExpectedValue("Main")
|
||||
.applyTo(appImageCmd);
|
||||
// Can not use "--launcher-as-service" option with app image packaging.
|
||||
appImageCmd.cmd().orElseThrow().removeArgument("--launcher-as-service");
|
||||
} else {
|
||||
appImageCmd.addInitializer(cmd -> {
|
||||
// Configure the main launcher to hang at the end of the execution.
|
||||
// The main launcher should not be executed in this test.
|
||||
// If it is executed, it indicates it was started as a service,
|
||||
// which must fail the test. The launcher's hang-up will be the event failing the test.
|
||||
cmd.addArguments("--java-options", "-Djpackage.test.noexit=true");
|
||||
});
|
||||
}
|
||||
|
||||
// Additional launcher with explicit "launcher-as-service=true" property in the property file.
|
||||
LauncherAsServiceVerifier.build()
|
||||
.mutate(uniqueOutputFile).appendAppOutputFileNamePrefix("-A1-")
|
||||
.setLauncherName("AL1")
|
||||
.setExpectedValue("AL1").applyTo(appImageCmd);
|
||||
|
||||
// Regular launcher. The installer should not automatically execute it.
|
||||
appImageCmd.add(new AdditionalLauncher("notservice")
|
||||
.withoutVerifyActions(Action.EXECUTE_LAUNCHER)
|
||||
.addJavaOptions("-Djpackage.test.noexit=true"));
|
||||
|
||||
new PackageTest().excludeTypes(MAC_DMG)
|
||||
.addRunOnceInitializer(appImageCmd.cmd().orElseThrow()::execute)
|
||||
.addInitializer(cmd -> {
|
||||
cmd.removeArgumentWithValue("--input");
|
||||
cmd.addArguments("--app-image", appImageCmd.cmd().orElseThrow().outputBundle());
|
||||
})
|
||||
.addInitializer(cmd -> {
|
||||
if (mainLauncherAsService) {
|
||||
cmd.addArgument("--launcher-as-service");
|
||||
}
|
||||
})
|
||||
.mutate(createTestInitializer()::applyTo)
|
||||
.run();
|
||||
}
|
||||
|
||||
private final class TestInitializer {
|
||||
|
||||
TestInitializer setUpgradeCode(String v) {
|
||||
@ -139,11 +263,14 @@ public class ServiceTest {
|
||||
return this;
|
||||
}
|
||||
|
||||
void applyTo(PackageTest test) throws IOException {
|
||||
void applyTo(PackageTest test) {
|
||||
if (winServiceInstaller != null) {
|
||||
var resourceDir = TKit.createTempDirectory("resource-dir");
|
||||
Files.copy(winServiceInstaller, resourceDir.resolve(
|
||||
"service-installer.exe"));
|
||||
try {
|
||||
Files.copy(winServiceInstaller, resourceDir.resolve("service-installer.exe"));
|
||||
} catch (IOException ex) {
|
||||
throw new UncheckedIOException(ex);
|
||||
}
|
||||
|
||||
test.forTypes(WINDOWS, () -> test.addInitializer(cmd -> {
|
||||
cmd.addArguments("--resource-dir", resourceDir);
|
||||
@ -165,9 +292,28 @@ public class ServiceTest {
|
||||
}
|
||||
|
||||
private static PackageTest createPackageTest() {
|
||||
return new PackageTest()
|
||||
var test = new PackageTest()
|
||||
.excludeTypes(MAC_DMG) // DMG not supported
|
||||
.addInitializer(JPackageCommand::setInputToEmptyDirectory);
|
||||
if (RunnablePackageTest.hasAction(RunnablePackageTest.Action.INSTALL)) {
|
||||
// Ensure launchers are executable because the output bundle will be installed
|
||||
// and we want to verify launchers are automatically started by the installer.
|
||||
test.addInitializer(JPackageCommand::ignoreFakeRuntime);
|
||||
}
|
||||
return test;
|
||||
}
|
||||
|
||||
private static Consumer<LauncherAsServiceVerifier.Builder> uniqueOutputFile() {
|
||||
var prefix = uniquePrefix();
|
||||
return builder -> {
|
||||
builder.setAppOutputFileNamePrefixToAppName()
|
||||
.appendAppOutputFileNamePrefix("-")
|
||||
.appendAppOutputFileNamePrefix(prefix);
|
||||
};
|
||||
}
|
||||
|
||||
private static String uniquePrefix() {
|
||||
return HexFormat.of().toHexDigits(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
private final Path winServiceInstaller;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user