Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.oracle.svm.driver.MacroOption Maven / Gradle / Ivy
/*
* Copyright (c) 2016, 2017, 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 com.oracle.svm.driver;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
final class MacroOption {
enum MacroOptionKind {
Language("languages", true),
Tool("tools", true),
Macro("macros", false);
final String subdir;
final boolean allowAll;
MacroOptionKind(String subdir, boolean allowAll) {
this.subdir = subdir;
this.allowAll = allowAll;
}
static MacroOptionKind fromSubdir(String subdir) {
for (MacroOptionKind kind : MacroOptionKind.values()) {
if (kind.subdir.equals(subdir)) {
return kind;
}
}
throw new InvalidMacroException("No MacroOptionKind for subDir: " + subdir);
}
static MacroOptionKind fromString(String kindName) {
for (MacroOptionKind kind : MacroOptionKind.values()) {
if (kind.toString().equals(kindName)) {
return kind;
}
}
throw new InvalidMacroException("No MacroOptionKind for kindName: " + kindName);
}
@Override
public String toString() {
return name().toLowerCase();
}
}
Path getOptionDirectory() {
return optionDirectory;
}
String getOptionName() {
return optionName;
}
private static final String macroOptionPrefix = "--";
String getDescription(boolean commandLineStyle) {
StringBuilder sb = new StringBuilder();
if (commandLineStyle) {
sb.append(macroOptionPrefix);
}
sb.append(kind.toString()).append(":").append(getOptionName());
return sb.toString();
}
@SuppressWarnings("serial")
static final class InvalidMacroException extends RuntimeException {
InvalidMacroException(String arg0) {
super(arg0);
}
}
@SuppressWarnings("serial")
static final class VerboseInvalidMacroException extends RuntimeException {
private final MacroOptionKind forKind;
private final MacroOption context;
VerboseInvalidMacroException(String arg0, MacroOption context) {
this(arg0, null, context);
}
VerboseInvalidMacroException(String arg0, MacroOptionKind forKind, MacroOption context) {
super(arg0);
this.forKind = forKind;
this.context = context;
}
public String getMessage(Registry registry) {
StringBuilder sb = new StringBuilder();
String message = super.getMessage();
if (context != null) {
sb.append(context.getDescription(false) + " contains ");
if (!message.isEmpty()) {
sb.append(Character.toLowerCase(message.charAt(0)));
sb.append(message.substring(1));
}
} else {
sb.append(message);
}
Consumer lineOut = s -> sb.append("\n" + s);
registry.showOptions(forKind, context == null, lineOut);
return sb.toString();
}
}
@SuppressWarnings("serial")
static final class AddedTwiceException extends RuntimeException {
private final MacroOption option;
private final MacroOption context;
AddedTwiceException(MacroOption option, MacroOption context) {
this.option = option;
this.context = context;
}
@Override
public String getMessage() {
StringBuilder sb = new StringBuilder();
if (context != null) {
sb.append("MacroOption ").append(context.getDescription(false));
if (option.equals(context)) {
sb.append(" cannot require itself");
} else {
sb.append(" requires ").append(option.getDescription(false)).append(" more than once");
}
} else {
sb.append("Command line option ").append(option.getDescription(true));
sb.append(" used more than once");
}
return sb.toString();
}
}
static final class EnabledOption {
private final MacroOption option;
private final String optionArg;
private EnabledOption(MacroOption option, String optionArg) {
this.option = Objects.requireNonNull(option);
this.optionArg = optionArg;
}
private String resolvePropertyValue(String val) {
return NativeImage.resolvePropertyValue(val, optionArg, getOption().optionDirectory.toString());
}
String getProperty(String key, String defaultVal) {
String val = option.properties.get(key);
if (val == null) {
return defaultVal;
}
return resolvePropertyValue(val);
}
String getProperty(String key) {
return getProperty(key, null);
}
boolean forEachPropertyValue(String propertyKey, Consumer target) {
return forEachPropertyValue(propertyKey, target, " ");
}
boolean forEachPropertyValue(String propertyKey, Consumer target, String separatorRegex) {
return NativeImage.forEachPropertyValue(option.properties.get(propertyKey), target, this::resolvePropertyValue, separatorRegex);
}
MacroOption getOption() {
return option;
}
}
static final class Registry {
private final Map> supported = new HashMap<>();
private final LinkedHashSet enabled = new LinkedHashSet<>();
private static Map> collectMacroOptions(Path rootDir) throws IOException {
Map> result = new HashMap<>();
for (MacroOptionKind kind : MacroOptionKind.values()) {
Path optionsDir = rootDir.resolve(kind.subdir);
Map collectedOptions = Collections.emptyMap();
if (Files.isDirectory(optionsDir)) {
collectedOptions = Files.list(optionsDir).filter(Files::isDirectory)
.filter(optionDir -> Files.isReadable(optionDir.resolve(NativeImage.nativeImagePropertiesFilename)))
.map(MacroOption::create).filter(Objects::nonNull)
.collect(Collectors.toMap(MacroOption::getOptionName, Function.identity()));
}
result.put(kind, collectedOptions);
}
return result;
}
Registry() {
for (MacroOptionKind kind : MacroOptionKind.values()) {
supported.put(kind, new HashMap<>());
}
}
void addMacroOptionRoot(Path rootDir) {
/* Discover MacroOptions and add to supported */
try {
collectMacroOptions(rootDir).forEach((optionKind, optionMap) -> {
supported.get(optionKind).putAll(optionMap);
});
} catch (IOException e) {
throw new InvalidMacroException("Error while discovering supported MacroOptions in " + rootDir + ": " + e.getMessage());
}
}
Set getAvailableOptions(MacroOptionKind forKind) {
return supported.get(forKind).keySet();
}
void showOptions(MacroOptionKind forKind, boolean commandLineStyle, Consumer lineOut) {
List optionsToShow = new ArrayList<>();
for (MacroOptionKind kind : MacroOptionKind.values()) {
if (forKind != null && !kind.equals(forKind)) {
continue;
}
if (forKind == null && kind == MacroOptionKind.Macro) {
// skip non-API macro options by default
continue;
}
for (MacroOption option : supported.get(kind).values()) {
if (!option.kind.subdir.isEmpty()) {
String linePrefix = " ";
if (commandLineStyle) {
linePrefix += macroOptionPrefix;
}
optionsToShow.add(linePrefix + option);
}
}
}
if (!optionsToShow.isEmpty()) {
StringBuilder sb = new StringBuilder().append("Available ");
if (forKind != null) {
sb.append(forKind.toString()).append(' ');
} else {
sb.append("macro-");
}
lineOut.accept(sb.append("options are:").toString());
optionsToShow.forEach(lineOut);
}
}
MacroOption getMacroOption(MacroOptionKind kindPart, String optionName) {
return supported.get(kindPart).get(optionName);
}
boolean enableOption(String optionString, HashSet addedCheck, MacroOption context, Consumer enabler) {
String specString;
if (context == null) {
if (optionString.startsWith(macroOptionPrefix)) {
specString = optionString.substring(macroOptionPrefix.length());
} else {
return false;
}
} else {
specString = optionString;
}
String[] specParts = specString.split(":", 2);
if (specParts.length != 2) {
if (context == null) {
return false;
} else {
throw new VerboseInvalidMacroException("Invalid option specification: " + optionString, context);
}
}
MacroOptionKind kindPart;
try {
kindPart = MacroOptionKind.fromString(specParts[0]);
} catch (Exception e) {
if (context == null) {
return false;
} else {
throw new VerboseInvalidMacroException("Unknown kind in option specification: " + optionString, context);
}
}
String specNameParts = specParts[1];
if (specNameParts.isEmpty()) {
throw new VerboseInvalidMacroException("Empty option specification: " + optionString, kindPart, context);
}
if (specNameParts.equals("all")) {
if (!kindPart.allowAll) {
throw new VerboseInvalidMacroException("Empty option specification: " + kindPart + " does no support 'all'", kindPart, context);
}
for (String optionName : getAvailableOptions(kindPart)) {
MacroOption option = getMacroOption(kindPart, optionName);
if (Boolean.parseBoolean(option.properties.getOrDefault("ExcludeFromAll", "false"))) {
continue;
}
enableResolved(option, null, addedCheck, context, enabler);
}
return true;
}
String[] parts = specNameParts.split("=", 2);
String optionName = parts[0];
MacroOption option = getMacroOption(kindPart, optionName);
if (option != null) {
String optionArg = parts.length == 2 ? parts[1] : null;
enableResolved(option, optionArg, addedCheck, context, enabler);
} else {
throw new VerboseInvalidMacroException("Unknown name in option specification: " + kindPart + ":" + optionName, kindPart, context);
}
return true;
}
private void enableResolved(MacroOption option, String optionArg, HashSet addedCheck, MacroOption context, Consumer enabler) {
if (addedCheck.contains(option)) {
return;
}
addedCheck.add(option);
EnabledOption enabledOption = new EnabledOption(option, optionArg);
String requires = enabledOption.getProperty("Requires", "");
if (!requires.isEmpty()) {
for (String specString : requires.split(" ")) {
enableOption(specString, addedCheck, option, enabler);
}
}
MacroOption truffleOption = getMacroOption(MacroOptionKind.Macro, "truffle");
if (option.kind.equals(MacroOptionKind.Language) && !addedCheck.contains(truffleOption)) {
/*
* Every language requires Truffle. If it is not specified explicitly as a
* requirement, add it automatically.
*/
enableResolved(truffleOption, null, addedCheck, context, enabler);
}
enabler.accept(enabledOption);
enabled.add(enabledOption);
}
LinkedHashSet getEnabledOptions(MacroOptionKind kind) {
return enabled.stream().filter(eo -> kind.equals(eo.option.kind)).collect(Collectors.toCollection(LinkedHashSet::new));
}
Stream getEnabledOptionsStream(MacroOptionKind kind, MacroOptionKind... otherKinds) {
EnumSet kindSet = EnumSet.of(kind, otherKinds);
return enabled.stream().filter(eo -> kindSet.contains(eo.option.kind));
}
LinkedHashSet getEnabledOptions() {
return enabled;
}
EnabledOption getEnabledOption(MacroOption option) {
return enabled.stream().filter(eo -> eo.getOption().equals(option)).findFirst().orElse(null);
}
}
private final String optionName;
private final Path optionDirectory;
final MacroOptionKind kind;
private final Map properties;
private static MacroOption create(Path macroOptionDirectory) {
try {
return new MacroOption(macroOptionDirectory);
} catch (Exception e) {
return null;
}
}
private MacroOption(Path optionDirectory) {
this.kind = MacroOptionKind.fromSubdir(optionDirectory.getParent().getFileName().toString());
this.optionName = optionDirectory.getFileName().toString();
this.optionDirectory = optionDirectory;
this.properties = NativeImage.loadProperties(optionDirectory.resolve(NativeImage.nativeImagePropertiesFilename));
}
@Override
public String toString() {
return getDescription(false);
}
}