--- old/src/jdk.jpackage/share/classes/jdk/jpackage/internal/JLinkBundlerHelper.java 2019-11-18 20:55:36.339768700 -0500 +++ /dev/null 2019-11-18 20:55:37.000000000 -0500 @@ -1,464 +0,0 @@ -/* - * Copyright (c) 2015, 2019, 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; - -import java.io.File; -import java.io.IOException; -import java.io.StringReader; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.ResourceBundle; -import java.util.Set; -import java.util.Optional; -import java.util.Arrays; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.regex.Matcher; -import java.util.spi.ToolProvider; -import java.lang.module.Configuration; -import java.lang.module.ResolvedModule; -import java.lang.module.ModuleDescriptor; -import java.lang.module.ModuleFinder; -import java.lang.module.ModuleReference; - -final class JLinkBundlerHelper { - - private static final ResourceBundle I18N = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.MainResources"); - private static final String JRE_MODULES_FILENAME = - "jdk/jpackage/internal/resources/jre.list"; - private static final String SERVER_JRE_MODULES_FILENAME = - "jdk/jpackage/internal/resources/jre.module.list"; - - static final ToolProvider JLINK_TOOL = - ToolProvider.findFirst("jlink").orElseThrow(); - - private JLinkBundlerHelper() {} - - @SuppressWarnings("unchecked") - static final BundlerParamInfo DEBUG = - new StandardBundlerParam<>( - "-J-Xdebug", - Integer.class, - p -> null, - (s, p) -> { - return Integer.valueOf(s); - }); - - static String listOfPathToString(List value) { - String result = ""; - - for (Path path : value) { - if (result.length() > 0) { - result += File.pathSeparator; - } - - result += path.toString(); - } - - return result; - } - - static String setOfStringToString(Set value) { - String result = ""; - - for (String element : value) { - if (result.length() > 0) { - result += ","; - } - - result += element; - } - - return result; - } - - static File getMainJar(Map params) { - File result = null; - RelativeFileSet fileset = - StandardBundlerParam.MAIN_JAR.fetchFrom(params); - - if (fileset != null) { - String filename = fileset.getIncludedFiles().iterator().next(); - result = fileset.getBaseDirectory().toPath(). - resolve(filename).toFile(); - - if (result == null || !result.exists()) { - String srcdir = - StandardBundlerParam.SOURCE_DIR.fetchFrom(params); - - if (srcdir != null) { - result = new File(srcdir + File.separator + filename); - } - } - } - - return result; - } - - static String getMainClass(Map params) { - String result = ""; - String mainModule = StandardBundlerParam.MODULE.fetchFrom(params); - if (mainModule != null) { - int index = mainModule.indexOf("/"); - if (index > 0) { - result = mainModule.substring(index + 1); - } - } else { - RelativeFileSet fileset = - StandardBundlerParam.MAIN_JAR.fetchFrom(params); - if (fileset != null) { - result = StandardBundlerParam.MAIN_CLASS.fetchFrom(params); - } else { - // possibly app-image - } - } - - return result; - } - - static String getMainModule(Map params) { - String result = null; - String mainModule = StandardBundlerParam.MODULE.fetchFrom(params); - - if (mainModule != null) { - int index = mainModule.indexOf("/"); - - if (index > 0) { - result = mainModule.substring(0, index); - } else { - result = mainModule; - } - } - - return result; - } - - private static Set getValidModules(List modulePath, - Set addModules, Set limitModules) { - ModuleHelper moduleHelper = new ModuleHelper( - modulePath, addModules, limitModules); - return removeInvalidModules(modulePath, moduleHelper.modules()); - } - - static void execute(Map params, - AbstractAppImageBuilder imageBuilder) - throws IOException, Exception { - List modulePath = - StandardBundlerParam.MODULE_PATH.fetchFrom(params); - Set addModules = - StandardBundlerParam.ADD_MODULES.fetchFrom(params); - Set limitModules = - StandardBundlerParam.LIMIT_MODULES.fetchFrom(params); - Path outputDir = imageBuilder.getRoot(); - String excludeFileList = imageBuilder.getExcludeFileList(); - File mainJar = getMainJar(params); - ModFile.ModType mainJarType = ModFile.ModType.Unknown; - - if (mainJar != null) { - mainJarType = new ModFile(mainJar).getModType(); - } else if (StandardBundlerParam.MODULE.fetchFrom(params) == null) { - // user specified only main class, all jars will be on the classpath - mainJarType = ModFile.ModType.UnnamedJar; - } - - boolean bindServices = addModules.isEmpty(); - - // Modules - String mainModule = getMainModule(params); - if (mainModule == null) { - if (mainJarType == ModFile.ModType.UnnamedJar) { - if (addModules.isEmpty()) { - // The default for an unnamed jar is ALL_DEFAULT - addModules.add(ModuleHelper.ALL_DEFAULT); - } - } else if (mainJarType == ModFile.ModType.Unknown || - mainJarType == ModFile.ModType.ModularJar) { - addModules.add(ModuleHelper.ALL_DEFAULT); - } - } - - Set validModules = - getValidModules(modulePath, addModules, limitModules); - - if (mainModule != null) { - validModules.add(mainModule); - } - - Log.verbose(MessageFormat.format( - I18N.getString("message.modules"), validModules.toString())); - - runJLink(outputDir, modulePath, validModules, limitModules, - excludeFileList, new HashMap(), bindServices); - - imageBuilder.prepareApplicationFiles(); - } - - - // Returns the path to the JDK modules in the user defined module path. - static Path findPathOfModule( List modulePath, String moduleName) { - - for (Path path : modulePath) { - Path moduleNamePath = path.resolve(moduleName); - - if (Files.exists(moduleNamePath)) { - return path; - } - } - - return null; - } - - /* - * Returns the set of modules that would be visible by default for - * a non-modular-aware application consisting of the given elements. - */ - private static Set getDefaultModules( - Path[] paths, String[] addModules) { - - // the modules in the run-time image that export an API - Stream systemRoots = ModuleFinder.ofSystem().findAll().stream() - .map(ModuleReference::descriptor) - .filter(descriptor -> exportsAPI(descriptor)) - .map(ModuleDescriptor::name); - - Set roots; - if (addModules == null || addModules.length == 0) { - roots = systemRoots.collect(Collectors.toSet()); - } else { - var extraRoots = Stream.of(addModules); - roots = Stream.concat(systemRoots, - extraRoots).collect(Collectors.toSet()); - } - - ModuleFinder finder = ModuleFinder.ofSystem(); - if (paths != null && paths.length > 0) { - finder = ModuleFinder.compose(finder, ModuleFinder.of(paths)); - } - return Configuration.empty() - .resolveAndBind(finder, ModuleFinder.of(), roots) - .modules() - .stream() - .map(ResolvedModule::name) - .collect(Collectors.toSet()); - } - - /* - * Returns true if the given module exports an API to all module. - */ - private static boolean exportsAPI(ModuleDescriptor descriptor) { - return descriptor.exports() - .stream() - .filter(e -> !e.isQualified()) - .findAny() - .isPresent(); - } - - private static Set removeInvalidModules( - List modulePath, Set modules) { - Set result = new LinkedHashSet(); - ModuleManager mm = new ModuleManager(modulePath); - List lmodfiles = - mm.getModules(EnumSet.of(ModuleManager.SearchType.ModularJar, - ModuleManager.SearchType.Jmod, - ModuleManager.SearchType.ExplodedModule)); - - HashMap validModules = new HashMap<>(); - - for (ModFile modFile : lmodfiles) { - validModules.put(modFile.getModName(), modFile); - } - - for (String name : modules) { - if (validModules.containsKey(name)) { - result.add(name); - } else { - Log.error(MessageFormat.format( - I18N.getString("warning.module.does.not.exist"), name)); - } - } - - return result; - } - - private static class ModuleHelper { - // The token for "all modules on the module path". - private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; - - // The token for "all valid runtime modules". - static final String ALL_DEFAULT = "ALL-DEFAULT"; - - private final Set modules = new HashSet<>(); - private enum Macros {None, AllModulePath, AllRuntime} - - ModuleHelper(List paths, Set addModules, - Set limitModules) { - boolean addAllModulePath = false; - boolean addDefaultMods = false; - - for (Iterator iterator = addModules.iterator(); - iterator.hasNext();) { - String module = iterator.next(); - - switch (module) { - case ALL_MODULE_PATH: - iterator.remove(); - addAllModulePath = true; - break; - case ALL_DEFAULT: - iterator.remove(); - addDefaultMods = true; - break; - default: - this.modules.add(module); - } - } - - if (addAllModulePath) { - this.modules.addAll(getModuleNamesFromPath(paths)); - } else if (addDefaultMods) { - this.modules.addAll(getDefaultModules( - paths.toArray(new Path[0]), - addModules.toArray(new String[0]))); - } - } - - Set modules() { - return modules; - } - - private static Set getModuleNamesFromPath(List Value) { - Set result = new LinkedHashSet(); - ModuleManager mm = new ModuleManager(Value); - List modFiles = mm.getModules( - EnumSet.of(ModuleManager.SearchType.ModularJar, - ModuleManager.SearchType.Jmod, - ModuleManager.SearchType.ExplodedModule)); - - for (ModFile modFile : modFiles) { - result.add(modFile.getModName()); - } - return result; - } - } - - private static void runJLink(Path output, List modulePath, - Set modules, Set limitModules, String excludes, - HashMap user, boolean bindServices) - throws IOException { - - // This is just to ensure jlink is given a non-existant directory - // The passed in output path should be non-existant or empty directory - IOUtils.deleteRecursive(output.toFile()); - - ArrayList args = new ArrayList(); - args.add("--output"); - args.add(output.toString()); - if (modulePath != null && !modulePath.isEmpty()) { - args.add("--module-path"); - args.add(getPathList(modulePath)); - } - if (modules != null && !modules.isEmpty()) { - args.add("--add-modules"); - args.add(getStringList(modules)); - } - if (limitModules != null && !limitModules.isEmpty()) { - args.add("--limit-modules"); - args.add(getStringList(limitModules)); - } - if (excludes != null) { - args.add("--exclude-files"); - args.add(excludes); - } - if (user != null && !user.isEmpty()) { - for (Map.Entry 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"); - } - } - - StringWriter writer = new StringWriter(); - PrintWriter pw = new PrintWriter(writer); - - Log.verbose("jlink arguments: " + args); - int retVal = JLINK_TOOL.run(pw, pw, args.toArray(new String[0])); - String jlinkOut = writer.toString(); - - if (retVal != 0) { - throw new IOException("jlink failed with: " + jlinkOut); - } else if (jlinkOut.length() > 0) { - Log.verbose("jlink output: " + jlinkOut); - } - } - - private static String getPathList(List pathList) { - String ret = null; - for (Path p : pathList) { - String s = Matcher.quoteReplacement(p.toString()); - if (ret == null) { - ret = s; - } else { - ret += File.pathSeparator + s; - } - } - return ret; - } - - private static String getStringList(Set strings) { - String ret = null; - for (String s : strings) { - if (ret == null) { - ret = s; - } else { - ret += "," + s; - } - } - return (ret == null) ? null : Matcher.quoteReplacement(ret); - } -} --- /dev/null 2019-11-18 20:55:38.000000000 -0500 +++ new/src/jdk.incubator.jpackage/share/classes/jdk/incubator/jpackage/internal/JLinkBundlerHelper.java 2019-11-18 20:55:32.832036900 -0500 @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2015, 2019, 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.incubator.jpackage.internal; + +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.Optional; +import java.util.Arrays; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.regex.Matcher; +import java.util.spi.ToolProvider; +import java.util.jar.JarFile; +import java.lang.module.Configuration; +import java.lang.module.ResolvedModule; +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.lang.module.ModuleReference; +import jdk.internal.module.ModulePath; + + +final class JLinkBundlerHelper { + + private static final ResourceBundle I18N = ResourceBundle.getBundle( + "jdk.incubator.jpackage.internal.resources.MainResources"); + + static final ToolProvider JLINK_TOOL = + ToolProvider.findFirst("jlink").orElseThrow(); + + static File getMainJar(Map params) { + File result = null; + RelativeFileSet fileset = + StandardBundlerParam.MAIN_JAR.fetchFrom(params); + + if (fileset != null) { + String filename = fileset.getIncludedFiles().iterator().next(); + result = fileset.getBaseDirectory().toPath(). + resolve(filename).toFile(); + + if (result == null || !result.exists()) { + String srcdir = + StandardBundlerParam.SOURCE_DIR.fetchFrom(params); + + if (srcdir != null) { + result = new File(srcdir + File.separator + filename); + } + } + } + + return result; + } + + static String getMainClassFromModule(Map params) { + String mainModule = StandardBundlerParam.MODULE.fetchFrom(params); + if (mainModule != null) { + + int index = mainModule.indexOf("/"); + if (index > 0) { + return mainModule.substring(index + 1); + } else { + ModuleDescriptor descriptor = + JLinkBundlerHelper.getMainModuleDescription(params); + if (descriptor != null) { + Optional mainClass = descriptor.mainClass(); + if (mainClass.isPresent()) { + Log.verbose(MessageFormat.format(I18N.getString( + "message.module-class"), + mainClass.get(), + JLinkBundlerHelper.getMainModule(params))); + return mainClass.get(); + } + } + } + } + return null; + } + + static String getMainModule(Map params) { + String result = null; + String mainModule = StandardBundlerParam.MODULE.fetchFrom(params); + + if (mainModule != null) { + int index = mainModule.indexOf("/"); + + if (index > 0) { + result = mainModule.substring(0, index); + } else { + result = mainModule; + } + } + + return result; + } + + static void execute(Map params, + AbstractAppImageBuilder imageBuilder) + throws IOException, Exception { + + List modulePath = + StandardBundlerParam.MODULE_PATH.fetchFrom(params); + Set addModules = + StandardBundlerParam.ADD_MODULES.fetchFrom(params); + Set limitModules = + StandardBundlerParam.LIMIT_MODULES.fetchFrom(params); + Path outputDir = imageBuilder.getRuntimeRoot(); + File mainJar = getMainJar(params); + ModFile.ModType mainJarType = ModFile.ModType.Unknown; + + if (mainJar != null) { + mainJarType = new ModFile(mainJar).getModType(); + } else if (StandardBundlerParam.MODULE.fetchFrom(params) == null) { + // user specified only main class, all jars will be on the classpath + mainJarType = ModFile.ModType.UnnamedJar; + } + + boolean bindServices = + StandardBundlerParam.BIND_SERVICES.fetchFrom(params); + + // Modules + String mainModule = getMainModule(params); + if (mainModule == null) { + if (mainJarType == ModFile.ModType.UnnamedJar) { + if (addModules.isEmpty()) { + // The default for an unnamed jar is ALL_DEFAULT + addModules.add(ModuleHelper.ALL_DEFAULT); + } + } else if (mainJarType == ModFile.ModType.Unknown || + mainJarType == ModFile.ModType.ModularJar) { + addModules.add(ModuleHelper.ALL_DEFAULT); + } + } + + Set modules = new ModuleHelper( + modulePath, addModules, limitModules).modules(); + + if (mainModule != null) { + modules.add(mainModule); + } + + runJLink(outputDir, modulePath, modules, limitModules, + new HashMap(), bindServices); + + imageBuilder.prepareApplicationFiles(params); + } + + + // Returns the path to the JDK modules in the user defined module path. + static Path findPathOfModule( List modulePath, String moduleName) { + + for (Path path : modulePath) { + Path moduleNamePath = path.resolve(moduleName); + + if (Files.exists(moduleNamePath)) { + return path; + } + } + + return null; + } + + static ModuleDescriptor getMainModuleDescription(Map params) { + boolean hasModule = params.containsKey(StandardBundlerParam.MODULE.getID()); + if (hasModule) { + List modulePath = StandardBundlerParam.MODULE_PATH.fetchFrom(params); + if (!modulePath.isEmpty()) { + ModuleFinder finder = ModuleFinder.of(modulePath.toArray(new Path[0])); + String mainModule = JLinkBundlerHelper.getMainModule(params); + Optional omref = finder.find(mainModule); + if (omref.isPresent()) { + return omref.get().descriptor(); + } + } + } + + return null; + } + + /* + * Returns the set of modules that would be visible by default for + * a non-modular-aware application consisting of the given elements. + */ + private static Set getDefaultModules( + Collection paths, Collection addModules) { + + // the modules in the run-time image that export an API + Stream systemRoots = ModuleFinder.ofSystem().findAll().stream() + .map(ModuleReference::descriptor) + .filter(JLinkBundlerHelper::exportsAPI) + .map(ModuleDescriptor::name); + + Set roots = Stream.concat(systemRoots, + addModules.stream()).collect(Collectors.toSet()); + + ModuleFinder finder = createModuleFinder(paths); + + return Configuration.empty() + .resolveAndBind(finder, ModuleFinder.of(), roots) + .modules() + .stream() + .map(ResolvedModule::name) + .collect(Collectors.toSet()); + } + + /* + * Returns true if the given module exports an API to all module. + */ + private static boolean exportsAPI(ModuleDescriptor descriptor) { + return descriptor.exports() + .stream() + .anyMatch(e -> !e.isQualified()); + } + + private static ModuleFinder createModuleFinder(Collection modulePath) { + return ModuleFinder.compose( + ModulePath.of(JarFile.runtimeVersion(), true, + modulePath.toArray(Path[]::new)), + ModuleFinder.ofSystem()); + } + + private static class ModuleHelper { + // The token for "all modules on the module path". + private static final String ALL_MODULE_PATH = "ALL-MODULE-PATH"; + + // The token for "all valid runtime modules". + static final String ALL_DEFAULT = "ALL-DEFAULT"; + + private final Set modules = new HashSet<>(); + ModuleHelper(List paths, Set addModules, + Set limitModules) { + boolean addAllModulePath = false; + boolean addDefaultMods = false; + + for (Iterator iterator = addModules.iterator(); + iterator.hasNext();) { + String module = iterator.next(); + + switch (module) { + case ALL_MODULE_PATH: + iterator.remove(); + addAllModulePath = true; + break; + case ALL_DEFAULT: + iterator.remove(); + addDefaultMods = true; + break; + default: + this.modules.add(module); + } + } + + if (addAllModulePath) { + this.modules.addAll(getModuleNamesFromPath(paths)); + } else if (addDefaultMods) { + this.modules.addAll(getDefaultModules( + paths, addModules)); + } + } + + Set modules() { + return modules; + } + + private static Set getModuleNamesFromPath(List paths) { + + return createModuleFinder(paths) + .findAll() + .stream() + .map(ModuleReference::descriptor) + .map(ModuleDescriptor::name) + .collect(Collectors.toSet()); + } + } + + private static void runJLink(Path output, List modulePath, + Set modules, Set limitModules, + HashMap user, boolean bindServices) + throws PackagerException { + + // This is just to ensure jlink is given a non-existant directory + // The passed in output path should be non-existant or empty directory + try { + IOUtils.deleteRecursive(output.toFile()); + } catch (IOException ioe) { + throw new PackagerException(ioe); + } + + ArrayList args = new ArrayList(); + args.add("--output"); + args.add(output.toString()); + if (modulePath != null && !modulePath.isEmpty()) { + args.add("--module-path"); + args.add(getPathList(modulePath)); + } + if (modules != null && !modules.isEmpty()) { + args.add("--add-modules"); + args.add(getStringList(modules)); + } + if (limitModules != null && !limitModules.isEmpty()) { + args.add("--limit-modules"); + args.add(getStringList(limitModules)); + } + if (user != null && !user.isEmpty()) { + for (Map.Entry 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"); + } + } + + StringWriter writer = new StringWriter(); + PrintWriter pw = new PrintWriter(writer); + + Log.verbose("jlink arguments: " + args); + int retVal = JLINK_TOOL.run(pw, pw, args.toArray(new String[0])); + String jlinkOut = writer.toString(); + + if (retVal != 0) { + throw new PackagerException("error.jlink.failed" , jlinkOut); + } else if (jlinkOut.length() > 0) { + Log.verbose("jlink output: " + jlinkOut); + } + } + + private static String getPathList(List pathList) { + String ret = null; + for (Path p : pathList) { + String s = Matcher.quoteReplacement(p.toString()); + if (ret == null) { + ret = s; + } else { + ret += File.pathSeparator + s; + } + } + return ret; + } + + private static String getStringList(Set strings) { + String ret = null; + for (String s : strings) { + if (ret == null) { + ret = s; + } else { + ret += "," + s; + } + } + return (ret == null) ? null : Matcher.quoteReplacement(ret); + } +}