8167018: Nashorn and jjs should support --module-path and --add-modules options
Reviewed-by: jlaskey, hannesw
This commit is contained in:
parent
e29b338cd7
commit
5cb4f9c787
@ -75,6 +75,7 @@ final class PackagesHelper {
|
||||
}
|
||||
|
||||
private final Context context;
|
||||
private final boolean modulePathSet;
|
||||
private final StandardJavaFileManager fm;
|
||||
private final Set<JavaFileObject.Kind> fileKinds;
|
||||
private final FileSystem jrtfs;
|
||||
@ -86,11 +87,17 @@ final class PackagesHelper {
|
||||
*/
|
||||
PackagesHelper(final Context context) throws IOException {
|
||||
this.context = context;
|
||||
final String classPath = context.getEnv()._classpath;
|
||||
final String modulePath = context.getEnv()._module_path;
|
||||
this.modulePathSet = modulePath != null && !modulePath.isEmpty();
|
||||
if (isJavacAvailable()) {
|
||||
final String classPath = context.getEnv()._classpath;
|
||||
fm = compiler.getStandardFileManager(null, null, null);
|
||||
fileKinds = EnumSet.of(JavaFileObject.Kind.CLASS);
|
||||
|
||||
if (this.modulePathSet) {
|
||||
fm.setLocation(StandardLocation.MODULE_PATH, getFiles(modulePath));
|
||||
}
|
||||
|
||||
if (classPath != null && !classPath.isEmpty()) {
|
||||
fm.setLocation(StandardLocation.CLASS_PATH, getFiles(classPath));
|
||||
} else {
|
||||
@ -155,6 +162,13 @@ final class PackagesHelper {
|
||||
final Set<String> props = new HashSet<>();
|
||||
if (fm != null) {
|
||||
listPackage(StandardLocation.PLATFORM_CLASS_PATH, pkg, props);
|
||||
if (this.modulePathSet) {
|
||||
for (Set<Location> locs : fm.listModuleLocations(StandardLocation.MODULE_PATH)) {
|
||||
for (Location loc : locs) {
|
||||
listPackage(loc, pkg, props);
|
||||
}
|
||||
}
|
||||
}
|
||||
listPackage(StandardLocation.CLASS_PATH, pkg, props);
|
||||
} else if (jrtfs != null) {
|
||||
// look for the /packages/<package_name> directory
|
||||
|
@ -56,6 +56,8 @@ import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Module;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.AccessController;
|
||||
import java.security.CodeSigner;
|
||||
@ -81,6 +83,8 @@ import java.util.concurrent.atomic.LongAdder;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.script.ScriptEngine;
|
||||
import jdk.dynalink.DynamicLinker;
|
||||
import jdk.internal.org.objectweb.asm.ClassReader;
|
||||
@ -614,18 +618,37 @@ public final class Context {
|
||||
}
|
||||
this.errors = errors;
|
||||
|
||||
// if user passed --module-path, we create a module class loader with
|
||||
// passed appLoader as the parent.
|
||||
final String modulePath = env._module_path;
|
||||
ClassLoader appCl = null;
|
||||
if (!env._compile_only && modulePath != null && !modulePath.isEmpty()) {
|
||||
// make sure that caller can create a class loader.
|
||||
if (sm != null) {
|
||||
sm.checkCreateClassLoader();
|
||||
}
|
||||
appCl = AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
|
||||
@Override
|
||||
public ClassLoader run() {
|
||||
return createModuleLoader(appLoader, modulePath, env._add_modules);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
appCl = appLoader;
|
||||
}
|
||||
|
||||
// if user passed -classpath option, make a URLClassLoader with that and
|
||||
// the app loader as the parent.
|
||||
final String classPath = options.getString("classpath");
|
||||
// the app loader or module app loader as the parent.
|
||||
final String classPath = env._classpath;
|
||||
if (!env._compile_only && classPath != null && !classPath.isEmpty()) {
|
||||
// make sure that caller can create a class loader.
|
||||
if (sm != null) {
|
||||
sm.checkCreateClassLoader();
|
||||
}
|
||||
this.appLoader = NashornLoader.createClassLoader(classPath, appLoader);
|
||||
} else {
|
||||
this.appLoader = appLoader;
|
||||
appCl = NashornLoader.createClassLoader(classPath, appCl);
|
||||
}
|
||||
|
||||
this.appLoader = appCl;
|
||||
this.dynamicLinker = Bootstrap.createDynamicLinker(this.appLoader, env._unstable_relink_threshold);
|
||||
|
||||
final int cacheSize = env._class_cache_size;
|
||||
@ -1750,4 +1773,37 @@ public final class Context {
|
||||
public SwitchPoint getBuiltinSwitchPoint(final String name) {
|
||||
return builtinSwitchPoints.get(name);
|
||||
}
|
||||
|
||||
private static ClassLoader createModuleLoader(final ClassLoader cl,
|
||||
final String modulePath, final String addModules) {
|
||||
if (addModules == null) {
|
||||
throw new IllegalArgumentException("--module-path specified with no --add-modules");
|
||||
}
|
||||
|
||||
final Path[] paths = Stream.of(modulePath.split(File.pathSeparator)).
|
||||
map(s -> Paths.get(s)).
|
||||
toArray(sz -> new Path[sz]);
|
||||
final ModuleFinder mf = ModuleFinder.of(paths);
|
||||
final Set<ModuleReference> mrefs = mf.findAll();
|
||||
if (mrefs.isEmpty()) {
|
||||
throw new RuntimeException("No modules in script --module-path: " + modulePath);
|
||||
}
|
||||
|
||||
final Set<String> rootMods;
|
||||
if (addModules.equals("ALL-MODULE-PATH")) {
|
||||
rootMods = mrefs.stream().
|
||||
map(mr->mr.descriptor().name()).
|
||||
collect(Collectors.toSet());
|
||||
} else {
|
||||
rootMods = Stream.of(addModules.split(",")).
|
||||
map(String::trim).
|
||||
collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
final Layer boot = Layer.boot();
|
||||
final Configuration conf = boot.configuration().
|
||||
resolveRequires(mf, ModuleFinder.of(), rootMods);
|
||||
final String firstMod = rootMods.iterator().next();
|
||||
return boot.defineModulesWithOneLoader(conf, cl).findLoader(firstMod);
|
||||
}
|
||||
}
|
||||
|
@ -153,6 +153,12 @@ public final class ScriptEnvironment {
|
||||
/** Create a new class loaded for each compilation */
|
||||
public final boolean _loader_per_compile;
|
||||
|
||||
/** --module-path, if any */
|
||||
public final String _module_path;
|
||||
|
||||
/** --add-modules, if any */
|
||||
public final String _add_modules;
|
||||
|
||||
/** Do not support Java support extensions. */
|
||||
public final boolean _no_java;
|
||||
|
||||
@ -285,6 +291,8 @@ public final class ScriptEnvironment {
|
||||
_lazy_compilation = lazy_compilation;
|
||||
}
|
||||
_loader_per_compile = options.getBoolean("loader.per.compile");
|
||||
_module_path = options.getString("module.path");
|
||||
_add_modules = options.getString("add.modules");
|
||||
_no_java = options.getBoolean("no.java");
|
||||
_no_syntax_extensions = options.getBoolean("no.syntax.extensions");
|
||||
_no_typed_arrays = options.getBoolean("no.typed.arrays");
|
||||
|
@ -77,6 +77,14 @@ public final class OptionTemplate implements Comparable<OptionTemplate> {
|
||||
/** is the option value specified as next argument? */
|
||||
private boolean valueNextArg;
|
||||
|
||||
/**
|
||||
* Can this option be repeated in command line?
|
||||
*
|
||||
* For a repeatable option, multiple values will be merged as comma
|
||||
* separated values rather than the last value overriding previous ones.
|
||||
*/
|
||||
private boolean repeated;
|
||||
|
||||
OptionTemplate(final String resource, final String key, final String value, final boolean isHelp, final boolean isXHelp) {
|
||||
this.resource = resource;
|
||||
this.key = key;
|
||||
@ -223,6 +231,14 @@ public final class OptionTemplate implements Comparable<OptionTemplate> {
|
||||
return valueNextArg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can this option be repeated?
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean isRepeated() {
|
||||
return repeated;
|
||||
}
|
||||
|
||||
private static String strip(final String value, final char start, final char end) {
|
||||
final int len = value.length();
|
||||
if (len > 1 && value.charAt(0) == start && value.charAt(len - 1) == end) {
|
||||
@ -281,6 +297,9 @@ public final class OptionTemplate implements Comparable<OptionTemplate> {
|
||||
case "value_next_arg":
|
||||
this.valueNextArg = Boolean.parseBoolean(arg);
|
||||
break;
|
||||
case "repeated":
|
||||
this.repeated = true;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(keyToken);
|
||||
}
|
||||
@ -302,6 +321,10 @@ public final class OptionTemplate implements Comparable<OptionTemplate> {
|
||||
if (name == null && shortName == null) {
|
||||
throw new IllegalArgumentException(origValue);
|
||||
}
|
||||
|
||||
if (this.repeated && !"string".equals(this.type)) {
|
||||
throw new IllegalArgumentException("repeated option should be of type string: " + this.name);
|
||||
}
|
||||
}
|
||||
|
||||
boolean nameMatches(final String aName) {
|
||||
|
@ -500,7 +500,16 @@ public final class Options {
|
||||
throw new IllegalOptionException(parg.template);
|
||||
}
|
||||
|
||||
set(parg.template.getKey(), createOption(parg.template, parg.value));
|
||||
if (parg.template.isRepeated()) {
|
||||
assert parg.template.getType().equals("string");
|
||||
|
||||
final String key = key(parg.template.getKey());
|
||||
final String value = options.containsKey(key)?
|
||||
(options.get(key).getValue() + "," + parg.value) : Objects.toString(parg.value);
|
||||
options.put(key, new Option<>(value));
|
||||
} else {
|
||||
set(parg.template.getKey(), createOption(parg.template, parg.value));
|
||||
}
|
||||
|
||||
// Arg may have a dependency to set other args, e.g.
|
||||
// scripting->anon.functions
|
||||
|
@ -237,6 +237,21 @@ nashorn.option.loader.per.compile = { \
|
||||
default=true \
|
||||
}
|
||||
|
||||
nashorn.option.module.path ={ \
|
||||
name="--module-path", \
|
||||
desc="--module-path path. Specify where to find user java modules.", \
|
||||
value_next_arg=true, \
|
||||
type=String \
|
||||
}
|
||||
|
||||
nashorn.option.add.modules ={ \
|
||||
name="--add-modules", \
|
||||
desc="--add-modules modules. Specify the root user java modules.", \
|
||||
repeated=true, \
|
||||
value_next_arg=true, \
|
||||
type=String \
|
||||
}
|
||||
|
||||
nashorn.option.no.java = { \
|
||||
name="--no-java", \
|
||||
short_name="-nj", \
|
||||
|
Loading…
Reference in New Issue
Block a user