8219536: Add Option for user defined jlink options

Reviewed-by: asemenyuk, almatvee
This commit is contained in:
Andy Herrick 2020-04-30 13:03:20 -04:00
parent a0d04ad0ae
commit 908e57638c
12 changed files with 239 additions and 29 deletions

View File

@ -33,7 +33,7 @@ import java.util.Map;
*/
public final class ApplicationLayout implements PathGroup.Facade<ApplicationLayout> {
enum PathRole {
RUNTIME, APP, LAUNCHERS, DESKTOP, APP_MODS, DLLS
RUNTIME, APP, LAUNCHERS, DESKTOP, APP_MODS, DLLS, RELEASE
}
ApplicationLayout(Map<Object, Path> paths) {
@ -96,6 +96,13 @@ public final class ApplicationLayout implements PathGroup.Facade<ApplicationLayo
return pathGroup().getPath(PathRole.DESKTOP);
}
/**
* Path to release file in the Java runtime directory.
*/
public Path runtimeRelease() {
return pathGroup().getPath(PathRole.RELEASE);
}
static ApplicationLayout linuxAppImage() {
return new ApplicationLayout(Map.of(
PathRole.LAUNCHERS, Path.of("bin"),
@ -103,7 +110,8 @@ public final class ApplicationLayout implements PathGroup.Facade<ApplicationLayo
PathRole.RUNTIME, Path.of("lib/runtime"),
PathRole.DESKTOP, Path.of("lib"),
PathRole.DLLS, Path.of("lib"),
PathRole.APP_MODS, Path.of("lib/app/mods")
PathRole.APP_MODS, Path.of("lib/app/mods"),
PathRole.RELEASE, Path.of("lib/runtime/release")
));
}
@ -114,7 +122,8 @@ public final class ApplicationLayout implements PathGroup.Facade<ApplicationLayo
PathRole.RUNTIME, Path.of("runtime"),
PathRole.DESKTOP, Path.of(""),
PathRole.DLLS, Path.of(""),
PathRole.APP_MODS, Path.of("app/mods")
PathRole.APP_MODS, Path.of("app/mods"),
PathRole.RELEASE, Path.of("runtime/release")
));
}
@ -125,7 +134,8 @@ public final class ApplicationLayout implements PathGroup.Facade<ApplicationLayo
PathRole.RUNTIME, Path.of("Contents/runtime"),
PathRole.DESKTOP, Path.of("Contents/Resources"),
PathRole.DLLS, Path.of("Contents/MacOS"),
PathRole.APP_MODS, Path.of("Contents/app/mods")
PathRole.APP_MODS, Path.of("Contents/app/mods"),
PathRole.RELEASE, Path.of("Contents/runtime/Contents/Home/release")
));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 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
@ -170,6 +170,11 @@ public class Arguments {
setOptionValue("arguments", arguments);
}),
JLINK_OPTIONS ("jlink-options", OptionCategories.PROPERTY, () -> {
List<String> options = getArgumentList(popArg());
setOptionValue("jlink-options", options);
}),
ICON ("icon", OptionCategories.PROPERTY),
COPYRIGHT ("copyright", OptionCategories.PROPERTY),
@ -264,6 +269,7 @@ public class Arguments {
MODULE_PATH ("module-path", "p", OptionCategories.MODULAR),
BIND_SERVICES ("bind-services", OptionCategories.PROPERTY, () -> {
showDeprecation("bind-services");
setOptionValue("bind-services", true);
}),
@ -579,7 +585,11 @@ public class Arguments {
CLIOptions.PREDEFINED_RUNTIME_IMAGE.getIdWithPrefix(),
CLIOptions.BIND_SERVICES.getIdWithPrefix());
}
if (allOptions.contains(CLIOptions.JLINK_OPTIONS)) {
throw new PackagerException("ERR_MutuallyExclusiveOptions",
CLIOptions.PREDEFINED_RUNTIME_IMAGE.getIdWithPrefix(),
CLIOptions.JLINK_OPTIONS.getIdWithPrefix());
}
}
if (hasMainJar && hasMainModule) {
throw new PackagerException("ERR_BothMainJarAndModule");
@ -809,4 +819,8 @@ public class Arguments {
return null;
}
private static void showDeprecation(String option) {
Log.error(MessageFormat.format(I18N.getString("warning.deprecation"),
option));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 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
@ -315,7 +315,8 @@ public class DeployParams {
StandardBundlerParam.MODULE_PATH.getID(),
StandardBundlerParam.ADD_MODULES.getID(),
StandardBundlerParam.LIMIT_MODULES.getID(),
StandardBundlerParam.FILE_ASSOCIATIONS.getID()
StandardBundlerParam.FILE_ASSOCIATIONS.getID(),
StandardBundlerParam.JLINK_OPTIONS.getID()
));
@SuppressWarnings("unchecked")

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 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
@ -145,6 +145,8 @@ final class JLinkBundlerHelper {
StandardBundlerParam.ADD_MODULES.fetchFrom(params);
Set<String> limitModules =
StandardBundlerParam.LIMIT_MODULES.fetchFrom(params);
List<String> options =
StandardBundlerParam.JLINK_OPTIONS.fetchFrom(params);
Path outputDir = imageBuilder.getRuntimeRoot();
File mainJar = getMainJar(params);
ModFile.ModType mainJarType = ModFile.ModType.Unknown;
@ -181,7 +183,7 @@ final class JLinkBundlerHelper {
}
runJLink(outputDir, modulePath, modules, limitModules,
new HashMap<String,String>(), bindServices);
options, bindServices);
imageBuilder.prepareApplicationFiles(params);
}
@ -316,7 +318,7 @@ final class JLinkBundlerHelper {
private static void runJLink(Path output, List<Path> modulePath,
Set<String> modules, Set<String> limitModules,
HashMap<String, String> user, boolean bindServices)
List<String> options, boolean bindServices)
throws PackagerException {
// This is just to ensure jlink is given a non-existant directory
@ -342,20 +344,19 @@ final class JLinkBundlerHelper {
args.add("--limit-modules");
args.add(getStringList(limitModules));
}
if (user != null && !user.isEmpty()) {
for (Map.Entry<String, String> entry : user.entrySet()) {
args.add(entry.getKey());
args.add(entry.getValue());
}
} else {
args.add("--strip-native-commands");
args.add("--strip-debug");
args.add("--no-man-pages");
args.add("--no-header-files");
if (bindServices) {
args.add("--bind-services");
if (options != null) {
for (String option : options) {
if (option.startsWith("--output") ||
option.startsWith("--add-modules") ||
option.startsWith("--module-path")) {
throw new PackagerException("error.blocked.option", option);
}
args.add(option);
}
}
if (bindServices) {
args.add("--bind-services");
}
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -70,6 +70,11 @@ class StandardBundlerParam<T> extends BundlerParamInfo<T> {
private static final String JAVABASEJMOD = "java.base.jmod";
private final static String DEFAULT_VERSION = "1.0";
private final static String DEFAULT_RELEASE = "1";
private final static String[] DEFAULT_JLINK_OPTIONS = {
"--strip-native-commands",
"--strip-debug",
"--no-man-pages",
"--no-header-files"};
StandardBundlerParam(String id, Class<T> valueType,
Function<Map<String, ? super Object>, T> defaultValueFunction,
@ -479,6 +484,14 @@ class StandardBundlerParam<T> extends BundlerParamInfo<T> {
(s, p) -> new LinkedHashSet<>(Arrays.asList(s.split(",")))
);
@SuppressWarnings("unchecked")
static final StandardBundlerParam<List<String>> JLINK_OPTIONS =
new StandardBundlerParam<>(
Arguments.CLIOptions.JLINK_OPTIONS.getId(),
(Class<List<String>>) (Object) List.class,
p -> Arrays.asList(DEFAULT_JLINK_OPTIONS),
(s, p) -> null);
@SuppressWarnings("unchecked")
static final BundlerParamInfo<Set<String>> LIMIT_MODULES =
new StandardBundlerParam<>(

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 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
@ -85,6 +85,7 @@ class ValidOptions {
options.put(CLIOptions.JAVA_OPTIONS.getId(), USE.LAUNCHER);
options.put(CLIOptions.ADD_LAUNCHER.getId(), USE.LAUNCHER);
options.put(CLIOptions.BIND_SERVICES.getId(), USE.LAUNCHER);
options.put(CLIOptions.JLINK_OPTIONS.getId(), USE.LAUNCHER);
options.put(CLIOptions.LICENSE_FILE.getId(), USE.INSTALL);
options.put(CLIOptions.INSTALL_DIR.getId(), USE.INSTALL);

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2017, 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
@ -107,6 +107,12 @@ Generic Options:\n\
\ --bind-services \n\
\ Pass on --bind-services option to jlink (which will link in \n\
\ service provider modules and their dependences) \n\
\ This option is deprecated. Use "--jlink-options" option instead. \n\
\ --jlink-options <jlink options> \n\
\ A space separated list of options to pass to jlink \n\
\ If not specified, defaults to "--strip-native-commands \n\
\ --strip-debug --no-man-pages --no-header-files" \n\
\ This option can be used multiple times.\n\
\ --runtime-image <file path>\n\
\ Path of the predefined runtime image that will be copied into\n\
\ the application image\n\

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2017, 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
@ -63,9 +63,11 @@ error.tool-not-found.advice=Please install {0}
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
warning.module.does.not.exist=Module [{0}] does not exist
warning.no.jdk.modules.found=Warning: No JDK Modules found
warning.deprecation=Warning: Option "{0}" is deprecated and may be removed in a future release
MSG_BundlerFailed=Error: Bundler "{1}" ({0}) failed to produce a package
MSG_BundlerConfigException=Bundler {0} skipped because of a configuration problem: {1} \n\

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2017, 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
@ -63,9 +63,11 @@ error.tool-not-found.advice={0}\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\
error.tool-old-version={0} {1}\u4EE5\u964D\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
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 option [{0}] is not permitted in --jlink-options
warning.module.does.not.exist=\u30E2\u30B8\u30E5\u30FC\u30EB[{0}]\u306F\u5B58\u5728\u3057\u307E\u305B\u3093
warning.no.jdk.modules.found=\u8B66\u544A: JDK\u30E2\u30B8\u30E5\u30FC\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093
warning.deprecation=Warning: Option "{0}" is deprecated and may be removed in a future release
MSG_BundlerFailed=\u30A8\u30E9\u30FC: \u30D0\u30F3\u30C9\u30E9"{1}" ({0})\u304C\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u751F\u6210\u306B\u5931\u6557\u3057\u307E\u3057\u305F
MSG_BundlerConfigException=\u69CB\u6210\u306E\u554F\u984C\u306E\u305F\u3081\u3001\u30D0\u30F3\u30C9\u30E9{0}\u304C\u30B9\u30AD\u30C3\u30D7\u3055\u308C\u307E\u3057\u305F: {1} \n\u6B21\u306E\u4FEE\u6B63\u3092\u884C\u3063\u3066\u304F\u3060\u3055\u3044: {2}

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2017, 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
@ -63,9 +63,11 @@ error.tool-not-found.advice=\u8BF7\u5B89\u88C5 {0}
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=jlink option [{0}] is not permitted in --jlink-options
warning.module.does.not.exist=\u6A21\u5757 [{0}] \u4E0D\u5B58\u5728
warning.no.jdk.modules.found=\u8B66\u544A: \u672A\u627E\u5230 JDK \u6A21\u5757
warning.deprecation=Warning: Option "{0}" is deprecated and may be removed in a future release
MSG_BundlerFailed=\u9519\u8BEF\uFF1A\u6253\u5305\u7A0B\u5E8F "{1}" ({0}) \u65E0\u6CD5\u751F\u6210\u7A0B\u5E8F\u5305
MSG_BundlerConfigException=\u7531\u4E8E\u914D\u7F6E\u95EE\u9898, \u8DF3\u8FC7\u4E86\u6253\u5305\u7A0B\u5E8F{0}: {1} \n\u4FEE\u590D\u5EFA\u8BAE: {2}

View File

@ -727,6 +727,19 @@ public final class JPackageCommand extends CommandArguments<JPackageCommand> {
appLauncherCfgPath(launcherName));
}
public List<String> readRuntimeReleaseFile() {
verifyIsOfType(PackageType.IMAGE);
if (isRuntime()) {
return null;
}
Path release = appLayout().runtimeRelease();
try {
return Files.readAllLines(release);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
public static String escapeAndJoin(String... args) {
return escapeAndJoin(List.of(args));
}

View File

@ -0,0 +1,145 @@
/*
* 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.
*/
package jdk.jpackage.tests;
import java.util.Collection;
import java.util.List;
import jdk.jpackage.test.Annotations.Parameters;
import jdk.jpackage.test.Annotations.Test;
import jdk.jpackage.test.JPackageCommand;
import jdk.jpackage.test.CfgFile;
import jdk.jpackage.test.TKit;
/*
* @test
* @summary jpackage application version testing
* @library ../../../../helpers
* @build jdk.jpackage.test.*
* @modules jdk.incubator.jpackage/jdk.incubator.jpackage.internal
* @compile JLinkOptionsTest.java
* @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main
* --jpt-run=jdk.jpackage.tests.JLinkOptionsTest
*/
public final class JLinkOptionsTest {
@Parameters
public static Collection input() {
return List.of(new Object[][]{
// default but with strip-native-commands removed
{"Hello", new String[]{
"--jlink-options",
"--strip-debug --no-man-pages --no-header-files",
},
// non modular should have everything
new String[]{"jdk.jartool", "jdk.unsupported"},
null,
},
// multiple jlink-options
{"com.other/com.other.Hello", new String[]{
"--jlink-options",
"--strip-debug --no-man-pages --no-header-files",
"--jlink-options",
"--bind-services",
},
// with bind-services should have some services
new String[]{"java.smartcardio", "jdk.crypto.ec"},
null,
},
// bind-services
{"Hello", new String[]{
"--jlink-options", "--bind-services",
},
// non modular should have everything
new String[]{"jdk.jartool", "jdk.unsupported"},
null,
},
// bind-services and jpackage option --bind-services (deprecated)
{"com.other/com.other.Hello", new String[]{
"--bind-services",
"--jlink-options", "--bind-services",
},
// with bind-services should have some services
new String[]{"java.smartcardio", "jdk.crypto.ec"},
null,
},
// limit modules
{"com.other/com.other.Hello", new String[]{
"--jlink-options",
"--limit-modules java.base,java.datatransfer,java.xml,java.prefs,java.desktop,com.other",
},
// should have whatever it needs
new String[]{"java.base", "com.other"},
// should not have whatever it doesn't need
new String[]{"jdk.incubator.jpackage"},
},
// bind-services and limit-options
{"com.other/com.other.Hello", new String[]{
"--bind-services",
"--jlink-options",
"--limit-modules java.base,java.datatransfer,java.xml,java.prefs,java.desktop,com.other,java.smartcardio",
},
// with bind-services should have some services
new String[]{"java.smartcardio"},
// but not limited
new String[]{"jdk.crypto.ec"},
},
});
}
public JLinkOptionsTest(String javaAppDesc, String[] jpackageArgs, String[] required, String[] prohibited) {
this.required = required;
this.prohibited = prohibited;
cmd = JPackageCommand.helloAppImage(javaAppDesc);
if (jpackageArgs != null) {
cmd.addArguments(jpackageArgs);
}
}
@Test
public void test() {
cmd.executeAndAssertHelloAppImageCreated();
List<String> release = cmd.readRuntimeReleaseFile();
List<String> mods = List.of(release.get(1));
if (required != null) {
for (String s : required) {
TKit.assertTextStream(s).label("mods").apply(mods.stream());
}
}
if (prohibited != null) {
for (String s : prohibited) {
TKit.assertTextStream(s).label("mods").negate().apply(mods.stream());
}
}
}
private final String[] required;
private final String[] prohibited;
private final JPackageCommand cmd;
}