Skip to content
Snippets Groups Projects
Commit baa83021 authored by Zbynek Slajchrt's avatar Zbynek Slajchrt
Browse files

R launchers adapted to GraalVM SDK

parent f4bafa82
No related branches found
No related tags found
No related merge requests found
/*
* Copyright (c) 2017, 2018, 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 com.oracle.truffle.r.launcher;
import static java.lang.Integer.max;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.graalvm.options.OptionCategory;
import org.graalvm.options.OptionDescriptor;
import org.graalvm.options.OptionDescriptors;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Instrument;
import org.graalvm.polyglot.Language;
public abstract class Launcher {
private static final boolean STATIC_VERBOSE = Boolean.getBoolean("org.graalvm.launcher.verbose");
private Engine tempEngine;
private final boolean verbose;
private boolean help;
private boolean helpDebug;
private boolean helpExpert;
private boolean helpTools;
private boolean helpLanguages;
private OptionCategory helpCategory;
private VersionAction versionAction = VersionAction.None;
protected enum VersionAction {
None,
PrintAndExit,
PrintAndContinue
}
public Launcher() {
verbose = STATIC_VERBOSE || Boolean.valueOf(System.getenv("VERBOSE_GRAALVM_LAUNCHERS"));
}
private Engine getTempEngine() {
if (tempEngine == null) {
tempEngine = Engine.create();
}
return tempEngine;
}
void setHelpCategory(OptionCategory helpCategory) {
this.helpCategory = helpCategory;
}
protected void setVersionAction(VersionAction versionAction) {
this.versionAction = versionAction;
}
private static class AbortException extends RuntimeException {
static final long serialVersionUID = 4681646279864737876L;
AbortException(String message) {
super(message, null);
}
@SuppressWarnings("sync-override")
@Override
public final Throwable fillInStackTrace() {
return null;
}
}
protected AbortException exit() {
return abort(null, 0);
}
protected AbortException abort(String message) {
return abort(message, 1);
}
protected AbortException abort(String message, int exitCode) {
if (message != null) {
System.err.println("ERROR: " + message);
}
System.exit(exitCode);
throw new AbortException(message);
}
protected abstract void printHelp(OptionCategory maxCategory);
protected abstract void printVersion();
protected abstract void collectArguments(Set<String> options);
protected static void printPolyglotVersions() {
Engine engine = Engine.create();
System.out.println("GraalVM Polyglot Engine Version " + engine.getVersion());
printLanguages(engine, true);
printInstruments(engine, true);
}
protected boolean isVerbose() {
return verbose;
}
final boolean runPolyglotAction() {
OptionCategory maxCategory = helpDebug ? OptionCategory.DEBUG : (helpExpert ? OptionCategory.EXPERT : (helpCategory != null ? helpCategory : OptionCategory.USER));
switch (versionAction) {
case PrintAndContinue:
printVersion();
return false;
case PrintAndExit:
printVersion();
return true;
case None:
break;
}
boolean printDefaultHelp = helpCategory != null || help || ((helpExpert || helpDebug) && !helpTools && !helpLanguages);
Engine tmpEngine = null;
if (printDefaultHelp) {
printHelp(maxCategory);
// @formatter:off
System.out.println();
System.out.println("Runtime Options:");
printOption("--polyglot", "Run with all other guest languages accessible.");
// not applicable at the moment
// printOption("--native", "Run using the native launcher with limited Java access (default).");
// printOption("--native.[option]", "Pass options to the native image; for example, '--native.Xmx1G'. To see available options, use '--native.help'.");
printOption("--jvm", "Run on the Java Virtual Machine with Java access.");
// not applicable at the moment
// printOption("--jvm.[option]", "Pass options to the JVM; for example, '--jvm.classpath=myapp.jar'. To see available options. use '--jvm.help'.");
printOption("--help", "Print this help message.");
printOption("--help:languages", "Print options for all installed languages.");
printOption("--help:tools", "Print options for all installed tools.");
printOption("--help:expert", "Print additional engine options for experts.");
if (helpExpert || helpDebug) {
printOption("--help:debug", "Print additional engine options for debugging.");
}
printOption("--version", "Print version information and exit.");
printOption("--show-version", "Print version information and continue execution.");
// @formatter:on
if (tmpEngine == null) {
tmpEngine = Engine.create();
}
List<PrintableOption> engineOptions = new ArrayList<>();
for (OptionDescriptor descriptor : tmpEngine.getOptions()) {
if (!descriptor.getName().startsWith("engine.") && !descriptor.getName().startsWith("compiler.")) {
continue;
}
if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) {
engineOptions.add(asPrintableOption(descriptor));
}
}
if (!engineOptions.isEmpty()) {
printOptions(engineOptions, "Engine options:", 2);
}
}
if (helpLanguages) {
if (tmpEngine == null) {
tmpEngine = Engine.create();
}
printLanguageOptions(tmpEngine, maxCategory);
}
if (helpTools) {
if (tmpEngine == null) {
tmpEngine = Engine.create();
}
printInstrumentOptions(tmpEngine, maxCategory);
}
if (printDefaultHelp || helpLanguages || helpTools) {
System.out.println("\nSee http://www.oracle.com/technetwork/oracle-labs/program-languages/overview/index.html for more information.");
return true;
}
return false;
}
private static void printInstrumentOptions(Engine engine, OptionCategory maxCategory) {
Map<Instrument, List<PrintableOption>> instrumentsOptions = new HashMap<>();
List<Instrument> instruments = sortedInstruments(engine);
for (Instrument instrument : instruments) {
List<PrintableOption> options = new ArrayList<>();
for (OptionDescriptor descriptor : instrument.getOptions()) {
if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) {
options.add(asPrintableOption(descriptor));
}
}
if (!options.isEmpty()) {
instrumentsOptions.put(instrument, options);
}
}
if (!instrumentsOptions.isEmpty()) {
System.out.println();
System.out.println("Tool options:");
for (Instrument instrument : instruments) {
List<PrintableOption> options = instrumentsOptions.get(instrument);
if (options != null) {
printOptions(options, " " + instrument.getName() + ":", 4);
}
}
}
}
private static void printLanguageOptions(Engine engine, OptionCategory maxCategory) {
Map<Language, List<PrintableOption>> languagesOptions = new HashMap<>();
List<Language> languages = sortedLanguages(engine);
for (Language language : languages) {
List<PrintableOption> options = new ArrayList<>();
for (OptionDescriptor descriptor : language.getOptions()) {
if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) {
options.add(asPrintableOption(descriptor));
}
}
if (!options.isEmpty()) {
languagesOptions.put(language, options);
}
}
if (!languagesOptions.isEmpty()) {
System.out.println();
System.out.println("Language Options:");
for (Language language : languages) {
List<PrintableOption> options = languagesOptions.get(language);
if (options != null) {
printOptions(options, " " + language.getName() + ":", 4);
}
}
}
}
protected boolean parsePolyglotOption(String defaultOptionPrefix, Map<String, String> options, String arg) {
switch (arg) {
case "--help":
help = true;
return true;
case "--help:debug":
helpDebug = true;
return true;
case "--help:expert":
helpExpert = true;
return true;
case "--help:tools":
helpTools = true;
return true;
case "--help:languages":
helpLanguages = true;
return true;
case "--version":
versionAction = VersionAction.PrintAndExit;
return true;
case "--show-version":
versionAction = VersionAction.PrintAndContinue;
return true;
// case "--polyglot":
// case "--jvm":
// case "--native":
// return false;
default:
// getLanguageId() or null?
if (arg.length() <= 2 || !arg.startsWith("--")) {
return false;
}
int eqIdx = arg.indexOf('=');
String key;
String value;
if (eqIdx < 0) {
key = arg.substring(2);
value = null;
} else {
key = arg.substring(2, eqIdx);
value = arg.substring(eqIdx + 1);
}
if (value == null) {
value = "true";
}
int index = key.indexOf('.');
String group = key;
if (index >= 0) {
group = group.substring(0, index);
}
OptionDescriptor descriptor = findPolyglotOptionDescriptor(group, key);
if (descriptor == null) {
if (defaultOptionPrefix != null) {
descriptor = findPolyglotOptionDescriptor(defaultOptionPrefix, defaultOptionPrefix + "." + key);
}
if (descriptor == null) {
return false;
}
}
try {
descriptor.getKey().getType().convert(value);
} catch (IllegalArgumentException e) {
throw abort(String.format("Invalid argument %s specified. %s'", arg, e.getMessage()));
}
options.put(key, value);
return true;
}
}
private OptionDescriptor findPolyglotOptionDescriptor(String group, String key) {
OptionDescriptors descriptors = null;
switch (group) {
case "compiler":
case "engine":
descriptors = getTempEngine().getOptions();
break;
default:
Engine engine = getTempEngine();
if (engine.getLanguages().containsKey(group)) {
descriptors = engine.getLanguages().get(group).getOptions();
} else if (engine.getInstruments().containsKey(group)) {
descriptors = engine.getInstruments().get(group).getOptions();
}
break;
}
if (descriptors == null) {
return null;
}
return descriptors.get(key);
}
protected static List<Language> sortedLanguages(Engine engine) {
List<Language> languages = new ArrayList<>(engine.getLanguages().values());
languages.sort(Comparator.comparing(Language::getId));
return languages;
}
protected static List<Instrument> sortedInstruments(Engine engine) {
List<Instrument> instruments = new ArrayList<>(engine.getInstruments().values());
instruments.sort(Comparator.comparing(Instrument::getId));
return instruments;
}
protected static void printOption(OptionCategory maxCategory, OptionDescriptor descriptor) {
if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) {
printOption(asPrintableOption(descriptor));
}
}
protected static PrintableOption asPrintableOption(OptionDescriptor descriptor) {
StringBuilder key = new StringBuilder("--");
key.append(descriptor.getName());
Object defaultValue = descriptor.getKey().getDefaultValue();
if (defaultValue instanceof Boolean && defaultValue == Boolean.FALSE) {
// nothing to print
} else {
key.append("=<");
key.append(descriptor.getKey().getType().getName());
key.append(">");
}
return new PrintableOption(key.toString(), descriptor.getHelp());
}
protected static void printOption(String option, String description) {
printOption(option, description, 2);
}
protected static void printOption(String option, String description, int indentation) {
StringBuilder indent = new StringBuilder(indentation);
for (int i = 0; i < indentation; i++) {
indent.append(' ');
}
String desc = description != null ? description : "";
if (option.length() >= 45 && description != null) {
System.out.println(String.format("%s%s%n%s%-45s%s", indent, option, indent, "", desc));
} else {
System.out.println(String.format("%s%-45s%s", indent, option, desc));
}
}
protected static void printOption(PrintableOption option) {
printOption(option, 2);
}
protected static void printOption(PrintableOption option, int indentation) {
printOption(option.option, option.description, indentation);
}
private static final class PrintableOption implements Comparable<PrintableOption> {
final String option;
final String description;
private PrintableOption(String option, String description) {
this.option = option;
this.description = description;
}
@Override
public int compareTo(PrintableOption o) {
return this.option.compareTo(o.option);
}
}
private static void printOptions(List<PrintableOption> options, String title, int indentation) {
Collections.sort(options);
System.out.println(title);
for (PrintableOption option : options) {
printOption(option, indentation);
}
}
protected enum OS {
Darwin,
Linux,
Solaris;
private static OS findCurrent() {
final String name = System.getProperty("os.name");
if (name.equals("Linux")) {
return Linux;
}
if (name.equals("SunOS")) {
return Solaris;
}
if (name.equals("Mac OS X") || name.equals("Darwin")) {
return Darwin;
}
throw new IllegalArgumentException("unknown OS: " + name);
}
private static final OS current = findCurrent();
public static OS getCurrent() {
return current;
}
}
protected static void printLanguages(Engine engine, boolean printWhenEmpty) {
if (engine.getLanguages().isEmpty()) {
if (printWhenEmpty) {
System.out.println(" Installed Languages: none");
}
} else {
System.out.println(" Installed Languages:");
List<Language> languages = new ArrayList<>(engine.getLanguages().size());
int nameLength = 0;
for (Language language : engine.getLanguages().values()) {
languages.add(language);
nameLength = max(nameLength, language.getName().length());
}
languages.sort(Comparator.comparing(Language::getId));
String langFormat = " %-" + nameLength + "s%s version %s%n";
for (Language language : languages) {
String version = language.getVersion();
if (version == null || version.length() == 0) {
version = "";
}
System.out.printf(langFormat, language.getName().isEmpty() ? "Unnamed" : language.getName(), version);
}
}
}
protected static void printInstruments(Engine engine, boolean printWhenEmpty) {
if (engine.getInstruments().isEmpty()) {
if (printWhenEmpty) {
System.out.println(" Installed Tools: none");
}
} else {
System.out.println(" Installed Tools:");
List<Instrument> instruments = sortedInstruments(engine);
int nameLength = 0;
for (Instrument instrument : instruments) {
nameLength = max(nameLength, instrument.getName().length());
}
String instrumentFormat = " %-" + nameLength + "s version %s%n";
for (Instrument instrument : instruments) {
String version = instrument.getVersion();
if (version == null || version.length() == 0) {
version = "";
}
System.out.printf(instrumentFormat, instrument.getName().isEmpty() ? "Unnamed" : instrument.getName(), version);
}
}
}
}
/*
* Copyright (c) 2018, 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 com.oracle.truffle.r.launcher;
import java.io.Closeable;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.graalvm.launcher.AbstractLanguageLauncher;
import org.graalvm.options.OptionCategory;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Context.Builder;
import com.oracle.truffle.r.launcher.RCmdOptions.Client;
import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption;
public abstract class RAbstractLauncher extends AbstractLanguageLauncher implements Closeable {
private final Client client;
protected final InputStream inStream;
protected final OutputStream outStream;
protected final OutputStream errStream;
protected RCmdOptions options;
private boolean useJVM;
protected ConsoleHandler consoleHandler;
protected Context context;
RAbstractLauncher(Client client, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
this.client = client;
assert env == null : "re-enble environment variables";
this.inStream = inStream;
this.outStream = outStream;
this.errStream = errStream;
}
@Override
protected List<String> preprocessArguments(List<String> arguments, Map<String, String> polyglotOptions) {
boolean[] recognizedArgsIndices = new boolean[arguments.size()];
this.options = RCmdOptions.parseArguments(client, arguments.toArray(new String[arguments.size()]), true, recognizedArgsIndices);
List<String> unrecognizedArgs = new ArrayList<>();
for (int i = 0; i < arguments.size(); i++) {
if ("--jvm".equals(arguments.get(i))) {
useJVM = true;
} else if (!recognizedArgsIndices[i]) {
unrecognizedArgs.add(arguments.get(i));
}
}
return unrecognizedArgs;
}
protected abstract String[] getArguments();
@Override
protected void launch(Builder contextBuilder) {
this.consoleHandler = RCommand.createConsoleHandler(options, null, inStream, outStream);
this.context = contextBuilder.allowAllAccess(true).allowHostAccess(useJVM).arguments("R", getArguments()).in(consoleHandler.createInputStream()).out(
outStream).err(errStream).build();
this.consoleHandler.setContext(context);
}
@Override
protected String getLanguageId() {
return "R";
}
@Override
protected void printHelp(OptionCategory maxCategory) {
RCmdOptions.printHelp(client);
}
@Override
protected void collectArguments(Set<String> opts) {
for (RCmdOption option : RCmdOption.values()) {
if (option.shortName != null) {
opts.add(option.shortName);
}
if (option.plainName != null) {
opts.add(option.plainName);
}
}
}
@Override
public void close() {
if (context != null) {
context.close();
}
}
}
......@@ -268,25 +268,44 @@ public final class RCmdOptions {
* {@code args[0]} and we do not want to parse that!
*/
public static RCmdOptions parseArguments(Client client, String[] args, boolean reparse) {
return parseArguments(client, args, reparse, null);
}
public static RCmdOptions parseArguments(Client client, String[] args, boolean reparse, boolean[] recognizedArgsIndices) {
assert recognizedArgsIndices == null || recognizedArgsIndices.length == args.length;
EnumMap<RCmdOption, Object> options = new EnumMap<>(RCmdOption.class);
if (recognizedArgsIndices != null) {
recognizedArgsIndices[0] = true;
}
int i = 1; // skip the first argument (the command)
int firstNonOptionArgIndex = args.length;
while (i < args.length) {
final String arg = args[i];
MatchResult result = matchOption(arg);
if (result == null) {
// for Rscript, this means we are done
if (client == Client.RSCRIPT) {
boolean isOption = arg.startsWith("--") || arg.startsWith("-");
if (!isOption && client == Client.RSCRIPT) {
// for Rscript, this means we are done
if (recognizedArgsIndices != null) {
recognizedArgsIndices[i] = true;
}
firstNonOptionArgIndex = i;
break;
}
if (!reparse) {
// GnuR does not abort, simply issues a warning
System.out.printf("WARNING: unknown option '%s'%n", arg);
if (recognizedArgsIndices != null) {
recognizedArgsIndices[i] = true;
}
}
i++;
continue;
} else {
if (recognizedArgsIndices != null) {
recognizedArgsIndices[i] = true;
}
RCmdOption option = result.option;
if (result.matchedShort && i == args.length - 1) {
System.out.println("usage:");
......@@ -302,6 +321,9 @@ public final class RCmdOptions {
if (result.matchedShort) {
i++;
setValue(options, option, args[i]);
if (recognizedArgsIndices != null) {
recognizedArgsIndices[i] = true;
}
} else {
if (option.type == RCmdOptionType.BOOLEAN) {
setValue(options, option, true);
......@@ -318,6 +340,14 @@ public final class RCmdOptions {
}
}
}
if (recognizedArgsIndices != null) {
// mark the all non-option arguments (the tail) as recognized
for (int j = firstNonOptionArgIndex; j < recognizedArgsIndices.length; j++) {
recognizedArgsIndices[j] = true;
}
}
// adjust for inserted executable name
return new RCmdOptions(options, args, firstNonOptionArgIndex);
}
......
......@@ -30,15 +30,11 @@ import java.io.OutputStream;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Supplier;
import org.graalvm.options.OptionCategory;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Context.Builder;
import org.graalvm.polyglot.PolyglotException;
import org.graalvm.polyglot.Source;
......@@ -47,37 +43,6 @@ import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption;
import jline.console.UserInterruptException;
class RLauncher extends Launcher {
private final Client client;
RLauncher(Client client) {
this.client = client;
}
@Override
protected void printHelp(OptionCategory maxCategory) {
RCmdOptions.printHelp(client);
}
@Override
protected void printVersion() {
RCmdOptions.printVersion();
}
@Override
protected void collectArguments(Set<String> options) {
for (RCmdOption option : RCmdOption.values()) {
if (option.shortName != null) {
options.add(option.shortName);
}
if (option.plainName != null) {
options.add(option.plainName);
}
}
}
}
/*
* TODO:
*
......@@ -89,40 +54,25 @@ class RLauncher extends Launcher {
/**
* Emulates the (Gnu)R command as precisely as possible.
*/
public class RCommand {
// CheckStyle: stop system..print check
public static RuntimeException fatal(String message, Object... args) {
System.out.println("FATAL: " + String.format(message, args));
System.exit(-1);
return new RuntimeException();
}
public class RCommand extends RAbstractLauncher {
public static RuntimeException fatal(Throwable t, String message, Object... args) {
t.printStackTrace();
System.out.println("FATAL: " + String.format(message, args));
System.exit(-1);
return null;
RCommand(String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
super(Client.R, env, inStream, outStream, errStream);
}
public static void main(String[] args) {
try {
System.exit(doMain(prependCommand(args), null, System.in, System.out, System.err));
// never returns
throw fatal("main should never return");
} catch (Throwable t) {
throw fatal(t, "error during REPL execution");
}
@Override
protected String[] getArguments() {
return options.getArguments();
}
static String[] prependCommand(String[] args) {
String[] result = new String[args.length + 1];
result[0] = "R";
System.arraycopy(args, 0, result, 1, args.length);
return result;
@Override
protected void launch(Builder contextBuilder) {
super.launch(contextBuilder);
StartupTiming.timestamp("VM Created");
StartupTiming.printSummary();
}
public static int doMain(String[] args, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
private int execute(String[] args) {
StartupTiming.timestamp("Main Entered");
ArrayList<String> argsList = new ArrayList<>(Arrays.asList(args));
if (System.console() != null) {
......@@ -143,34 +93,8 @@ public class RCommand {
}
}
boolean useJVM = false;
RLauncher launcher = new RLauncher(Client.R);
Map<String, String> polyglotOptions = new HashMap<>();
Iterator<String> iterator = argsList.iterator();
if (iterator.hasNext()) {
iterator.next(); // skip first argument
while (iterator.hasNext()) {
String arg = iterator.next();
if ("--jvm".equals(arg)) {
useJVM = true;
iterator.remove();
} else if (launcher.parsePolyglotOption("R", polyglotOptions, arg)) {
iterator.remove();
}
}
}
if (launcher.runPolyglotAction()) {
return 0;
}
RCmdOptions options = RCmdOptions.parseArguments(Client.R, argsList.toArray(new String[argsList.size()]), false);
assert env == null || env.length == 0 : "re-enable setting environments";
ConsoleHandler consoleHandler = createConsoleHandler(options, null, inStream, outStream);
try (Context context = Context.newBuilder().allowAllAccess(true).allowHostAccess(useJVM).options(polyglotOptions).arguments("R", options.getArguments()).in(
consoleHandler.createInputStream()).out(outStream).err(errStream).build()) {
consoleHandler.setContext(context);
StartupTiming.timestamp("VM Created");
StartupTiming.printSummary();
launch(argsList.toArray(new String[0]));
if (context != null) {
File srcFile = null;
String fileOption = options.getString(RCmdOption.FILE);
if (fileOption != null) {
......@@ -178,6 +102,45 @@ public class RCommand {
}
return readEvalPrint(context, consoleHandler, srcFile);
} else {
return 0;
}
}
// CheckStyle: stop system..print check
public static RuntimeException fatal(String message, Object... args) {
System.out.println("FATAL: " + String.format(message, args));
System.exit(-1);
return new RuntimeException();
}
public static RuntimeException fatal(Throwable t, String message, Object... args) {
t.printStackTrace();
System.out.println("FATAL: " + String.format(message, args));
System.exit(-1);
return null;
}
static String[] prependCommand(String[] args) {
String[] result = new String[args.length + 1];
result[0] = "R";
System.arraycopy(args, 0, result, 1, args.length);
return result;
}
public static void main(String[] args) {
try {
System.exit(doMain(prependCommand(args), null, System.in, System.out, System.err));
// never returns
throw fatal("main should never return");
} catch (Throwable t) {
throw fatal(t, "error during REPL execution");
}
}
public static int doMain(String[] args, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
try (RCommand rcmd = new RCommand(env, inStream, outStream, errStream)) {
return rcmd.execute(args);
}
}
......
......@@ -26,14 +26,10 @@ import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.graalvm.options.OptionCategory;
import org.graalvm.polyglot.Context;
import com.oracle.truffle.r.launcher.RCmdOptions.Client;
import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption;
......@@ -43,11 +39,43 @@ import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption;
* way but the effect is similar.
*
*/
public class RscriptCommand {
public final class RscriptCommand extends RAbstractLauncher {
private String[] rScriptArguments;
RscriptCommand(String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
super(Client.RSCRIPT, env, inStream, outStream, errStream);
}
@Override
protected List<String> preprocessArguments(List<String> arguments, Map<String, String> polyglotOptions) {
List<String> unrecognizedArgs = super.preprocessArguments(arguments, polyglotOptions);
try {
this.rScriptArguments = preprocessRScriptOptions(options);
return unrecognizedArgs;
} catch (PrintHelp e) {
return Collections.singletonList("--help");
}
}
@Override
protected String[] getArguments() {
return rScriptArguments;
}
protected int execute(String[] args) {
launch(args);
if (context != null) {
String fileOption = options.getString(RCmdOption.FILE);
return RCommand.readEvalPrint(context, consoleHandler, fileOption != null ? new File(fileOption) : null);
} else {
return 0;
}
}
// CheckStyle: stop system..print check
private static String[] preprocessRScriptOptions(RLauncher launcher, RCmdOptions options) {
private static String[] preprocessRScriptOptions(RCmdOptions options) throws PrintHelp {
String[] arguments = options.getArguments();
int resultArgsLength = arguments.length;
int firstNonOptionArgIndex = options.getFirstNonOptionArgIndex();
......@@ -61,11 +89,7 @@ public class RscriptCommand {
// Either -e options are set or first non-option arg is a file
if (options.getStringList(RCmdOption.EXPR) == null) {
if (firstNonOptionArgIndex == resultArgsLength) {
launcher.setHelpCategory(OptionCategory.USER);
// does not return
if (launcher.runPolyglotAction()) {
System.exit(1);
}
throw new PrintHelp();
} else {
options.setValue(RCmdOption.FILE, arguments[firstNonOptionArgIndex]);
}
......@@ -99,50 +123,18 @@ public class RscriptCommand {
return adjArgs.toArray(new String[adjArgs.size()]);
}
@SuppressWarnings("serial")
static class PrintHelp extends Exception {
}
public static void main(String[] args) {
System.exit(doMain(RCommand.prependCommand(args), null, System.in, System.out, System.err));
throw RCommand.fatal("should not reach here");
}
public static int doMain(String[] args, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) {
assert env == null : "re-enble environment variables";
ArrayList<String> argsList = new ArrayList<>(Arrays.asList(args));
RLauncher launcher = new RLauncher(Client.RSCRIPT) {
@Override
protected void printVersion() {
System.out.print("R scripting front-end version ");
System.out.print(RVersionNumber.FULL);
System.out.println(RVersionNumber.RELEASE_DATE);
}
};
boolean useJVM = false;
Map<String, String> polyglotOptions = new HashMap<>();
Iterator<String> iterator = argsList.iterator();
if (iterator.hasNext()) {
iterator.next(); // skip first argument
while (iterator.hasNext()) {
String arg = iterator.next();
if ("--jvm".equals(arg)) {
useJVM = true;
iterator.remove();
} else if (launcher.parsePolyglotOption("R", polyglotOptions, arg)) {
iterator.remove();
}
}
}
if (launcher.runPolyglotAction()) {
return 0;
}
RCmdOptions options = RCmdOptions.parseArguments(Client.RSCRIPT, argsList.toArray(new String[argsList.size()]), false);
String[] arguments = preprocessRScriptOptions(launcher, options);
ConsoleHandler consoleHandler = RCommand.createConsoleHandler(options, null, inStream, outStream);
try (Context context = Context.newBuilder().allowAllAccess(true).allowHostAccess(useJVM).options(polyglotOptions).arguments("R", arguments).in(consoleHandler.createInputStream()).out(
outStream).err(errStream).build()) {
consoleHandler.setContext(context);
String fileOption = options.getString(RCmdOption.FILE);
return RCommand.readEvalPrint(context, consoleHandler, fileOption != null ? new File(fileOption) : null);
try (RscriptCommand rcmd = new RscriptCommand(env, inStream, outStream, errStream)) {
return rcmd.execute(args);
}
}
}
......@@ -231,6 +231,7 @@ suite = {
"sourceDirs" : ["src"],
"dependencies" : [
"sdk:GRAAL_SDK",
"sdk:LAUNCHER_COMMON",
"truffle:JLINE",
],
"checkstyle" : "com.oracle.truffle.r.runtime",
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment