8256475: Fix Behavior when Installer name differs from application name.

Reviewed-by: asemenyuk, almatvee, kizune
This commit is contained in:
Andy Herrick 2020-11-24 14:56:23 +00:00
parent fa3cfcd0cd
commit 303631e3d5
18 changed files with 203 additions and 40 deletions

View File

@ -47,6 +47,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import static jdk.jpackage.internal.OverridableResource.createResource;
import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME;
import static jdk.jpackage.internal.StandardBundlerParam.VERSION;
import static jdk.jpackage.internal.StandardBundlerParam.RELEASE;
import static jdk.jpackage.internal.StandardBundlerParam.VENDOR;
@ -71,8 +72,7 @@ public class LinuxDebBundler extends LinuxPackageBundler {
Arguments.CLIOptions.LINUX_BUNDLE_NAME.getId(),
String.class,
params -> {
String nm = APP_NAME.fetchFrom(params);
String nm = INSTALLER_NAME.fetchFrom(params);
if (nm == null) return null;
// make sure to lower case and spaces/underscores become dashes

View File

@ -38,6 +38,7 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME;
import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE;
import static jdk.jpackage.internal.StandardBundlerParam.VERSION;
import static jdk.jpackage.internal.StandardBundlerParam.RELEASE;
@ -73,7 +74,7 @@ public class LinuxRpmBundler extends LinuxPackageBundler {
Arguments.CLIOptions.LINUX_BUNDLE_NAME.getId(),
String.class,
params -> {
String nm = APP_NAME.fetchFrom(params);
String nm = INSTALLER_NAME.fetchFrom(params);
if (nm == null) return null;
// make sure to lower case and spaces become dashes

View File

@ -143,7 +143,7 @@ public class MacAppStoreBundler extends MacBaseInstallerBundler {
ProcessBuilder pb;
// create the final pkg file
Path finalPKG = outdir.resolve(INSTALLER_NAME.fetchFrom(params)
Path finalPKG = outdir.resolve(MAC_INSTALLER_NAME.fetchFrom(params)
+ INSTALLER_SUFFIX.fetchFrom(params)
+ ".pkg");
Files.createDirectories(outdir);

View File

@ -37,6 +37,7 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME;
import static jdk.jpackage.internal.StandardBundlerParam.INSTALL_DIR;
import static jdk.jpackage.internal.StandardBundlerParam.PREDEFINED_APP_IMAGE;
import static jdk.jpackage.internal.StandardBundlerParam.VERSION;
@ -75,12 +76,12 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler {
params -> "",
null);
public static final BundlerParamInfo<String> INSTALLER_NAME =
public static final BundlerParamInfo<String> MAC_INSTALLER_NAME =
new StandardBundlerParam<> (
"mac.installerName",
String.class,
params -> {
String nm = APP_NAME.fetchFrom(params);
String nm = INSTALLER_NAME.fetchFrom(params);
if (nm == null) return null;
String version = VERSION.fetchFrom(params);

View File

@ -270,7 +270,7 @@ public class MacDmgBundler extends MacBaseInstallerBundler {
}
Path protoDMG = imagesRoot.resolve(APP_NAME.fetchFrom(params) +"-tmp.dmg");
Path finalDMG = outdir.resolve(INSTALLER_NAME.fetchFrom(params)
Path finalDMG = outdir.resolve(MAC_INSTALLER_NAME.fetchFrom(params)
+ INSTALLER_SUFFIX.fetchFrom(params) + ".dmg");
Path srcFolder = APP_IMAGE_TEMP_ROOT.fetchFrom(params);

View File

@ -448,7 +448,7 @@ public class MacPkgBundler extends MacBaseInstallerBundler {
IOUtils.exec(pb);
// build final package
Path finalPKG = outdir.resolve(INSTALLER_NAME.fetchFrom(params)
Path finalPKG = outdir.resolve(MAC_INSTALLER_NAME.fetchFrom(params)
+ INSTALLER_SUFFIX.fetchFrom(params)
+ ".pkg");
Files.createDirectories(outdir);

View File

@ -31,6 +31,7 @@ import java.util.Map;
import java.util.List;
import jdk.jpackage.internal.Arguments.CLIOptions;
import static jdk.jpackage.internal.StandardBundlerParam.LAUNCHER_DATA;
import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
/*
* AddLauncherArguments
@ -158,8 +159,10 @@ class AddLauncherArguments {
Map<String, ? super Object> tmp = new HashMap<>(original);
List.of(exclude).forEach(tmp::remove);
// remove LauncherData from map so it will re-run the defaultValueFunction
// remove LauncherData from map so it will be re-computed
tmp.remove(LAUNCHER_DATA.getID());
// remove "application-name" so it will be re-computed
tmp.remove(APP_NAME.getID());
if (additional.containsKey(CLIOptions.MODULE.getId())) {
tmp.remove(CLIOptions.MAIN_JAR.getId());

View File

@ -233,6 +233,16 @@ public class AppImageFile {
return launchers;
}
public static String extractAppName(Path appImageDir) {
try {
return AppImageFile.load(appImageDir).getLauncherName();
} catch (IOException ioe) {
Log.verbose(MessageFormat.format(I18N.getString(
"warning.foreign-app-image"), appImageDir));
return null;
}
}
private static String xpathQueryNullable(XPath xPath, String xpathExpr,
Document xml) throws XPathExpressionException {
NodeList nodes = (NodeList) xPath.evaluate(xpathExpr, xml,

View File

@ -128,25 +128,59 @@ class StandardBundlerParam<T> extends BundlerParamInfo<T> {
(s, p) -> Path.of(s)
);
static final StandardBundlerParam<String> APP_NAME =
static final StandardBundlerParam<Path> PREDEFINED_APP_IMAGE =
new StandardBundlerParam<>(
Arguments.CLIOptions.PREDEFINED_APP_IMAGE.getId(),
Path.class,
params -> null,
(s, p) -> Path.of(s));
// this is the raw --app-name arg - used in APP_NAME and INSTALLER_NAME
static final StandardBundlerParam<String> NAME =
new StandardBundlerParam<>(
Arguments.CLIOptions.NAME.getId(),
String.class,
params -> null,
(s, p) -> s
);
// this is the application name, either from the app-image (if given),
// the name (if given) derived from the main-class, or the runtime image
static final StandardBundlerParam<String> APP_NAME =
new StandardBundlerParam<>(
"application-name",
String.class,
params -> {
String s = MAIN_CLASS.fetchFrom(params);
if (s != null) {
int idx = s.lastIndexOf(".");
if (idx >= 0) {
return s.substring(idx+1);
}
return s;
} else if (isRuntimeInstaller(params)) {
Path f = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params);
if (f != null) {
return f.getFileName().toString();
Path appImage = PREDEFINED_APP_IMAGE.fetchFrom(params);
String appName = NAME.fetchFrom(params);
if (appImage != null) {
String name = AppImageFile.extractAppName(appImage);
appName = (name != null) ? name : appName;
} else if (appName == null) {
String s = MAIN_CLASS.fetchFrom(params);
if (s != null) {
int idx = s.lastIndexOf(".");
appName = (idx < 0) ? s : s.substring(idx+1);
} else if (isRuntimeInstaller(params)) {
Path f = PREDEFINED_RUNTIME_IMAGE.fetchFrom(params);
if (f != null) {
appName = f.getFileName().toString();
}
}
}
return null;
return appName;
},
(s, p) -> s
);
static final StandardBundlerParam<String> INSTALLER_NAME =
new StandardBundlerParam<>(
"installer-name",
String.class,
params -> {
String installerName = NAME.fetchFrom(params);
return (installerName != null) ? installerName :
APP_NAME.fetchFrom(params);
},
(s, p) -> s
);
@ -285,12 +319,6 @@ class StandardBundlerParam<T> extends BundlerParamInfo<T> {
(s, p) -> s
);
static final StandardBundlerParam<Path> PREDEFINED_APP_IMAGE =
new StandardBundlerParam<>(
Arguments.CLIOptions.PREDEFINED_APP_IMAGE.getId(),
Path.class,
params -> null,
(s, p) -> Path.of(s));
@SuppressWarnings("unchecked")
static final StandardBundlerParam<List<Map<String, ? super Object>>> ADD_LAUNCHERS =

View File

@ -72,6 +72,7 @@ error.tool-old-version=Can not find {0} {1} or newer
error.tool-old-version.advice=Please install {0} {1} or newer
error.jlink.failed=jlink failed with: {0}
error.blocked.option=jlink option [{0}] is not permitted in --jlink-options
error.no.name=Name not specified with --name and cannot infer one from app-image
warning.no.jdk.modules.found=Warning: No JDK Modules found
warning.foreign-app-image=Warning: app-image dir ({0}) not generated by jpackage.

View File

@ -72,6 +72,7 @@ error.tool-old-version={0} {1}\u4EE5\u964D\u304C\u898B\u3064\u304B\u308A\u307E\u
error.tool-old-version.advice={0} {1}\u4EE5\u964D\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066\u304F\u3060\u3055\u3044
error.jlink.failed=jlink\u304C\u6B21\u3067\u5931\u6557\u3057\u307E\u3057\u305F: {0}
error.blocked.option=jlink\u30AA\u30D7\u30B7\u30E7\u30F3[{0}]\u306F--jlink-options\u3067\u306F\u8A31\u53EF\u3055\u308C\u307E\u305B\u3093
error.no.name=Name not specified with --name and cannot infer one from app-image
warning.no.jdk.modules.found=\u8B66\u544A: JDK\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
warning.foreign-app-image=Warning: app-image dir ({0}) not generated by jpackage.

View File

@ -72,6 +72,7 @@ error.tool-old-version=\u627E\u4E0D\u5230 {0} {1}\u6216\u66F4\u65B0\u7248\u672C
error.tool-old-version.advice=\u8BF7\u5B89\u88C5 {0} {1}\u6216\u66F4\u65B0\u7248\u672C
error.jlink.failed=jlink \u5931\u8D25\uFF0C\u51FA\u73B0 {0}
error.blocked.option=\u4E0D\u5141\u8BB8\u5728 --jlink-options \u4E2D\u4F7F\u7528 jlink \u9009\u9879 [{0}]
error.no.name=Name not specified with --name and cannot infer one from app-image
warning.no.jdk.modules.found=\u8B66\u544A: \u672A\u627E\u5230 JDK \u6A21\u5757
warning.foreign-app-image=Warning: app-image dir ({0}) not generated by jpackage.

View File

@ -56,6 +56,7 @@ import javax.xml.xpath.XPathFactory;
import static jdk.jpackage.internal.OverridableResource.createResource;
import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME;
import static jdk.jpackage.internal.StandardBundlerParam.INSTALLER_NAME;
import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT;
import static jdk.jpackage.internal.StandardBundlerParam.DESCRIPTION;
import static jdk.jpackage.internal.StandardBundlerParam.LICENSE_FILE;
@ -171,7 +172,7 @@ public class WinMsiBundler extends AbstractBundler {
"win.installerName",
String.class,
params -> {
String nm = APP_NAME.fetchFrom(params);
String nm = INSTALLER_NAME.fetchFrom(params);
if (nm == null) return null;
String version = VERSION.fetchFrom(params);
@ -305,23 +306,21 @@ public class WinMsiBundler extends AbstractBundler {
private void prepareProto(Map<String, ? super Object> params)
throws PackagerException, IOException {
Path appImage = StandardBundlerParam.getPredefinedAppImage(params);
String appName = APP_NAME.fetchFrom(params);
Path appDir;
String appName;
if (appName == null) {
// Can happen when no name is given, and using a foreign app-image
throw new PackagerException("error.no.name");
}
// we either have an application image or need to build one
if (appImage != null) {
appDir = MSI_IMAGE_DIR.fetchFrom(params).resolve(APP_NAME.fetchFrom(params));
appDir = MSI_IMAGE_DIR.fetchFrom(params).resolve(appName);
// copy everything from appImage dir into appDir/name
IOUtils.copyRecursive(appImage, appDir);
try {
appName = AppImageFile.load(appDir).getLauncherName();
} catch (Exception e) {
appName = APP_NAME.fetchFrom(params);
}
} else {
appDir = appImageBundler.execute(params, MSI_IMAGE_DIR.fetchFrom(
params));
appName = APP_NAME.fetchFrom(params);
}
// Configure installer icon

View File

@ -209,9 +209,28 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> {
}
public String name() {
String appImage = getArgumentValue("--app-image", () -> null);
if (appImage != null) {
String name = AppImageFile.extractAppName(Path.of(appImage));
// can be null if using foreign app-image
return ((name != null) ? name : getArgumentValue("--name"));
}
return getArgumentValue("--name", () -> getArgumentValue("--main-class"));
}
public String installerName() {
verifyIsOfType(PackageType.NATIVE);
String installerName = getArgumentValue("--name",
() -> getArgumentValue("--main-class", () -> null));
if (installerName == null) {
String appImage = getArgumentValue("--app-image");
if (appImage != null) {
installerName = AppImageFile.extractAppName(Path.of(appImage));
}
}
return installerName;
}
public boolean isRuntime() {
return hasArgument("--runtime-image")
&& !hasArgument("--main-jar")

View File

@ -51,7 +51,7 @@ public class LinuxHelper {
public static String getPackageName(JPackageCommand cmd) {
cmd.verifyIsOfType(PackageType.LINUX);
return cmd.getArgumentValue("--linux-package-name",
() -> cmd.name().toLowerCase());
() -> cmd.installerName().toLowerCase());
}
public static Path getDesktopFile(JPackageCommand cmd) {

View File

@ -194,7 +194,7 @@ public class MacHelper {
private static String getPackageName(JPackageCommand cmd) {
return cmd.getArgumentValue("--mac-package-name",
() -> cmd.name());
() -> cmd.installerName());
}
public static final class PListWrapper {

View File

@ -40,7 +40,7 @@ public class WindowsHelper {
static String getBundleName(JPackageCommand cmd) {
cmd.verifyIsOfType(PackageType.WINDOWS);
return String.format("%s-%s%s", cmd.name(), cmd.version(),
return String.format("%s-%s%s", cmd.installerName(), cmd.version(),
cmd.packageType().getSuffix());
}

View File

@ -0,0 +1,99 @@
/*
* Copyright (c) 2020, 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.IOException;
import jdk.jpackage.test.PackageTest;
import jdk.jpackage.test.PackageType;
import jdk.jpackage.test.TKit;
import jdk.jpackage.test.Annotations.Test;
import jdk.jpackage.test.Annotations.Parameter;
import jdk.jpackage.test.JPackageCommand;
/**
* Test creation of packages in tho phases with different names.
* The first phase creates and app image, and the second phase uses that image.
* If the first phase has no --name, it will derive name from main-class.
* If the second phase has no --name, will derive it from the app-image content.
* The resulting name may differ, and all should still work
*/
/*
* @test
* @summary Multiple names in two phases
* @library ../helpers
* @library /test/lib
* @key jpackagePlatformPackage
* @requires (jpackage.test.SQETest == null)
* @build jdk.jpackage.test.*
* @modules jdk.jpackage/jdk.jpackage.internal
* @compile MultiNameTwoPhaseTest.java
* @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=MultiNameTwoPhaseTest
*/
public class MultiNameTwoPhaseTest {
@Test
@Parameter({"MultiNameTest", "MultiNameTest"})
@Parameter({"MultiNameTest", "MultiNameTestInstaller"})
@Parameter({"MultiNameTest", ""})
@Parameter({"", "MultiNameTestInstaller"})
@Parameter({"", ""})
public static void test(String... testArgs) throws IOException {
String appName = testArgs[0];
String installName = testArgs[1];
Path appimageOutput = TKit.createTempDirectory("appimage");
JPackageCommand appImageCmd = JPackageCommand.helloAppImage()
.setArgumentValue("--dest", appimageOutput)
.removeArgumentWithValue("--name");
if (!appName.isEmpty()) {
appImageCmd.addArguments("--name", appName);
}
PackageTest packageTest = new PackageTest()
.addRunOnceInitializer(() -> appImageCmd.execute())
.addBundleDesktopIntegrationVerifier(true)
.addInitializer(cmd -> {
cmd.addArguments("--app-image", appImageCmd.outputBundle());
cmd.removeArgumentWithValue("--input");
cmd.removeArgumentWithValue("--name");
if (!installName.isEmpty()) {
cmd.addArguments("--name", installName);
}
})
.forTypes(PackageType.WINDOWS)
.addInitializer(cmd -> {
cmd.addArguments("--win-shortcut", "--win-menu",
"--win-menu-group", "MultiNameTwoPhaseTest");
})
.forTypes(PackageType.LINUX)
.addInitializer(cmd -> {
cmd.addArguments("--linux-shortcut");
});
packageTest.run();
}
}