mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-15 13:49:42 +02:00
8308349: missing working directory option for launcher when invoked from shortcuts
Reviewed-by: almatvee
This commit is contained in:
parent
6927fc3904
commit
72d3a2a977
16 changed files with 352 additions and 108 deletions
|
@ -46,6 +46,7 @@ import javax.imageio.ImageIO;
|
|||
import javax.xml.stream.XMLStreamException;
|
||||
import javax.xml.stream.XMLStreamWriter;
|
||||
import jdk.jpackage.internal.model.FileAssociation;
|
||||
import jdk.jpackage.internal.model.LauncherShortcut;
|
||||
import jdk.jpackage.internal.model.LinuxLauncher;
|
||||
import jdk.jpackage.internal.model.LinuxPackage;
|
||||
import jdk.jpackage.internal.model.Package;
|
||||
|
@ -237,6 +238,23 @@ final class DesktopIntegration extends ShellCustomAction {
|
|||
data.put("DEPLOY_BUNDLE_CATEGORY", pkg.menuGroupName());
|
||||
data.put("APPLICATION_LAUNCHER", Enquoter.forPropertyValues().applyTo(
|
||||
installedLayout.launchersDirectory().resolve(launcher.executableNameWithSuffix()).toString()));
|
||||
data.put("STARTUP_DIRECTORY", launcher.shortcut()
|
||||
.flatMap(LauncherShortcut::startupDirectory)
|
||||
.map(startupDirectory -> {
|
||||
switch (startupDirectory) {
|
||||
case DEFAULT -> {
|
||||
return (Path)null;
|
||||
}
|
||||
case APP_DIR -> {
|
||||
return installedLayout.appDirectory();
|
||||
}
|
||||
default -> {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
}).map(str -> {
|
||||
return "Path=" + str;
|
||||
}).orElse(null));
|
||||
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -109,12 +109,8 @@ final class LinuxFromParams {
|
|||
static final BundlerParamInfo<LinuxPackage> DEB_PACKAGE = createPackageBundlerParam(
|
||||
LinuxFromParams::createLinuxDebPackage);
|
||||
|
||||
private static final BundlerParamInfo<Boolean> LINUX_SHORTCUT_HINT = new BundlerParamInfo<>(
|
||||
Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(),
|
||||
Boolean.class,
|
||||
params -> false,
|
||||
(s, p) -> (s == null || "null".equalsIgnoreCase(s)) ? false : Boolean.valueOf(s)
|
||||
);
|
||||
private static final BundlerParamInfo<String> LINUX_SHORTCUT_HINT = createStringBundlerParam(
|
||||
Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId());
|
||||
|
||||
private static final BundlerParamInfo<String> LINUX_CATEGORY = createStringBundlerParam(
|
||||
Arguments.CLIOptions.LINUX_CATEGORY.getId());
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
Name=APPLICATION_NAME
|
||||
Comment=APPLICATION_DESCRIPTION
|
||||
Exec=APPLICATION_LAUNCHER
|
||||
STARTUP_DIRECTORY
|
||||
Icon=APPLICATION_ICON
|
||||
Terminal=false
|
||||
Type=Application
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.util.EnumSet;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.ResourceBundle;
|
||||
|
@ -348,16 +349,13 @@ public class Arguments {
|
|||
|
||||
WIN_UPDATE_URL ("win-update-url", OptionCategories.PLATFORM_WIN),
|
||||
|
||||
WIN_MENU_HINT ("win-menu", OptionCategories.PLATFORM_WIN, () -> {
|
||||
setOptionValue("win-menu", true);
|
||||
}),
|
||||
WIN_MENU_HINT ("win-menu", OptionCategories.PLATFORM_WIN,
|
||||
createArgumentWithOptionalValueAction("win-menu")),
|
||||
|
||||
WIN_MENU_GROUP ("win-menu-group", OptionCategories.PLATFORM_WIN),
|
||||
|
||||
WIN_SHORTCUT_HINT ("win-shortcut",
|
||||
OptionCategories.PLATFORM_WIN, () -> {
|
||||
setOptionValue("win-shortcut", true);
|
||||
}),
|
||||
WIN_SHORTCUT_HINT ("win-shortcut", OptionCategories.PLATFORM_WIN,
|
||||
createArgumentWithOptionalValueAction("win-shortcut")),
|
||||
|
||||
WIN_SHORTCUT_PROMPT ("win-shortcut-prompt",
|
||||
OptionCategories.PLATFORM_WIN, () -> {
|
||||
|
@ -396,10 +394,8 @@ public class Arguments {
|
|||
LINUX_PACKAGE_DEPENDENCIES ("linux-package-deps",
|
||||
OptionCategories.PLATFORM_LINUX),
|
||||
|
||||
LINUX_SHORTCUT_HINT ("linux-shortcut",
|
||||
OptionCategories.PLATFORM_LINUX, () -> {
|
||||
setOptionValue("linux-shortcut", true);
|
||||
}),
|
||||
LINUX_SHORTCUT_HINT ("linux-shortcut", OptionCategories.PLATFORM_LINUX,
|
||||
createArgumentWithOptionalValueAction("linux-shortcut")),
|
||||
|
||||
LINUX_MENU_GROUP ("linux-menu-group", OptionCategories.PLATFORM_LINUX);
|
||||
|
||||
|
@ -478,9 +474,32 @@ public class Arguments {
|
|||
context().pos++;
|
||||
}
|
||||
|
||||
private static void prevArg() {
|
||||
Objects.checkIndex(context().pos, context().argList.size());
|
||||
context().pos--;
|
||||
}
|
||||
|
||||
private static boolean hasNextArg() {
|
||||
return context().pos < context().argList.size();
|
||||
}
|
||||
|
||||
private static Runnable createArgumentWithOptionalValueAction(String option) {
|
||||
Objects.requireNonNull(option);
|
||||
return () -> {
|
||||
nextArg();
|
||||
if (hasNextArg()) {
|
||||
var value = getArg();
|
||||
if (value.startsWith("-")) {
|
||||
prevArg();
|
||||
setOptionValue(option, true);
|
||||
} else {
|
||||
setOptionValue(option, value);
|
||||
}
|
||||
} else {
|
||||
setOptionValue(option, true);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum OptionCategories {
|
||||
|
|
|
@ -52,6 +52,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.VENDOR;
|
|||
import static jdk.jpackage.internal.StandardBundlerParam.VERSION;
|
||||
import static jdk.jpackage.internal.StandardBundlerParam.hasPredefinedAppImage;
|
||||
import static jdk.jpackage.internal.StandardBundlerParam.isRuntimeInstaller;
|
||||
import static jdk.jpackage.internal.util.function.ThrowingFunction.toFunction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
@ -69,6 +70,7 @@ import jdk.jpackage.internal.model.Launcher;
|
|||
import jdk.jpackage.internal.model.LauncherShortcut;
|
||||
import jdk.jpackage.internal.model.LauncherShortcutStartupDirectory;
|
||||
import jdk.jpackage.internal.model.PackageType;
|
||||
import jdk.jpackage.internal.model.ParseUtils;
|
||||
import jdk.jpackage.internal.model.RuntimeLayout;
|
||||
import jdk.jpackage.internal.util.function.ThrowingFunction;
|
||||
|
||||
|
@ -171,11 +173,11 @@ final class FromParams {
|
|||
}
|
||||
|
||||
static Optional<LauncherShortcut> findLauncherShortcut(
|
||||
BundlerParamInfo<Boolean> shortcutParam,
|
||||
BundlerParamInfo<String> shortcutParam,
|
||||
Map<String, ? super Object> mainParams,
|
||||
Map<String, ? super Object> launcherParams) {
|
||||
|
||||
Optional<Boolean> launcherValue;
|
||||
Optional<String> launcherValue;
|
||||
if (launcherParams == mainParams) {
|
||||
// The main launcher
|
||||
launcherValue = Optional.empty();
|
||||
|
@ -183,17 +185,19 @@ final class FromParams {
|
|||
launcherValue = shortcutParam.findIn(launcherParams);
|
||||
}
|
||||
|
||||
return launcherValue.map(withShortcut -> {
|
||||
if (withShortcut) {
|
||||
return Optional.of(LauncherShortcutStartupDirectory.DEFAULT);
|
||||
} else {
|
||||
return Optional.<LauncherShortcutStartupDirectory>empty();
|
||||
}
|
||||
}).or(() -> {
|
||||
return shortcutParam.findIn(mainParams).map(_ -> {
|
||||
return Optional.of(LauncherShortcutStartupDirectory.DEFAULT);
|
||||
});
|
||||
}).map(LauncherShortcut::new);
|
||||
return launcherValue.map(ParseUtils::parseLauncherShortcutForAddLauncher).or(() -> {
|
||||
return Optional.ofNullable(mainParams.get(shortcutParam.getID())).map(toFunction(value -> {
|
||||
if (value instanceof Boolean) {
|
||||
return new LauncherShortcut(LauncherShortcutStartupDirectory.DEFAULT);
|
||||
} else {
|
||||
try {
|
||||
return ParseUtils.parseLauncherShortcutForMainLauncher((String)value);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw I18N.buildConfigException("error.invalid-option-value", value, "--" + shortcutParam.getID()).create();
|
||||
}
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
private static ApplicationLaunchers createLaunchers(
|
||||
|
|
|
@ -41,7 +41,14 @@ public enum LauncherShortcutStartupDirectory {
|
|||
* On Linux, it indicates that a shortcut doesn't have the startup directory
|
||||
* configured explicitly.
|
||||
*/
|
||||
DEFAULT("true");
|
||||
DEFAULT("true"),
|
||||
|
||||
/**
|
||||
* The 'app' directory in the installed application app image. This is the
|
||||
* directory that is referenced with {@link ApplicationLayout#appDirectory()}
|
||||
* method.
|
||||
*/
|
||||
APP_DIR("app-dir");
|
||||
|
||||
LauncherShortcutStartupDirectory(String stringValue) {
|
||||
this.stringValue = Objects.requireNonNull(stringValue);
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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.internal.model;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* Collection of functions to create instances of types defined in this package from strings.
|
||||
*/
|
||||
public final class ParseUtils {
|
||||
|
||||
private ParseUtils() {
|
||||
}
|
||||
|
||||
public static LauncherShortcut parseLauncherShortcutForMainLauncher(String str) {
|
||||
return parse(str, LauncherShortcutStartupDirectory.APP_DIR).map(LauncherShortcut::new).orElseThrow(IllegalArgumentException::new);
|
||||
}
|
||||
|
||||
public static LauncherShortcut parseLauncherShortcutForAddLauncher(String str) {
|
||||
return parse(str, LauncherShortcutStartupDirectory.values()).map(LauncherShortcut::new).orElseGet(() -> {
|
||||
if (Boolean.valueOf(str)) {
|
||||
return new LauncherShortcut(LauncherShortcutStartupDirectory.DEFAULT);
|
||||
} else {
|
||||
return new LauncherShortcut();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Optional<LauncherShortcutStartupDirectory> parse(String str, LauncherShortcutStartupDirectory... recognizedValues) {
|
||||
Objects.requireNonNull(str);
|
||||
return Stream.of(recognizedValues).filter(v -> {
|
||||
return str.equals(v.asStringValue());
|
||||
}).findFirst();
|
||||
}
|
||||
}
|
|
@ -82,6 +82,8 @@ error.invalid-app-image=Error: app-image dir "{0}" generated by another jpackage
|
|||
|
||||
error.invalid-install-dir=Invalid installation directory "{0}"
|
||||
|
||||
error.invalid-option-value=Invalid value "{0}" of option {1}
|
||||
|
||||
MSG_BundlerFailed=Error: Bundler "{1}" ({0}) failed to produce a package
|
||||
MSG_BundlerConfigException=Bundler {0} skipped because of a configuration problem: {1} \n\
|
||||
Advice to fix: {2}
|
||||
|
|
|
@ -105,10 +105,10 @@ final class WinFromParams {
|
|||
static final BundlerParamInfo<WinMsiPackage> MSI_PACKAGE = createPackageBundlerParam(
|
||||
WinFromParams::createWinMsiPackage);
|
||||
|
||||
private static final BundlerParamInfo<Boolean> WIN_MENU_HINT = createBooleanBundlerParam(
|
||||
private static final BundlerParamInfo<String> WIN_MENU_HINT = createStringBundlerParam(
|
||||
Arguments.CLIOptions.WIN_MENU_HINT.getId());
|
||||
|
||||
private static final BundlerParamInfo<Boolean> WIN_SHORTCUT_HINT = createBooleanBundlerParam(
|
||||
private static final BundlerParamInfo<String> WIN_SHORTCUT_HINT = createStringBundlerParam(
|
||||
Arguments.CLIOptions.WIN_SHORTCUT_HINT.getId());
|
||||
|
||||
public static final BundlerParamInfo<Boolean> CONSOLE_HINT = createBooleanBundlerParam(
|
||||
|
|
|
@ -474,6 +474,9 @@ final class WixAppImageFragmentBuilder extends WixFragmentBuilder {
|
|||
case DEFAULT -> {
|
||||
return INSTALLDIR;
|
||||
}
|
||||
case APP_DIR -> {
|
||||
return installedAppImage.appDirectory();
|
||||
}
|
||||
default -> {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
|
|
@ -54,6 +54,10 @@ public final class AdditionalLauncher {
|
|||
setPersistenceHandler(null);
|
||||
}
|
||||
|
||||
public String name() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public AdditionalLauncher withVerifyActions(Action... actions) {
|
||||
verifyActions.addAll(List.of(actions));
|
||||
return this;
|
||||
|
|
|
@ -44,6 +44,7 @@ public enum LauncherShortcut {
|
|||
|
||||
public enum StartupDirectory {
|
||||
DEFAULT("true"),
|
||||
APP_DIR("app-dir"),
|
||||
;
|
||||
|
||||
StartupDirectory(String stringValue) {
|
||||
|
@ -79,7 +80,7 @@ public enum LauncherShortcut {
|
|||
|
||||
private final String stringValue;
|
||||
|
||||
private final static Map<String, StartupDirectory> VALUE_MAP =
|
||||
private static final Map<String, StartupDirectory> VALUE_MAP =
|
||||
Stream.of(values()).collect(toMap(StartupDirectory::asStringValue, x -> x));
|
||||
}
|
||||
|
||||
|
@ -147,7 +148,14 @@ public enum LauncherShortcut {
|
|||
|
||||
private Optional<StartupDirectory> findMainLauncherShortcut(JPackageCommand cmd) {
|
||||
if (cmd.hasArgument(optionName())) {
|
||||
return Optional.of(StartupDirectory.DEFAULT);
|
||||
var value = Optional.ofNullable(cmd.getArgumentValue(optionName())).filter(optionValue -> {
|
||||
return !optionValue.startsWith("-");
|
||||
});
|
||||
if (value.isPresent()) {
|
||||
return value.flatMap(StartupDirectory::parse);
|
||||
} else {
|
||||
return Optional.of(StartupDirectory.DEFAULT);
|
||||
}
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
|
|
@ -514,6 +514,9 @@ public final class LinuxHelper {
|
|||
case DEFAULT -> {
|
||||
return (Path)null;
|
||||
}
|
||||
case APP_DIR -> {
|
||||
return cmd.pathToPackageFile(appLayout.appDirectory());
|
||||
}
|
||||
default -> {
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
|
|
@ -213,7 +213,17 @@ public final class WinShortcutVerifier {
|
|||
final var installDir = Path.of(installRoot.getMsiPropertyName()).resolve(getInstallationSubDirectory(cmd));
|
||||
|
||||
final Function<StartupDirectory, Path> workDir = startupDirectory -> {
|
||||
return installDir;
|
||||
switch (startupDirectory) {
|
||||
case DEFAULT -> {
|
||||
return installDir;
|
||||
}
|
||||
case APP_DIR -> {
|
||||
return ApplicationLayout.windowsAppImage().resolveAt(installDir).appDirectory();
|
||||
}
|
||||
default -> {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (winMenu.isPresent()) {
|
||||
|
|
|
@ -28,16 +28,21 @@ import java.nio.file.Path;
|
|||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import jdk.internal.util.OperatingSystem;
|
||||
import jdk.jpackage.test.AdditionalLauncher;
|
||||
import jdk.jpackage.test.Annotations.Parameter;
|
||||
import jdk.jpackage.test.Annotations.ParameterSupplier;
|
||||
import jdk.jpackage.test.Annotations.Test;
|
||||
import jdk.jpackage.test.FileAssociations;
|
||||
import jdk.jpackage.test.HelloApp;
|
||||
import jdk.jpackage.test.JPackageCommand;
|
||||
import jdk.jpackage.test.JavaAppDesc;
|
||||
import jdk.jpackage.test.LauncherShortcut;
|
||||
import jdk.jpackage.test.LauncherShortcut.InvokeShortcutSpec;
|
||||
import jdk.jpackage.test.LauncherShortcut.StartupDirectory;
|
||||
|
@ -63,6 +68,7 @@ import jdk.jpackage.test.WinShortcutVerifier;
|
|||
* @key jpackagePlatformPackage
|
||||
* @library /test/jdk/tools/jpackage/helpers
|
||||
* @build jdk.jpackage.test.*
|
||||
* @requires (os.family != "mac")
|
||||
* @requires (jpackage.test.SQETest != null)
|
||||
* @compile -Xlint:all -Werror AddLShortcutTest.java
|
||||
* @run main/othervm/timeout=540 -Xmx512m
|
||||
|
@ -76,6 +82,7 @@ import jdk.jpackage.test.WinShortcutVerifier;
|
|||
* @key jpackagePlatformPackage
|
||||
* @library /test/jdk/tools/jpackage/helpers
|
||||
* @build jdk.jpackage.test.*
|
||||
* @requires (os.family != "mac")
|
||||
* @requires (jpackage.test.SQETest == null)
|
||||
* @compile -Xlint:all -Werror AddLShortcutTest.java
|
||||
* @run main/othervm/timeout=1080 -Xmx512m
|
||||
|
@ -85,7 +92,7 @@ import jdk.jpackage.test.WinShortcutVerifier;
|
|||
|
||||
public class AddLShortcutTest {
|
||||
|
||||
@Test
|
||||
@Test(ifNotOS = OperatingSystem.MACOS)
|
||||
public void test() {
|
||||
// Configure several additional launchers with each combination of
|
||||
// possible shortcut hints in add-launcher property file.
|
||||
|
@ -93,6 +100,8 @@ public class AddLShortcutTest {
|
|||
// will have shortcuts while other launchers with some properties set
|
||||
// to "false" will have none.
|
||||
|
||||
final var packageName = MethodHandles.lookup().lookupClass().getSimpleName();
|
||||
|
||||
PackageTest packageTest = new PackageTest().configureHelloApp();
|
||||
packageTest.addInitializer(cmd -> {
|
||||
cmd.addArguments("--arguments", "Duke", "--arguments", "is",
|
||||
|
@ -102,11 +111,14 @@ public class AddLShortcutTest {
|
|||
} else if (TKit.isLinux()) {
|
||||
cmd.addArguments("--linux-shortcut");
|
||||
}
|
||||
|
||||
cmd.setArgumentValue("--name", packageName);
|
||||
|
||||
var addLauncherApp = TKit.TEST_SRC_ROOT.resolve("apps/PrintEnv.java");
|
||||
HelloApp.createBundle(JavaAppDesc.parse(addLauncherApp + "*another.jar:Welcome"), cmd.inputDir());
|
||||
});
|
||||
|
||||
new FileAssociations(
|
||||
MethodHandles.lookup().lookupClass().getSimpleName()).applyTo(
|
||||
packageTest);
|
||||
new FileAssociations(packageName).applyTo(packageTest);
|
||||
|
||||
new AdditionalLauncher("Foo")
|
||||
.setDefaultArguments("yep!")
|
||||
|
@ -131,11 +143,16 @@ public class AddLShortcutTest {
|
|||
.setShortcuts(true, false)
|
||||
.applyTo(packageTest);
|
||||
|
||||
new AdditionalLauncher("Launcher5")
|
||||
.setDefaultArguments()
|
||||
var launcher5 = new AdditionalLauncher("Launcher5")
|
||||
.setDefaultArguments("--print-workdir")
|
||||
.setIcon(GOLDEN_ICON)
|
||||
.setShortcuts(false, true)
|
||||
.applyTo(packageTest);
|
||||
.setShortcut(LauncherShortcut.LINUX_SHORTCUT, StartupDirectory.APP_DIR)
|
||||
.setShortcut(LauncherShortcut.WIN_DESKTOP_SHORTCUT, StartupDirectory.APP_DIR)
|
||||
.setShortcut(LauncherShortcut.WIN_START_MENU_SHORTCUT, null)
|
||||
.setProperty("main-jar", "another.jar")
|
||||
.setProperty("main-class", "Welcome");
|
||||
|
||||
new ShortcutStartupDirectoryVerifier(packageName).add(launcher5).applyTo(packageTest);
|
||||
|
||||
packageTest.run();
|
||||
}
|
||||
|
@ -190,10 +207,50 @@ public class AddLShortcutTest {
|
|||
|
||||
predefinedAppImage[0] = cmd.outputBundle();
|
||||
}).addInitializer(cmd -> {
|
||||
cfgs[0].applyToMainLauncher(cmd);
|
||||
cmd.removeArgumentWithValue("--input");
|
||||
cmd.setArgumentValue("--name", "AddLShortcutDir2Test");
|
||||
cmd.addArguments("--app-image", predefinedAppImage[0]);
|
||||
cfgs[0].applyToMainLauncher(cmd);
|
||||
}).run(RunnablePackageTest.Action.CREATE_AND_UNPACK);
|
||||
}
|
||||
|
||||
@Test(ifNotOS = OperatingSystem.MACOS)
|
||||
@Parameter(value = "DEFAULT")
|
||||
@Parameter(value = "APP_DIR")
|
||||
public void testLastArg(StartupDirectory startupDirectory) {
|
||||
final List<String> shortcutArgs = new ArrayList<>();
|
||||
if (TKit.isLinux()) {
|
||||
shortcutArgs.add("--linux-shortcut");
|
||||
} else if (TKit.isWindows()) {
|
||||
shortcutArgs.add("--win-shortcut");
|
||||
} else {
|
||||
TKit.assertUnexpected("Unsupported platform");
|
||||
}
|
||||
|
||||
if (startupDirectory == StartupDirectory.APP_DIR) {
|
||||
shortcutArgs.add(startupDirectory.asStringValue());
|
||||
}
|
||||
|
||||
Path[] predefinedAppImage = new Path[1];
|
||||
|
||||
new PackageTest().addRunOnceInitializer(() -> {
|
||||
var cmd = JPackageCommand.helloAppImage()
|
||||
.setArgumentValue("--name", "foo")
|
||||
.setFakeRuntime();
|
||||
|
||||
cmd.execute();
|
||||
|
||||
predefinedAppImage[0] = cmd.outputBundle();
|
||||
}).addInitializer(cmd -> {
|
||||
cmd.removeArgumentWithValue("--input");
|
||||
cmd.setArgumentValue("--name", "AddLShortcutDir3Test");
|
||||
cmd.addArguments("--app-image", predefinedAppImage[0]);
|
||||
cmd.ignoreDefaultVerbose(true);
|
||||
}).addInitializer(cmd -> {
|
||||
cmd.addArguments(shortcutArgs);
|
||||
}).addBundleVerifier(cmd -> {
|
||||
TKit.assertEquals(shortcutArgs.getLast(), cmd.getAllArguments().getLast(),
|
||||
"Check the last argument of jpackage command line");
|
||||
}).run(RunnablePackageTest.Action.CREATE_AND_UNPACK);
|
||||
}
|
||||
|
||||
|
@ -207,6 +264,7 @@ public class AddLShortcutTest {
|
|||
|
||||
@Test(ifNotOS = OperatingSystem.MACOS)
|
||||
@Parameter(value = "DEFAULT")
|
||||
@Parameter(value = "APP_DIR")
|
||||
public void testInvokeShortcuts(StartupDirectory startupDirectory) {
|
||||
|
||||
var testApp = TKit.TEST_SRC_ROOT.resolve("apps/PrintEnv.java");
|
||||
|
@ -219,82 +277,118 @@ public class AddLShortcutTest {
|
|||
cmd.addArguments("--arguments", "--print-workdir");
|
||||
}).addInitializer(JPackageCommand::ignoreFakeRuntime).addHelloAppInitializer(testApp + "*Hello");
|
||||
|
||||
var shortcutStartupDirectoryVerifier = new ShortcutStartupDirectoryVerifier(name, "a");
|
||||
|
||||
shortcutStartupDirectoryVerifier.applyTo(test, startupDirectory);
|
||||
|
||||
test.addInstallVerifier(cmd -> {
|
||||
if (!cmd.isPackageUnpacked("Not invoking launcher shortcuts")) {
|
||||
Collection<? extends InvokeShortcutSpec> invokeShortcutSpecs;
|
||||
if (TKit.isLinux()) {
|
||||
invokeShortcutSpecs = LinuxHelper.getInvokeShortcutSpecs(cmd);
|
||||
} else if (TKit.isWindows()) {
|
||||
invokeShortcutSpecs = WinShortcutVerifier.getInvokeShortcutSpecs(cmd);
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
shortcutStartupDirectoryVerifier.verify(invokeShortcutSpecs);
|
||||
}
|
||||
});
|
||||
new ShortcutStartupDirectoryVerifier(name).add("a", startupDirectory).applyTo(test);
|
||||
|
||||
test.run();
|
||||
}
|
||||
|
||||
|
||||
private record ShortcutStartupDirectoryVerifier(String packageName, String launcherName) {
|
||||
ShortcutStartupDirectoryVerifier {
|
||||
Objects.requireNonNull(packageName);
|
||||
Objects.requireNonNull(launcherName);
|
||||
private static final class ShortcutStartupDirectoryVerifier {
|
||||
|
||||
ShortcutStartupDirectoryVerifier(String packageName) {
|
||||
this.packageName = Objects.requireNonNull(packageName);
|
||||
}
|
||||
|
||||
void applyTo(PackageTest test, StartupDirectory startupDirectory) {
|
||||
var al = new AdditionalLauncher(launcherName);
|
||||
al.setShortcut(shortcut(), Objects.requireNonNull(startupDirectory));
|
||||
al.addJavaOptions(String.format("-Djpackage.test.appOutput=${%s}/%s",
|
||||
outputDirVarName(), expectedOutputFilename()));
|
||||
al.withoutVerifyActions(Action.EXECUTE_LAUNCHER).applyTo(test);
|
||||
}
|
||||
void applyTo(PackageTest test) {
|
||||
verifiers.values().forEach(verifier -> {
|
||||
verifier.applyTo(test);
|
||||
});
|
||||
test.addInstallVerifier(cmd -> {
|
||||
if (!cmd.isPackageUnpacked("Not invoking launcher shortcuts")) {
|
||||
Collection<? extends InvokeShortcutSpec> invokeShortcutSpecs;
|
||||
if (TKit.isLinux()) {
|
||||
invokeShortcutSpecs = LinuxHelper.getInvokeShortcutSpecs(cmd);
|
||||
} else if (TKit.isWindows()) {
|
||||
invokeShortcutSpecs = WinShortcutVerifier.getInvokeShortcutSpecs(cmd);
|
||||
} else {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
void verify(Collection<? extends InvokeShortcutSpec> invokeShortcutSpecs) throws IOException {
|
||||
var invokeShortcutSpecsMap = invokeShortcutSpecs.stream().collect(Collectors.groupingBy(InvokeShortcutSpec::launcherName));
|
||||
|
||||
TKit.trace(String.format("Verify shortcut [%s]", launcherName));
|
||||
|
||||
var expectedOutputFile = Path.of(System.getenv(outputDirVarName())).resolve(expectedOutputFilename());
|
||||
|
||||
TKit.deleteIfExists(expectedOutputFile);
|
||||
|
||||
var invokeShortcutSpec = invokeShortcutSpecs.stream().filter(v -> {
|
||||
return launcherName.equals(v.launcherName());
|
||||
}).findAny().orElseThrow();
|
||||
|
||||
invokeShortcutSpec.execute();
|
||||
|
||||
// On Linux, "gtk-launch" is used to launch a .desktop file. It is async and there is no
|
||||
// way to make it wait for exit of a process it triggers.
|
||||
TKit.waitForFileCreated(expectedOutputFile, Duration.ofSeconds(10), Duration.ofSeconds(3));
|
||||
|
||||
TKit.assertFileExists(expectedOutputFile);
|
||||
var actualStr = Files.readAllLines(expectedOutputFile).getFirst();
|
||||
|
||||
var outputPrefix = "$CD=";
|
||||
|
||||
TKit.assertTrue(actualStr.startsWith(outputPrefix), "Check output starts with '" + outputPrefix+ "' string");
|
||||
|
||||
invokeShortcutSpec.expectedWorkDirectory().ifPresent(expectedWorkDirectory -> {
|
||||
TKit.assertEquals(
|
||||
expectedWorkDirectory,
|
||||
Path.of(actualStr.substring(outputPrefix.length())),
|
||||
String.format("Check work directory of %s of launcher [%s]",
|
||||
invokeShortcutSpec.shortcut().propertyName(),
|
||||
invokeShortcutSpec.launcherName()));
|
||||
for (var e : verifiers.entrySet()) {
|
||||
e.getValue().verify(invokeShortcutSpecsMap.get(e.getKey()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private String expectedOutputFilename() {
|
||||
return String.format("%s-%s.out", packageName, launcherName);
|
||||
ShortcutStartupDirectoryVerifier add(String launcherName, StartupDirectory startupDirectory) {
|
||||
return add(new AdditionalLauncher(launcherName)
|
||||
.setShortcut(shortcut(), Objects.requireNonNull(Objects.requireNonNull(startupDirectory))));
|
||||
}
|
||||
|
||||
private String outputDirVarName() {
|
||||
ShortcutStartupDirectoryVerifier add(AdditionalLauncher addLauncher) {
|
||||
var launcherVerifier = new LauncherVerifier(addLauncher);
|
||||
verifiers.put(launcherVerifier.launcherName(), launcherVerifier);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
private final class LauncherVerifier {
|
||||
|
||||
private LauncherVerifier(AdditionalLauncher addLauncher) {
|
||||
this.addLauncher = Objects.requireNonNull(addLauncher);
|
||||
}
|
||||
|
||||
private String launcherName() {
|
||||
return addLauncher.name();
|
||||
}
|
||||
|
||||
private void applyTo(PackageTest test) {
|
||||
addLauncher.addJavaOptions(String.format("-Djpackage.test.appOutput=${%s}/%s",
|
||||
outputDirVarName(), expectedOutputFilename()));
|
||||
addLauncher.withoutVerifyActions(Action.EXECUTE_LAUNCHER).applyTo(test);
|
||||
}
|
||||
|
||||
private void verify(Collection<? extends InvokeShortcutSpec> invokeShortcutSpecs) throws IOException {
|
||||
Objects.requireNonNull(invokeShortcutSpecs);
|
||||
if (invokeShortcutSpecs.isEmpty()) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
TKit.trace(String.format("Verify shortcut [%s]", launcherName()));
|
||||
|
||||
var expectedOutputFile = Path.of(System.getenv(outputDirVarName())).resolve(expectedOutputFilename());
|
||||
|
||||
TKit.deleteIfExists(expectedOutputFile);
|
||||
|
||||
var invokeShortcutSpec = invokeShortcutSpecs.stream().filter(v -> {
|
||||
return launcherName().equals(v.launcherName());
|
||||
}).findAny().orElseThrow();
|
||||
|
||||
invokeShortcutSpec.execute();
|
||||
|
||||
// On Linux, "gtk-launch" is used to launch a .desktop file. It is async and there is no
|
||||
// way to make it wait for exit of a process it triggers.
|
||||
TKit.waitForFileCreated(expectedOutputFile, Duration.ofSeconds(10), Duration.ofSeconds(3));
|
||||
|
||||
TKit.assertFileExists(expectedOutputFile);
|
||||
var actualStr = Files.readAllLines(expectedOutputFile).getFirst();
|
||||
|
||||
var outputPrefix = "$CD=";
|
||||
|
||||
TKit.assertTrue(actualStr.startsWith(outputPrefix), "Check output starts with '" + outputPrefix+ "' string");
|
||||
|
||||
invokeShortcutSpec.expectedWorkDirectory().ifPresent(expectedWorkDirectory -> {
|
||||
TKit.assertEquals(
|
||||
expectedWorkDirectory,
|
||||
Path.of(actualStr.substring(outputPrefix.length())),
|
||||
String.format("Check work directory of %s of launcher [%s]",
|
||||
invokeShortcutSpec.shortcut().propertyName(),
|
||||
invokeShortcutSpec.launcherName()));
|
||||
});
|
||||
}
|
||||
|
||||
private String expectedOutputFilename() {
|
||||
return String.format("%s-%s.out", packageName, launcherName());
|
||||
}
|
||||
|
||||
private final AdditionalLauncher addLauncher;
|
||||
}
|
||||
|
||||
|
||||
private static String outputDirVarName() {
|
||||
if (TKit.isLinux()) {
|
||||
return "HOME";
|
||||
} else if (TKit.isWindows()) {
|
||||
|
@ -304,7 +398,7 @@ public class AddLShortcutTest {
|
|||
}
|
||||
}
|
||||
|
||||
private LauncherShortcut shortcut() {
|
||||
private static LauncherShortcut shortcut() {
|
||||
if (TKit.isLinux()) {
|
||||
return LauncherShortcut.LINUX_SHORTCUT;
|
||||
} else if (TKit.isWindows()) {
|
||||
|
@ -313,6 +407,10 @@ public class AddLShortcutTest {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private final String packageName;
|
||||
// Keep the order
|
||||
private final Map<String, LauncherVerifier> verifiers = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -576,6 +576,9 @@ public final class ErrorTest {
|
|||
);
|
||||
}).flatMap(x -> x).map(TestSpec.Builder::create).toList());
|
||||
|
||||
invalidShortcut(testCases::add, "--win-menu");
|
||||
invalidShortcut(testCases::add, "--win-shortcut");
|
||||
|
||||
return toTestArgs(testCases.stream());
|
||||
}
|
||||
|
||||
|
@ -642,6 +645,8 @@ public final class ErrorTest {
|
|||
.error("error.rpm-invalid-value-for-package-name.advice")
|
||||
).map(TestSpec.Builder::create).toList());
|
||||
|
||||
invalidShortcut(testCases::add, "--linux-shortcut");
|
||||
|
||||
return toTestArgs(testCases.stream());
|
||||
}
|
||||
|
||||
|
@ -697,6 +702,13 @@ public final class ErrorTest {
|
|||
duplicateAddArgs(builder, accumulator, "--mac-sign");
|
||||
}
|
||||
|
||||
private static void invalidShortcut(Consumer<TestSpec> accumulator, String shortcutOption) {
|
||||
Objects.requireNonNull(shortcutOption);
|
||||
Stream.of("true", "false", "").map(value -> {
|
||||
return testSpec().nativeType().addArgs(shortcutOption, value).error("error.invalid-option-value", value, shortcutOption).create();
|
||||
}).forEach(accumulator);
|
||||
}
|
||||
|
||||
private record UnsupportedPlatformOption(String name, Optional<String> value) {
|
||||
UnsupportedPlatformOption {
|
||||
Objects.requireNonNull(name);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue