All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.graalvm.launcher.LanguageLauncherBase Maven / Gradle / Ivy

There is a newer version: 24.1.1
Show newest version
/*
 * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * The Universal Permissive License (UPL), Version 1.0
 *
 * Subject to the condition set forth below, permission is hereby granted to any
 * person obtaining a copy of this software, associated documentation and/or
 * data (collectively the "Software"), free of charge and under any and all
 * copyright rights in the Software, and any and all patent rights owned or
 * freely licensable by each licensor hereunder covering either (i) the
 * unmodified Software as contributed to or provided by such licensor, or (ii)
 * the Larger Works (as defined below), to deal in both
 *
 * (a) the Software, and
 *
 * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
 * one is included with the Software each a "Larger Work" to which the Software
 * is contributed by such licensors),
 *
 * without restriction, including without limitation the rights to copy, create
 * derivative works of, display, perform, and distribute the Software and make,
 * use, sell, offer for sale, import, export, have made, and have sold the
 * Software and the Larger Work(s), and to sublicense the foregoing rights on
 * either these or other terms.
 *
 * This license is subject to the following condition:
 *
 * The above copyright notice and either this complete permission notice or at a
 * minimum a reference to the UPL must be included in all copies or substantial
 * portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.graalvm.launcher;

import java.io.IOException;
import static java.lang.Integer.max;
import java.nio.file.Path;
import java.util.ArrayList;
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.Context;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Instrument;
import org.graalvm.polyglot.Language;
import org.graalvm.polyglot.PolyglotException;

/**
 * Base implementation for polyglot-aware languages and tools. Prints additional language-related
 * help items, prints installed engine's options.
 */
public abstract class LanguageLauncherBase extends Launcher {
    private static Engine tempEngine;
    private boolean seenPolyglot;
    private boolean helpTools;
    private boolean helpLanguages;
    private VersionAction versionAction = VersionAction.None;

    final boolean isPolyglot() {
        return seenPolyglot;
    }

    final void setPolyglot(boolean polyglot) {
        seenPolyglot = polyglot;
    }

    final void setupContextBuilder(Context.Builder builder) {
        Path logFile = getLogFile();
        if (logFile != null) {
            try {
                builder.logHandler(newLogStream(logFile));
            } catch (IOException ioe) {
                throw abort(ioe);
            }
        }
        if (System.err != getError()) {
            builder.err(getError());
        }
        if (System.out != getOutput()) {
            builder.out(getOutput());
        }
    }

    static Engine getTempEngine() {
        if (tempEngine == null) {
            tempEngine = Engine.create();
        }
        return tempEngine;
    }

    protected void argumentsProcessingDone() {
        if (tempEngine != null) {
            tempEngine.close();
            tempEngine = null;
        }
    }

    @Override
    protected boolean runLauncherAction() {
        switch (versionAction) {
            case PrintAndExit:
                printPolyglotVersions();
                return true;
            case PrintAndContinue:
                printPolyglotVersions();
                break;
            case None:
                break;
        }
        return super.runLauncherAction();
    }

    @Override
    protected boolean parseCommonOption(String defaultOptionPrefix, Map polyglotOptions, boolean experimentalOptions, String arg) {
        switch (arg) {
            case "--help:tools":
                helpTools = true;
                break;
            case "--help:languages":
                helpLanguages = true;
                break;
            case "--polyglot":
                seenPolyglot = true;
                break;
            case "--version:graalvm":
                versionAction = VersionAction.PrintAndExit;
                break;
            case "--show-version:graalvm":
                versionAction = VersionAction.PrintAndContinue;
                break;
            default:
                return super.parseCommonOption(defaultOptionPrefix, polyglotOptions, experimentalOptions, arg);
        }
        return true;
    }

    void handlePolyglotException(PolyglotException e) {
        if (e.getMessage() != null) {
            System.err.println("ERROR: " + e.getMessage());
        }
        if (e.isInternalError()) {
            e.printStackTrace();
        }
        if (e.isExit()) {
            System.exit(e.getExitStatus());
        } else {
            System.exit(1);
        }
    }

    @Override
    protected void printDefaultHelp(OptionCategory helpCategory) {
        super.printDefaultHelp(helpCategory);
        launcherOption("--version:graalvm", "Print GraalVM version information and exit.");
        launcherOption("--show-version:graalvm", "Print GraalVM version information and continue execution.");
        launcherOption("--help:languages", "Print options for all installed languages.");
        launcherOption("--help:tools", "Print options for all installed tools.");
        launcherOption("--help:expert", "Print additional options for experts.");
        launcherOption("--help:internal", "Print internal options for debugging language implementations and tools.");
        printEngineOptions(getTempEngine(), helpCategory);
    }

    @Override
    protected void maybePrintAdditionalHelp(OptionCategory helpCategory) {
        if (helpLanguages) {
            printLanguageOptions(getTempEngine(), helpCategory);
            printOtherHelpCategory("language", "--help:languages");
        }
        if (helpTools) {
            printInstrumentOptions(getTempEngine(), helpCategory);
            printOtherHelpCategory("tool", "--help:tools");
        }
    }

    /**
     * Prints version information about all known {@linkplain Language languages} and
     * {@linkplain Instrument instruments} on {@linkplain System#out stdout}.
     */
    protected void printPolyglotVersions() {
        Engine engine = getTempEngine();
        String mode = isAOT() ? "Native" : "JVM";
        println(engine.getImplementationName() + " " + mode + " Polyglot Engine Version " + engine.getVersion());
        println("Java Version " + System.getProperty("java.version"));
        println("Java VM Version " + System.getProperty("java.vm.version"));
        Path graalVMHome = Engine.findHome();
        if (graalVMHome != null) {
            println("GraalVM Home " + graalVMHome);
        }
        printLanguages(engine, true);
        printInstruments(engine, true);
    }

    @Override
    protected OptionDescriptor findOptionDescriptor(String group, String key) {
        OptionDescriptors descriptors = null;
        switch (group) {
            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);

    }

    private void printEngineOptions(Engine engine, OptionCategory optionCategory) {
        List engineOptions = filterOptions(engine.getOptions(), optionCategory);
        if (!engineOptions.isEmpty()) {
            println();
            printOptions(engineOptions, optionsTitle("engine", optionCategory), 2);
        }
    }

    private void printInstrumentOptions(Engine engine, OptionCategory optionCategory) {
        Map> instrumentsOptions = new HashMap<>();
        List instruments = sortedInstruments(engine);
        for (Instrument instrument : instruments) {
            List options = filterOptions(instrument.getOptions(), optionCategory);
            if (!options.isEmpty()) {
                instrumentsOptions.put(instrument, options);
            }
        }
        if (!instrumentsOptions.isEmpty()) {
            println();
            println(optionsTitle("tool", optionCategory));
            for (Instrument instrument : instruments) {
                List options = instrumentsOptions.get(instrument);
                if (options != null) {
                    printOptions(options, "  " + instrument.getName() + ":", 4);
                }
            }
        }
    }

    private void printLanguageOptions(Engine engine, OptionCategory optionCategory) {
        Map> languagesOptions = new HashMap<>();
        List languages = sortedLanguages(engine);
        for (Language language : languages) {
            List options = filterOptions(language.getOptions(), optionCategory);
            if (!options.isEmpty()) {
                languagesOptions.put(language, options);
            }
        }
        if (!languagesOptions.isEmpty()) {
            println();
            println(optionsTitle("language", optionCategory));
            for (Language language : languages) {
                List options = languagesOptions.get(language);
                if (options != null) {
                    printOptions(options, "  " + language.getName() + ":", 4);
                }
            }
        }
    }

    private void printLanguages(Engine engine, boolean printWhenEmpty) {
        if (engine.getLanguages().isEmpty()) {
            if (printWhenEmpty) {
                println("  Installed Languages: none");
            }
        } else {
            println("  Installed Languages:");
            List 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 host;
                host = "";
                String version = language.getVersion();
                if (version == null || version.length() == 0) {
                    version = "";
                }
                System.out.printf(langFormat, language.getName().isEmpty() ? "Unnamed" : language.getName(), host, version);
            }
        }
    }

    private void printInstruments(Engine engine, boolean printWhenEmpty) {
        if (engine.getInstruments().isEmpty()) {
            if (printWhenEmpty) {
                println("  Installed Tools: none");
            }
        } else {
            println("  Installed Tools:");
            List 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() ? instrument.getId() : instrument.getName(), version);
            }
        }
    }

    private static List filterOptions(OptionDescriptors descriptors, OptionCategory optionCategory) {
        List options = new ArrayList<>();
        for (OptionDescriptor descriptor : descriptors) {
            if (!descriptor.isDeprecated() && sameCategory(descriptor, optionCategory)) {
                options.add(asPrintableOption(descriptor));
            }
        }
        return options;
    }

    private static boolean sameCategory(OptionDescriptor descriptor, OptionCategory optionCategory) {
        return descriptor.getCategory().ordinal() == optionCategory.ordinal();
    }

    void printOption(OptionCategory optionCategory, OptionDescriptor descriptor) {
        if (!descriptor.isDeprecated() && sameCategory(descriptor, optionCategory)) {
            printOption(asPrintableOption(descriptor));
        }
    }

    private static Launcher.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());
    }

    @Override
    protected void collectArguments(Set options) {
        options.add("--help:languages");
        options.add("--help:tools");
        options.add("--version:graalvm");
        options.add("--show-version:graalvm");

        Engine engine = getTempEngine();
        addOptions(engine.getOptions(), options);
        for (Instrument instrument : engine.getInstruments().values()) {
            addOptions(instrument.getOptions(), options);
        }

        String languageId = null;
        if (this instanceof AbstractLanguageLauncher) {
            languageId = ((AbstractLanguageLauncher) this).getLanguageId();
        }
        for (Language language : engine.getLanguages().values()) {
            if (language.getId().equals(languageId)) {
                for (OptionDescriptor descriptor : language.getOptions()) {
                    options.add("--" + descriptor.getName().substring(languageId.length() + 1));
                }
            }
            addOptions(language.getOptions(), options);
        }
    }

    private static void addOptions(OptionDescriptors descriptors, Set target) {
        for (OptionDescriptor descriptor : descriptors) {
            target.add("--" + descriptor.getName());
        }
    }

    static List sortedLanguages(Engine engine) {
        List languages = new ArrayList<>(engine.getLanguages().values());
        languages.sort(Comparator.comparing(Language::getId));
        return languages;
    }

    static List sortedInstruments(Engine engine) {
        List instruments = new ArrayList<>();
        for (Instrument instrument : engine.getInstruments().values()) {
            // no options not accessible to the user.
            if (!instrument.getOptions().iterator().hasNext()) {
                continue;
            }
            instruments.add(instrument);
        }
        instruments.sort(Comparator.comparing(Instrument::getId));
        return instruments;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy