8269387: jpackage --add-launcher should have option to not create shortcuts for additional launchers
Reviewed-by: asemenyuk, almatvee
This commit is contained in:
parent
746fe5dc68
commit
057992f206
@ -56,6 +56,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION;
|
|||||||
import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS;
|
import static jdk.jpackage.internal.StandardBundlerParam.FILE_ASSOCIATIONS;
|
||||||
import static jdk.jpackage.internal.StandardBundlerParam.ICON;
|
import static jdk.jpackage.internal.StandardBundlerParam.ICON;
|
||||||
import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE;
|
import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE;
|
||||||
|
import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT;;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to create files for desktop integration.
|
* Helper to create files for desktop integration.
|
||||||
@ -82,7 +83,7 @@ final class DesktopIntegration {
|
|||||||
// Need desktop and icon files if one of conditions is met:
|
// Need desktop and icon files if one of conditions is met:
|
||||||
// - there are file associations configured
|
// - there are file associations configured
|
||||||
// - user explicitely requested to create a shortcut
|
// - user explicitely requested to create a shortcut
|
||||||
boolean withDesktopFile = !associations.isEmpty() || SHORTCUT_HINT.fetchFrom(params);
|
boolean withDesktopFile = !associations.isEmpty() || LINUX_SHORTCUT_HINT.fetchFrom(params);
|
||||||
|
|
||||||
var curIconResource = LinuxAppImageBuilder.createIconResource(DEFAULT_ICON,
|
var curIconResource = LinuxAppImageBuilder.createIconResource(DEFAULT_ICON,
|
||||||
ICON_PNG, params, mainParams);
|
ICON_PNG, params, mainParams);
|
||||||
@ -138,28 +139,34 @@ final class DesktopIntegration {
|
|||||||
// Read launchers information from predefine app image
|
// Read launchers information from predefine app image
|
||||||
if (launchers.isEmpty() &&
|
if (launchers.isEmpty() &&
|
||||||
PREDEFINED_APP_IMAGE.fetchFrom(params) != null) {
|
PREDEFINED_APP_IMAGE.fetchFrom(params) != null) {
|
||||||
List<String> launcherPaths = AppImageFile.getLauncherNames(
|
List<AppImageFile.LauncherInfo> launcherInfos =
|
||||||
|
AppImageFile.getLaunchers(
|
||||||
PREDEFINED_APP_IMAGE.fetchFrom(params), params);
|
PREDEFINED_APP_IMAGE.fetchFrom(params), params);
|
||||||
if (!launcherPaths.isEmpty()) {
|
if (!launcherInfos.isEmpty()) {
|
||||||
launcherPaths.remove(0); // Remove main launcher
|
launcherInfos.remove(0); // Remove main launcher
|
||||||
}
|
}
|
||||||
for (var launcherPath : launcherPaths) {
|
for (var launcherInfo : launcherInfos) {
|
||||||
Map<String, ? super Object> launcherParams = new HashMap<>();
|
Map<String, ? super Object> launcherParams = new HashMap<>();
|
||||||
Arguments.putUnlessNull(launcherParams, CLIOptions.NAME.getId(),
|
Arguments.putUnlessNull(launcherParams, CLIOptions.NAME.getId(),
|
||||||
launcherPath);
|
launcherInfo.getName());
|
||||||
launcherParams = AddLauncherArguments.merge(params, launcherParams,
|
launcherParams = AddLauncherArguments.merge(params,
|
||||||
ICON.getID(), ICON_PNG.getID(), ADD_LAUNCHERS.getID(),
|
launcherParams, ICON.getID(), ICON_PNG.getID(),
|
||||||
FILE_ASSOCIATIONS.getID(), PREDEFINED_APP_IMAGE.getID());
|
ADD_LAUNCHERS.getID(), FILE_ASSOCIATIONS.getID(),
|
||||||
nestedIntegrations.add(new DesktopIntegration(thePackage,
|
PREDEFINED_APP_IMAGE.getID());
|
||||||
launcherParams, params));
|
if (launcherInfo.isShortcut()) {
|
||||||
|
nestedIntegrations.add(new DesktopIntegration(thePackage,
|
||||||
|
launcherParams, params));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (var launcherParams : launchers) {
|
for (var launcherParams : launchers) {
|
||||||
launcherParams = AddLauncherArguments.merge(params, launcherParams,
|
launcherParams = AddLauncherArguments.merge(params,
|
||||||
ICON.getID(), ICON_PNG.getID(), ADD_LAUNCHERS.getID(),
|
launcherParams, ICON.getID(), ICON_PNG.getID(),
|
||||||
FILE_ASSOCIATIONS.getID());
|
ADD_LAUNCHERS.getID(), FILE_ASSOCIATIONS.getID());
|
||||||
nestedIntegrations.add(new DesktopIntegration(thePackage,
|
if (SHORTCUT_HINT.fetchFrom(launcherParams)) {
|
||||||
launcherParams, params));
|
nestedIntegrations.add(new DesktopIntegration(thePackage,
|
||||||
|
launcherParams, params));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -567,7 +574,7 @@ final class DesktopIntegration {
|
|||||||
(s, p) -> s
|
(s, p) -> s
|
||||||
);
|
);
|
||||||
|
|
||||||
private static final StandardBundlerParam<Boolean> SHORTCUT_HINT =
|
private static final StandardBundlerParam<Boolean> LINUX_SHORTCUT_HINT =
|
||||||
new StandardBundlerParam<>(
|
new StandardBundlerParam<>(
|
||||||
Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(),
|
Arguments.CLIOptions.LINUX_SHORTCUT_HINT.getId(),
|
||||||
Boolean.class,
|
Boolean.class,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -32,6 +32,8 @@ import java.util.List;
|
|||||||
import jdk.jpackage.internal.Arguments.CLIOptions;
|
import jdk.jpackage.internal.Arguments.CLIOptions;
|
||||||
import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA;
|
import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA;
|
||||||
import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
|
import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
|
||||||
|
import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT;
|
||||||
|
import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* AddLauncherArguments
|
* AddLauncherArguments
|
||||||
@ -59,7 +61,10 @@ import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
|
|||||||
* arguments
|
* arguments
|
||||||
* java-options
|
* java-options
|
||||||
* win-console
|
* win-console
|
||||||
|
* win-shortcut
|
||||||
|
* win-menu
|
||||||
* linux-app-category
|
* linux-app-category
|
||||||
|
* linux-shortcut
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class AddLauncherArguments {
|
class AddLauncherArguments {
|
||||||
@ -109,17 +114,27 @@ class AddLauncherArguments {
|
|||||||
Arguments.putUnlessNull(bundleParams, CLIOptions.RELEASE.getId(),
|
Arguments.putUnlessNull(bundleParams, CLIOptions.RELEASE.getId(),
|
||||||
getOptionValue(CLIOptions.RELEASE));
|
getOptionValue(CLIOptions.RELEASE));
|
||||||
|
|
||||||
Arguments.putUnlessNull(bundleParams, CLIOptions.LINUX_CATEGORY.getId(),
|
|
||||||
getOptionValue(CLIOptions.LINUX_CATEGORY));
|
|
||||||
|
|
||||||
Arguments.putUnlessNull(bundleParams,
|
|
||||||
CLIOptions.WIN_CONSOLE_HINT.getId(),
|
|
||||||
getOptionValue(CLIOptions.WIN_CONSOLE_HINT));
|
|
||||||
|
|
||||||
String value = getOptionValue(CLIOptions.ICON);
|
String value = getOptionValue(CLIOptions.ICON);
|
||||||
Arguments.putUnlessNull(bundleParams, CLIOptions.ICON.getId(),
|
Arguments.putUnlessNull(bundleParams, CLIOptions.ICON.getId(),
|
||||||
(value == null) ? null : Path.of(value));
|
(value == null) ? null : Path.of(value));
|
||||||
|
|
||||||
|
if (Platform.isWindows()) {
|
||||||
|
Arguments.putUnlessNull(bundleParams,
|
||||||
|
CLIOptions.WIN_CONSOLE_HINT.getId(),
|
||||||
|
getOptionValue(CLIOptions.WIN_CONSOLE_HINT));
|
||||||
|
Arguments.putUnlessNull(bundleParams, SHORTCUT_HINT.getID(),
|
||||||
|
getOptionValue(CLIOptions.WIN_SHORTCUT_HINT));
|
||||||
|
Arguments.putUnlessNull(bundleParams, MENU_HINT.getID(),
|
||||||
|
getOptionValue(CLIOptions.WIN_MENU_HINT));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Platform.isLinux()) {
|
||||||
|
Arguments.putUnlessNull(bundleParams, CLIOptions.LINUX_CATEGORY.getId(),
|
||||||
|
getOptionValue(CLIOptions.LINUX_CATEGORY));
|
||||||
|
Arguments.putUnlessNull(bundleParams, SHORTCUT_HINT.getID(),
|
||||||
|
getOptionValue(CLIOptions.LINUX_SHORTCUT_HINT));
|
||||||
|
}
|
||||||
|
|
||||||
// "arguments" and "java-options" even if value is null:
|
// "arguments" and "java-options" even if value is null:
|
||||||
if (allArgs.containsKey(CLIOptions.ARGUMENTS.getId())) {
|
if (allArgs.containsKey(CLIOptions.ARGUMENTS.getId())) {
|
||||||
String argumentStr = getOptionValue(CLIOptions.ARGUMENTS);
|
String argumentStr = getOptionValue(CLIOptions.ARGUMENTS);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -40,12 +40,16 @@ import javax.xml.xpath.XPathConstants;
|
|||||||
import javax.xml.xpath.XPathExpressionException;
|
import javax.xml.xpath.XPathExpressionException;
|
||||||
import javax.xml.xpath.XPathFactory;
|
import javax.xml.xpath.XPathFactory;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
|
import org.w3c.dom.Node;
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
|
import org.w3c.dom.NamedNodeMap;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
import static jdk.jpackage.internal.StandardBundlerParam.VERSION;
|
import static jdk.jpackage.internal.StandardBundlerParam.VERSION;
|
||||||
import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS;
|
import static jdk.jpackage.internal.StandardBundlerParam.ADD_LAUNCHERS;
|
||||||
import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
|
import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
|
||||||
|
import static jdk.jpackage.internal.StandardBundlerParam.SHORTCUT_HINT;
|
||||||
|
import static jdk.jpackage.internal.StandardBundlerParam.MENU_HINT;
|
||||||
|
|
||||||
public class AppImageFile {
|
public class AppImageFile {
|
||||||
|
|
||||||
@ -53,7 +57,7 @@ public class AppImageFile {
|
|||||||
private final String creatorVersion;
|
private final String creatorVersion;
|
||||||
private final String creatorPlatform;
|
private final String creatorPlatform;
|
||||||
private final String launcherName;
|
private final String launcherName;
|
||||||
private final List<String> addLauncherNames;
|
private final List<LauncherInfo> addLauncherInfos;
|
||||||
|
|
||||||
private static final String FILENAME = ".jpackage.xml";
|
private static final String FILENAME = ".jpackage.xml";
|
||||||
|
|
||||||
@ -66,10 +70,10 @@ public class AppImageFile {
|
|||||||
this(null, null, null, null);
|
this(null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private AppImageFile(String launcherName, List<String> addLauncherNames,
|
private AppImageFile(String launcherName, List<LauncherInfo> launcherInfos,
|
||||||
String creatorVersion, String creatorPlatform) {
|
String creatorVersion, String creatorPlatform) {
|
||||||
this.launcherName = launcherName;
|
this.launcherName = launcherName;
|
||||||
this.addLauncherNames = addLauncherNames;
|
this.addLauncherInfos = launcherInfos;
|
||||||
this.creatorVersion = creatorVersion;
|
this.creatorVersion = creatorVersion;
|
||||||
this.creatorPlatform = creatorPlatform;
|
this.creatorPlatform = creatorPlatform;
|
||||||
}
|
}
|
||||||
@ -79,8 +83,8 @@ public class AppImageFile {
|
|||||||
* Each item in the list is not null or empty string.
|
* Each item in the list is not null or empty string.
|
||||||
* Returns empty list for application without additional launchers.
|
* Returns empty list for application without additional launchers.
|
||||||
*/
|
*/
|
||||||
List<String> getAddLauncherNames() {
|
List<LauncherInfo> getAddLaunchers() {
|
||||||
return addLauncherNames;
|
return addLauncherInfos;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,7 +135,10 @@ public class AppImageFile {
|
|||||||
for (int i = 0; i < addLaunchers.size(); i++) {
|
for (int i = 0; i < addLaunchers.size(); i++) {
|
||||||
Map<String, ? super Object> sl = addLaunchers.get(i);
|
Map<String, ? super Object> sl = addLaunchers.get(i);
|
||||||
xml.writeStartElement("add-launcher");
|
xml.writeStartElement("add-launcher");
|
||||||
xml.writeCharacters(APP_NAME.fetchFrom(sl));
|
xml.writeAttribute("name", APP_NAME.fetchFrom(sl));
|
||||||
|
xml.writeAttribute("shortcut",
|
||||||
|
SHORTCUT_HINT.fetchFrom(sl).toString());
|
||||||
|
xml.writeAttribute("menu", MENU_HINT.fetchFrom(sl).toString());
|
||||||
xml.writeEndElement();
|
xml.writeEndElement();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -156,7 +163,7 @@ public class AppImageFile {
|
|||||||
return new AppImageFile();
|
return new AppImageFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> addLaunchers = new ArrayList<>();
|
List<LauncherInfo> launcherInfos = new ArrayList<>();
|
||||||
|
|
||||||
String platform = xpathQueryNullable(xPath,
|
String platform = xpathQueryNullable(xPath,
|
||||||
"/jpackage-state/@platform", doc);
|
"/jpackage-state/@platform", doc);
|
||||||
@ -164,16 +171,23 @@ public class AppImageFile {
|
|||||||
String version = xpathQueryNullable(xPath,
|
String version = xpathQueryNullable(xPath,
|
||||||
"/jpackage-state/@version", doc);
|
"/jpackage-state/@version", doc);
|
||||||
|
|
||||||
NodeList launcherNameNodes = (NodeList) xPath.evaluate(
|
NodeList launcherNodes = (NodeList) xPath.evaluate(
|
||||||
"/jpackage-state/add-launcher/text()", doc,
|
"/jpackage-state/add-launcher", doc,
|
||||||
XPathConstants.NODESET);
|
XPathConstants.NODESET);
|
||||||
|
|
||||||
for (int i = 0; i != launcherNameNodes.getLength(); i++) {
|
for (int i = 0; i != launcherNodes.getLength(); i++) {
|
||||||
addLaunchers.add(launcherNameNodes.item(i).getNodeValue());
|
Node item = launcherNodes.item(i);
|
||||||
|
String name = getAttribute(item, "name");
|
||||||
|
String shortcut = getAttribute(item, "shortcut");
|
||||||
|
String menu = getAttribute(item, "menu");
|
||||||
|
|
||||||
|
launcherInfos.add(new LauncherInfo(name,
|
||||||
|
!("false".equals(shortcut)),
|
||||||
|
!("false".equals(menu))));
|
||||||
}
|
}
|
||||||
|
|
||||||
AppImageFile file = new AppImageFile(
|
AppImageFile file = new AppImageFile(
|
||||||
mainLauncher, addLaunchers, version, platform);
|
mainLauncher, launcherInfos, version, platform);
|
||||||
if (!file.isValid()) {
|
if (!file.isValid()) {
|
||||||
file = new AppImageFile();
|
file = new AppImageFile();
|
||||||
}
|
}
|
||||||
@ -184,6 +198,12 @@ public class AppImageFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getAttribute(Node item, String attr) {
|
||||||
|
NamedNodeMap attrs = item.getAttributes();
|
||||||
|
Node attrNode = attrs.getNamedItem(attr);
|
||||||
|
return ((attrNode == null) ? null : attrNode.getNodeValue());
|
||||||
|
}
|
||||||
|
|
||||||
public static Document readXml(Path appImageDir) throws IOException {
|
public static Document readXml(Path appImageDir) throws IOException {
|
||||||
try {
|
try {
|
||||||
Path path = getPathInAppImage(appImageDir);
|
Path path = getPathInAppImage(appImageDir);
|
||||||
@ -202,18 +222,19 @@ public class AppImageFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns list of launcher names configured for the application.
|
* Returns list of LauncherInfo objects configured for the application.
|
||||||
* The first item in the returned list is main launcher name.
|
* The first item in the returned list is main launcher.
|
||||||
* Following items in the list are names of additional launchers.
|
* Following items in the list are names of additional launchers.
|
||||||
*/
|
*/
|
||||||
static List<String> getLauncherNames(Path appImageDir,
|
static List<LauncherInfo> getLaunchers(Path appImageDir,
|
||||||
Map<String, ? super Object> params) {
|
Map<String, ? super Object> params) {
|
||||||
List<String> launchers = new ArrayList<>();
|
List<LauncherInfo> launchers = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
AppImageFile appImageInfo = AppImageFile.load(appImageDir);
|
AppImageFile appImageInfo = AppImageFile.load(appImageDir);
|
||||||
if (appImageInfo != null) {
|
if (appImageInfo != null) {
|
||||||
launchers.add(appImageInfo.getLauncherName());
|
launchers.add(new LauncherInfo(
|
||||||
launchers.addAll(appImageInfo.getAddLauncherNames());
|
appImageInfo.getLauncherName(), true, true));
|
||||||
|
launchers.addAll(appImageInfo.getAddLaunchers());
|
||||||
return launchers;
|
return launchers;
|
||||||
}
|
}
|
||||||
} catch (NoSuchFileException nsfe) {
|
} catch (NoSuchFileException nsfe) {
|
||||||
@ -226,10 +247,11 @@ public class AppImageFile {
|
|||||||
"warning.invalid-app-image"), appImageDir));
|
"warning.invalid-app-image"), appImageDir));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
// this should never be the case, but maintaining behavior of
|
||||||
|
// creating default launchers without AppImageFile present
|
||||||
|
|
||||||
launchers.add(APP_NAME.fetchFrom(params));
|
ADD_LAUNCHERS.fetchFrom(params).stream().map(APP_NAME::fetchFrom).map(
|
||||||
ADD_LAUNCHERS.fetchFrom(params).stream().map(APP_NAME::fetchFrom).forEach(
|
name -> new LauncherInfo(name, true, true)).forEach(launchers::add);
|
||||||
launchers::add);
|
|
||||||
return launchers;
|
return launchers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,15 +284,37 @@ public class AppImageFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean isValid() {
|
private boolean isValid() {
|
||||||
if (launcherName == null || launcherName.length() == 0 ||
|
if (launcherName == null || launcherName.length() == 0) {
|
||||||
addLauncherNames.indexOf("") != -1) {
|
|
||||||
// Some launchers have empty names. This is invalid.
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
for (var launcher : addLauncherInfos) {
|
||||||
// Add more validation.
|
if ("".equals(launcher.getName())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class LauncherInfo {
|
||||||
|
private String name;
|
||||||
|
private boolean shortcut;
|
||||||
|
private boolean menu;
|
||||||
|
|
||||||
|
public LauncherInfo(String name, boolean shortcut, boolean menu) {
|
||||||
|
this.name = name;
|
||||||
|
this.shortcut = shortcut;
|
||||||
|
this.menu = menu;
|
||||||
|
}
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
public boolean isShortcut() {
|
||||||
|
return shortcut;
|
||||||
|
}
|
||||||
|
public boolean isMenu() {
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -311,6 +311,24 @@ class StandardBundlerParam<T> extends BundlerParamInfo<T> {
|
|||||||
true : Boolean.valueOf(s)
|
true : Boolean.valueOf(s)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static final StandardBundlerParam<Boolean> SHORTCUT_HINT =
|
||||||
|
new StandardBundlerParam<>(
|
||||||
|
"shortcut-hint", // not directly related to a CLI option
|
||||||
|
Boolean.class,
|
||||||
|
params -> true, // defaults to true
|
||||||
|
(s, p) -> (s == null || "null".equalsIgnoreCase(s)) ?
|
||||||
|
true : Boolean.valueOf(s)
|
||||||
|
);
|
||||||
|
|
||||||
|
static final StandardBundlerParam<Boolean> MENU_HINT =
|
||||||
|
new StandardBundlerParam<>(
|
||||||
|
"menu-hint", // not directly related to a CLI option
|
||||||
|
Boolean.class,
|
||||||
|
params -> true, // defaults to true
|
||||||
|
(s, p) -> (s == null || "null".equalsIgnoreCase(s)) ?
|
||||||
|
true : Boolean.valueOf(s)
|
||||||
|
);
|
||||||
|
|
||||||
static final StandardBundlerParam<Path> RESOURCE_DIR =
|
static final StandardBundlerParam<Path> RESOURCE_DIR =
|
||||||
new StandardBundlerParam<>(
|
new StandardBundlerParam<>(
|
||||||
Arguments.CLIOptions.RESOURCE_DIR.getId(),
|
Arguments.CLIOptions.RESOURCE_DIR.getId(),
|
||||||
|
@ -135,8 +135,9 @@ Generic Options:\n\
|
|||||||
\ a list of key, value pairs\n\
|
\ a list of key, value pairs\n\
|
||||||
\ (absolute path or relative to the current directory)\n\
|
\ (absolute path or relative to the current directory)\n\
|
||||||
\ The keys "module", "main-jar", "main-class",\n\
|
\ The keys "module", "main-jar", "main-class",\n\
|
||||||
\ "arguments", "java-options", "app-version", "icon", and\n\
|
\ "arguments", "java-options", "app-version", "icon",\n\
|
||||||
\ "win-console" can be used.\n\
|
\ "win-console", "win-shortcut", "win-menu",\n\
|
||||||
|
\ "linux-app-category", and "linux-shortcut" can be used.\n\
|
||||||
\ These options are added to, or used to overwrite, the original\n\
|
\ These options are added to, or used to overwrite, the original\n\
|
||||||
\ command line options to build an additional alternative launcher.\n\
|
\ command line options to build an additional alternative launcher.\n\
|
||||||
\ The main application launcher will be built from the command line\n\
|
\ The main application launcher will be built from the command line\n\
|
||||||
|
@ -135,8 +135,9 @@ Generic Options:\n\
|
|||||||
\ a list of key, value pairs\n\
|
\ a list of key, value pairs\n\
|
||||||
\ (absolute path or relative to the current directory)\n\
|
\ (absolute path or relative to the current directory)\n\
|
||||||
\ The keys "module", "main-jar", "main-class",\n\
|
\ The keys "module", "main-jar", "main-class",\n\
|
||||||
\ "arguments", "java-options", "app-version", "icon", and\n\
|
\ "arguments", "java-options", "app-version", "icon",\n\
|
||||||
\ "win-console" can be used.\n\
|
\ "win-console", "win-shortcut", "win-menu",\n\
|
||||||
|
\ "linux-app-category", and "linux-shortcut" can be used.\n\
|
||||||
\ These options are added to, or used to overwrite, the original\n\
|
\ These options are added to, or used to overwrite, the original\n\
|
||||||
\ command line options to build an additional alternative launcher.\n\
|
\ command line options to build an additional alternative launcher.\n\
|
||||||
\ The main application launcher will be built from the command line\n\
|
\ The main application launcher will be built from the command line\n\
|
||||||
|
@ -135,8 +135,9 @@ Generic Options:\n\
|
|||||||
\ a list of key, value pairs\n\
|
\ a list of key, value pairs\n\
|
||||||
\ (absolute path or relative to the current directory)\n\
|
\ (absolute path or relative to the current directory)\n\
|
||||||
\ The keys "module", "main-jar", "main-class",\n\
|
\ The keys "module", "main-jar", "main-class",\n\
|
||||||
\ "arguments", "java-options", "app-version", "icon", and\n\
|
\ "arguments", "java-options", "app-version", "icon",\n\
|
||||||
\ "win-console" can be used.\n\
|
\ "win-console", "win-shortcut", "win-menu",\n\
|
||||||
|
\ "linux-app-category", and "linux-shortcut" can be used.\n\
|
||||||
\ These options are added to, or used to overwrite, the original\n\
|
\ These options are added to, or used to overwrite, the original\n\
|
||||||
\ command line options to build an additional alternative launcher.\n\
|
\ command line options to build an additional alternative launcher.\n\
|
||||||
\ The main application launcher will be built from the command line\n\
|
\ The main application launcher will be built from the command line\n\
|
||||||
|
@ -107,12 +107,9 @@ class WixAppImageFragmentBuilder extends WixFragmentBuilder {
|
|||||||
Collectors.toSet());
|
Collectors.toSet());
|
||||||
|
|
||||||
if (StandardBundlerParam.isRuntimeInstaller(params)) {
|
if (StandardBundlerParam.isRuntimeInstaller(params)) {
|
||||||
launcherPaths = Collections.emptyList();
|
launchers = Collections.emptyList();
|
||||||
} else {
|
} else {
|
||||||
launcherPaths = AppImageFile.getLauncherNames(appImageRoot, params).stream()
|
launchers = AppImageFile.getLaunchers(appImageRoot, params);
|
||||||
.map(name -> installedAppImage.launchersDirectory().resolve(name))
|
|
||||||
.map(WixAppImageFragmentBuilder::addExeSuffixToPath)
|
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
programMenuFolderName = MENU_GROUP.fetchFrom(params);
|
programMenuFolderName = MENU_GROUP.fetchFrom(params);
|
||||||
@ -411,13 +408,23 @@ class WixAppImageFragmentBuilder extends WixFragmentBuilder {
|
|||||||
XMLStreamException, IOException {
|
XMLStreamException, IOException {
|
||||||
List<String> componentIds = new ArrayList<>();
|
List<String> componentIds = new ArrayList<>();
|
||||||
Set<ShortcutsFolder> defineShortcutFolders = new HashSet<>();
|
Set<ShortcutsFolder> defineShortcutFolders = new HashSet<>();
|
||||||
for (var launcherPath : launcherPaths) {
|
for (var launcher : launchers) {
|
||||||
for (var folder : shortcutFolders) {
|
for (var folder : shortcutFolders) {
|
||||||
String componentId = addShortcutComponent(xml, launcherPath,
|
Path launcherPath = addExeSuffixToPath(installedAppImage
|
||||||
folder);
|
.launchersDirectory().resolve(launcher.getName()));
|
||||||
if (componentId != null) {
|
|
||||||
defineShortcutFolders.add(folder);
|
if ((launcher.isMenu() &&
|
||||||
componentIds.add(componentId);
|
(folder.equals(ShortcutsFolder.ProgramMenu))) ||
|
||||||
|
(launcher.isShortcut() &&
|
||||||
|
(folder.equals(ShortcutsFolder.Desktop)))) {
|
||||||
|
|
||||||
|
String componentId = addShortcutComponent(xml, launcherPath,
|
||||||
|
folder);
|
||||||
|
|
||||||
|
if (componentId != null) {
|
||||||
|
defineShortcutFolders.add(folder);
|
||||||
|
componentIds.add(componentId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -824,7 +831,7 @@ class WixAppImageFragmentBuilder extends WixFragmentBuilder {
|
|||||||
|
|
||||||
private Set<ShortcutsFolder> shortcutFolders;
|
private Set<ShortcutsFolder> shortcutFolders;
|
||||||
|
|
||||||
private List<Path> launcherPaths;
|
private List<AppImageFile.LauncherInfo> launchers;
|
||||||
|
|
||||||
private ApplicationLayout appImage;
|
private ApplicationLayout appImage;
|
||||||
private ApplicationLayout installedAppImage;
|
private ApplicationLayout installedAppImage;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -81,6 +81,12 @@ public final class AdditionalLauncher {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AdditionalLauncher setShortcuts(boolean menu, boolean shortcut) {
|
||||||
|
withMenuShortcut = menu;
|
||||||
|
withShortcut = shortcut;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public AdditionalLauncher setIcon(Path iconPath) {
|
public AdditionalLauncher setIcon(Path iconPath) {
|
||||||
if (iconPath == NO_ICON) {
|
if (iconPath == NO_ICON) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
@ -143,6 +149,18 @@ public final class AdditionalLauncher {
|
|||||||
properties.add(Map.entry("icon", iconPath));
|
properties.add(Map.entry("icon", iconPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (withShortcut != null) {
|
||||||
|
if (TKit.isLinux()) {
|
||||||
|
properties.add(Map.entry("linux-shortcut", withShortcut.toString()));
|
||||||
|
} else if (TKit.isWindows()) {
|
||||||
|
properties.add(Map.entry("win-shortcut", withShortcut.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TKit.isWindows() && withMenuShortcut != null) {
|
||||||
|
properties.add(Map.entry("win-menu", withMenuShortcut.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
properties.addAll(rawProperties);
|
properties.addAll(rawProperties);
|
||||||
|
|
||||||
createFileHandler.accept(propsFile, properties);
|
createFileHandler.accept(propsFile, properties);
|
||||||
@ -178,7 +196,7 @@ public final class AdditionalLauncher {
|
|||||||
() -> iconInResourceDir(cmd, name));
|
() -> iconInResourceDir(cmd, name));
|
||||||
while (effectiveIcon != NO_ICON) {
|
while (effectiveIcon != NO_ICON) {
|
||||||
if (effectiveIcon != null) {
|
if (effectiveIcon != null) {
|
||||||
withLinuxDesktopFile = true;
|
withLinuxDesktopFile = Boolean.FALSE != withShortcut;
|
||||||
verifier.setExpectedIcon(effectiveIcon);
|
verifier.setExpectedIcon(effectiveIcon);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -186,7 +204,7 @@ public final class AdditionalLauncher {
|
|||||||
Path customMainLauncherIcon = cmd.getArgumentValue("--icon",
|
Path customMainLauncherIcon = cmd.getArgumentValue("--icon",
|
||||||
() -> iconInResourceDir(cmd, null), Path::of);
|
() -> iconInResourceDir(cmd, null), Path::of);
|
||||||
if (customMainLauncherIcon != null) {
|
if (customMainLauncherIcon != null) {
|
||||||
withLinuxDesktopFile = true;
|
withLinuxDesktopFile = Boolean.FALSE != withShortcut;
|
||||||
verifier.setExpectedIcon(customMainLauncherIcon);
|
verifier.setExpectedIcon(customMainLauncherIcon);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -197,8 +215,8 @@ public final class AdditionalLauncher {
|
|||||||
|
|
||||||
if (TKit.isLinux() && !cmd.isImagePackageType()) {
|
if (TKit.isLinux() && !cmd.isImagePackageType()) {
|
||||||
if (effectiveIcon != NO_ICON && !withLinuxDesktopFile) {
|
if (effectiveIcon != NO_ICON && !withLinuxDesktopFile) {
|
||||||
withLinuxDesktopFile = Stream.of("--linux-shortcut").anyMatch(
|
withLinuxDesktopFile = (Boolean.FALSE != withShortcut) &&
|
||||||
cmd::hasArgument);
|
Stream.of("--linux-shortcut").anyMatch(cmd::hasArgument);
|
||||||
verifier.setExpectedDefaultIcon();
|
verifier.setExpectedDefaultIcon();
|
||||||
}
|
}
|
||||||
Path desktopFile = LinuxHelper.getDesktopFile(cmd, name);
|
Path desktopFile = LinuxHelper.getDesktopFile(cmd, name);
|
||||||
@ -212,8 +230,21 @@ public final class AdditionalLauncher {
|
|||||||
verifier.applyTo(cmd);
|
verifier.applyTo(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void verifyShortcuts(JPackageCommand cmd) throws IOException {
|
||||||
|
if (TKit.isLinux() && !cmd.isImagePackageType()
|
||||||
|
&& withShortcut != null) {
|
||||||
|
Path desktopFile = LinuxHelper.getDesktopFile(cmd, name);
|
||||||
|
if (withShortcut) {
|
||||||
|
TKit.assertFileExists(desktopFile);
|
||||||
|
} else {
|
||||||
|
TKit.assertPathExists(desktopFile, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void verify(JPackageCommand cmd) throws IOException {
|
private void verify(JPackageCommand cmd) throws IOException {
|
||||||
verifyIcon(cmd);
|
verifyIcon(cmd);
|
||||||
|
verifyShortcuts(cmd);
|
||||||
|
|
||||||
Path launcherPath = cmd.appLauncherPath(name);
|
Path launcherPath = cmd.appLauncherPath(name);
|
||||||
|
|
||||||
@ -240,6 +271,8 @@ public final class AdditionalLauncher {
|
|||||||
private final String name;
|
private final String name;
|
||||||
private final List<Map.Entry<String, String>> rawProperties;
|
private final List<Map.Entry<String, String>> rawProperties;
|
||||||
private BiConsumer<Path, List<Map.Entry<String, String>>> createFileHandler;
|
private BiConsumer<Path, List<Map.Entry<String, String>>> createFileHandler;
|
||||||
|
private Boolean withMenuShortcut;
|
||||||
|
private Boolean withShortcut;
|
||||||
|
|
||||||
private final static Path NO_ICON = Path.of("");
|
private final static Path NO_ICON = Path.of("");
|
||||||
}
|
}
|
||||||
|
@ -104,8 +104,8 @@ public class AppImageFileTest {
|
|||||||
"<launcher></launcher>",
|
"<launcher></launcher>",
|
||||||
"</jpackage-state>");
|
"</jpackage-state>");
|
||||||
Assert.assertEquals("Foo", file.getLauncherName());
|
Assert.assertEquals("Foo", file.getLauncherName());
|
||||||
Assert.assertArrayEquals(new String[0],
|
|
||||||
file.getAddLauncherNames().toArray(String[]::new));
|
Assert.assertEquals(0, file.getAddLaunchers().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -119,7 +119,7 @@ public class AppImageFileTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddLauncherNames() throws IOException {
|
public void testAddLaunchers() throws IOException {
|
||||||
Map<String, ? super Object> params = new LinkedHashMap<>();
|
Map<String, ? super Object> params = new LinkedHashMap<>();
|
||||||
List<Map<String, ? super Object>> launchersAsMap = new ArrayList<>();
|
List<Map<String, ? super Object>> launchersAsMap = new ArrayList<>();
|
||||||
|
|
||||||
@ -136,10 +136,14 @@ public class AppImageFileTest {
|
|||||||
params.put("add-launcher", launchersAsMap);
|
params.put("add-launcher", launchersAsMap);
|
||||||
AppImageFile aif = create(params);
|
AppImageFile aif = create(params);
|
||||||
|
|
||||||
List<String> addLauncherNames = aif.getAddLauncherNames();
|
List<AppImageFile.LauncherInfo> addLaunchers = aif.getAddLaunchers();
|
||||||
Assert.assertEquals(2, addLauncherNames.size());
|
Assert.assertEquals(2, addLaunchers.size());
|
||||||
Assert.assertTrue(addLauncherNames.contains("Launcher2Name"));
|
List<String> names = new ArrayList<String>();
|
||||||
Assert.assertTrue(addLauncherNames.contains("Launcher3Name"));
|
names.add(addLaunchers.get(0).getName());
|
||||||
|
names.add(addLaunchers.get(1).getName());
|
||||||
|
|
||||||
|
Assert.assertTrue(names.contains("Launcher2Name"));
|
||||||
|
Assert.assertTrue(names.contains("Launcher3Name"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +154,7 @@ public class AppImageFileTest {
|
|||||||
|
|
||||||
private void assertInvalid(AppImageFile file) {
|
private void assertInvalid(AppImageFile file) {
|
||||||
Assert.assertNull(file.getLauncherName());
|
Assert.assertNull(file.getLauncherName());
|
||||||
Assert.assertNull(file.getAddLauncherNames());
|
Assert.assertNull(file.getAddLaunchers());
|
||||||
}
|
}
|
||||||
|
|
||||||
private AppImageFile createFromXml(String... xmlData) throws IOException {
|
private AppImageFile createFromXml(String... xmlData) throws IOException {
|
||||||
|
114
test/jdk/tools/jpackage/share/AddLShortcutTest.java
Normal file
114
test/jdk/tools/jpackage/share/AddLShortcutTest.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.lang.invoke.MethodHandles;
|
||||||
|
import jdk.jpackage.test.PackageTest;
|
||||||
|
import jdk.jpackage.test.FileAssociations;
|
||||||
|
import jdk.jpackage.test.AdditionalLauncher;
|
||||||
|
import jdk.jpackage.test.TKit;
|
||||||
|
import jdk.jpackage.test.Annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test --add-launcher parameter with shortcuts (platform permitting).
|
||||||
|
* Output of the test should be AddLShortcutTest*.* installer.
|
||||||
|
* The output installer should provide the same functionality as the
|
||||||
|
* default installer (see description of the default installer in
|
||||||
|
* SimplePackageTest.java) plus install extra application launchers with and
|
||||||
|
* without various shortcuts to be tested manually.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @summary jpackage with --add-launcher
|
||||||
|
* @key jpackagePlatformPackage
|
||||||
|
* @library ../helpers
|
||||||
|
* @build jdk.jpackage.test.*
|
||||||
|
* @modules jdk.jpackage/jdk.jpackage.internal
|
||||||
|
* @compile AddLShortcutTest.java
|
||||||
|
* @run main/othervm/timeout=540 -Xmx512m jdk.jpackage.test.Main
|
||||||
|
* --jpt-run=AddLShortcutTest
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AddLShortcutTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
// Configure several additional launchers with each combination of
|
||||||
|
// possible shortcut hints in add-launcher property file.
|
||||||
|
// default is true so Foo (no property), and Bar (properties set to "true")
|
||||||
|
// will have shortcuts while other launchers with some properties set
|
||||||
|
// to "false" will have none.
|
||||||
|
|
||||||
|
PackageTest packageTest = new PackageTest().configureHelloApp();
|
||||||
|
packageTest.addInitializer(cmd -> {
|
||||||
|
cmd.addArguments("--arguments", "Duke", "--arguments", "is",
|
||||||
|
"--arguments", "the", "--arguments", "King");
|
||||||
|
if (TKit.isWindows()) {
|
||||||
|
cmd.addArguments("--win-shortcut", "--win-menu");
|
||||||
|
} else if (TKit.isLinux()) {
|
||||||
|
cmd.addArguments("--linux-shortcut");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
new FileAssociations(
|
||||||
|
MethodHandles.lookup().lookupClass().getSimpleName()).applyTo(
|
||||||
|
packageTest);
|
||||||
|
|
||||||
|
new AdditionalLauncher("Foo")
|
||||||
|
.setDefaultArguments("yep!")
|
||||||
|
.setIcon(GOLDEN_ICON)
|
||||||
|
.applyTo(packageTest);
|
||||||
|
|
||||||
|
new AdditionalLauncher("Bar")
|
||||||
|
.setDefaultArguments("one", "two", "three")
|
||||||
|
.setIcon(GOLDEN_ICON)
|
||||||
|
.setShortcuts(true, true)
|
||||||
|
.applyTo(packageTest);
|
||||||
|
|
||||||
|
new AdditionalLauncher("Launcher3")
|
||||||
|
.setDefaultArguments()
|
||||||
|
.setIcon(GOLDEN_ICON)
|
||||||
|
.setShortcuts(false, false)
|
||||||
|
.applyTo(packageTest);
|
||||||
|
|
||||||
|
new AdditionalLauncher("Launcher4")
|
||||||
|
.setDefaultArguments()
|
||||||
|
.setIcon(GOLDEN_ICON)
|
||||||
|
.setShortcuts(true, false)
|
||||||
|
.applyTo(packageTest);
|
||||||
|
|
||||||
|
new AdditionalLauncher("Launcher5")
|
||||||
|
.setDefaultArguments()
|
||||||
|
.setIcon(GOLDEN_ICON)
|
||||||
|
.setShortcuts(false, true)
|
||||||
|
.applyTo(packageTest);
|
||||||
|
|
||||||
|
packageTest.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static Path GOLDEN_ICON = TKit.TEST_SRC_ROOT.resolve(Path.of(
|
||||||
|
"resources", "icon" + TKit.ICON_SUFFIX));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user