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

org.jline.script.GroovyCommand Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2002-2021, the original author(s).
 *
 * This software is distributable under the BSD license. See the terms of the
 * BSD license in the documentation provided with this software.
 *
 * https://opensource.org/licenses/BSD-3-Clause
 */
package org.jline.script;

import java.io.File;
import java.nio.file.*;
import java.util.*;
import java.util.stream.Stream;

import org.jline.builtins.Completers;
import org.jline.builtins.Completers.OptDesc;
import org.jline.builtins.Completers.OptionCompleter;
import org.jline.console.CmdDesc;
import org.jline.console.CommandInput;
import org.jline.console.CommandMethods;
import org.jline.console.CommandRegistry;
import org.jline.console.Printer;
import org.jline.console.impl.AbstractCommandRegistry;
import org.jline.groovy.ObjectInspector;
import org.jline.reader.Completer;
import org.jline.reader.impl.completer.ArgumentCompleter;
import org.jline.reader.impl.completer.NullCompleter;
import org.jline.reader.impl.completer.StringsCompleter;
import org.jline.utils.AttributedString;

import groovy.console.ui.Console;
import groovy.console.ui.ObjectBrowser;

public class GroovyCommand extends AbstractCommandRegistry implements CommandRegistry {
    public enum Command {
        INSPECT,
        CONSOLE,
        GRAB,
        CLASSLOADER
    }

    private static final String DEFAULT_NANORC_VALUE = "classpath:/org/jline/groovy/gron.nanorc";
    private final GroovyEngine engine;
    private final Printer printer;
    private final Map commandDescs = new HashMap<>();
    private final Map> commandInfos = new HashMap<>();
    private boolean consoleUi;
    private boolean ivy;

    public GroovyCommand(GroovyEngine engine, Printer printer) {
        this(null, engine, printer);
    }

    @SuppressWarnings("this-escape")
    public GroovyCommand(Set commands, GroovyEngine engine, Printer printer) {
        this.engine = engine;
        this.printer = printer;
        try {
            Class.forName("groovy.console.ui.ObjectBrowser");
            consoleUi = true;
        } catch (Exception e) {
            // ignore
        }
        try {
            Class.forName("org.apache.ivy.util.Message");
            System.setProperty("groovy.grape.report.downloads", "false");
            ivy = true;
        } catch (Exception e) {
            // ignore
        }
        Set cmds;
        Map commandName = new HashMap<>();
        Map commandExecute = new HashMap<>();
        if (commands == null) {
            cmds = new HashSet<>(EnumSet.allOf(Command.class));
        } else {
            cmds = new HashSet<>(commands);
        }
        if (!consoleUi) {
            cmds.remove(Command.CONSOLE);
        }
        if (!ivy) {
            cmds.remove(Command.GRAB);
        }
        for (Command c : cmds) {
            commandName.put(c, c.name().toLowerCase());
        }
        commandExecute.put(Command.INSPECT, new CommandMethods(this::inspect, this::inspectCompleter));
        commandExecute.put(Command.CONSOLE, new CommandMethods(this::console, this::defaultCompleter));
        commandExecute.put(Command.GRAB, new CommandMethods(this::grab, this::defaultCompleter));
        commandExecute.put(Command.CLASSLOADER, new CommandMethods(this::classLoader, this::classloaderCompleter));
        registerCommands(commandName, commandExecute);
        commandDescs.put(Command.INSPECT, inspectCmdDesc());
        commandDescs.put(Command.CONSOLE, consoleCmdDesc());
        commandDescs.put(Command.GRAB, grabCmdDesc());
        commandDescs.put(Command.CLASSLOADER, classLoaderCmdDesc());
    }

    @Override
    public List commandInfo(String command) {
        Command cmd = (Command) registeredCommand(command);
        return commandInfos.get(cmd);
    }

    @Override
    public CmdDesc commandDescription(List args) {
        String command = args != null && !args.isEmpty() ? args.get(0) : "";
        Command cmd = (Command) registeredCommand(command);
        return commandDescs.get(cmd);
    }

    @SuppressWarnings("unchecked")
    public Object grab(CommandInput input) {
        if (input.xargs().length == 0) {
            return null;
        }
        if (input.args().length > 2) {
            throw new IllegalArgumentException("Wrong number of command parameters: " + input.args().length);
        }
        try {
            String arg = input.args()[0];
            if (arg.equals("-?") || arg.equals("--help")) {
                printer.println(helpDesc(Command.GRAB));
            } else if (arg.equals("-l") || arg.equals("--list")) {
                Object resp = engine.execute("groovy.grape.Grape.getInstance().enumerateGrapes()");
                Map options = new HashMap<>();
                options.put(Printer.SKIP_DEFAULT_OPTIONS, true);
                options.put(Printer.MAX_DEPTH, 1);
                options.put(Printer.INDENTION, 4);
                options.put(Printer.VALUE_STYLE, engine.groovyOption(GroovyEngine.NANORC_VALUE, DEFAULT_NANORC_VALUE));
                printer.println(options, resp);
            } else {
                int artifactId = 0;
                if (input.args().length == 2) {
                    if (input.args()[0].equals("-v") || input.args()[0].equals("--verbose")) {
                        System.setProperty("groovy.grape.report.downloads", "true");
                        artifactId = 1;
                    } else if (input.args()[1].equals("-v") || input.args()[1].equals("--verbose")) {
                        System.setProperty("groovy.grape.report.downloads", "true");
                    } else {
                        throw new IllegalArgumentException("Unknown command parameters!");
                    }
                }
                Map artifact = new HashMap<>();
                Object xarg = input.xargs()[artifactId];
                if (xarg instanceof String) {
                    String[] vals = input.args()[artifactId].split(":");
                    if (vals.length != 3) {
                        throw new IllegalArgumentException("Invalid command parameter: " + input.args()[artifactId]);
                    }
                    artifact.put("group", vals[0]);
                    artifact.put("module", vals[1]);
                    artifact.put("version", vals[2]);
                } else if (xarg instanceof Map) {
                    artifact = (Map) xarg;
                } else {
                    throw new IllegalArgumentException("Unknown command parameter: " + xarg);
                }
                engine.put("_artifact", artifact);
                engine.execute("groovy.grape.Grape.grab(_artifact)");
            }
        } catch (Exception e) {
            saveException(e);
        } finally {
            System.setProperty("groovy.grape.report.downloads", "false");
        }
        return null;
    }

    public void console(CommandInput input) {
        if (input.args().length > 1) {
            throw new IllegalArgumentException("Wrong number of command parameters: " + input.args().length);
        }
        if (input.args().length == 1) {
            String arg = input.args()[0];
            if (arg.equals("-?") || arg.equals("--help")) {
                printer.println(helpDesc(Command.CONSOLE));
                return;
            } else {
                throw new IllegalArgumentException("Unknown command parameter: " + input.args()[0]);
            }
        }
        Console c = new Console(engine.sharedData);
        c.run();
    }

    public Object inspect(CommandInput input) {
        if (input.xargs().length == 0) {
            return null;
        }
        if (input.args().length > 2) {
            throw new IllegalArgumentException("Wrong number of command parameters: " + input.args().length);
        }
        int idx = optionIdx(input.args());
        String option = idx < 0 ? "--info" : input.args()[idx];
        if (option.equals("-?") || option.equals("--help")) {
            printer.println(helpDesc(Command.INSPECT));
            return null;
        }
        int id = 0;
        if (idx >= 0) {
            id = idx == 0 ? 1 : 0;
        }
        if (input.args().length < id + 1) {
            throw new IllegalArgumentException("Wrong number of command parameters: " + input.args().length);
        }
        try {
            Object obj = input.xargs()[id];
            ObjectInspector inspector = new ObjectInspector(obj);
            Object out = null;
            Map options = new HashMap<>();
            if (option.equals("-m") || option.equals("--methods")) {
                out = inspector.methods();
                options.put(Printer.COLUMNS, ObjectInspector.METHOD_COLUMNS);
            } else if (option.equals("-n") || option.equals("--metaMethods")) {
                out = inspector.metaMethods();
                options.put(Printer.COLUMNS, ObjectInspector.METHOD_COLUMNS);
            } else if (option.equals("-i") || option.equals("--info")) {
                out = inspector.properties();
                options.put(Printer.VALUE_STYLE, engine.groovyOption(GroovyEngine.NANORC_VALUE, DEFAULT_NANORC_VALUE));
            } else if (consoleUi && (option.equals("-g") || option.equals("--gui"))) {
                ObjectBrowser.inspect(obj);
            } else {
                throw new IllegalArgumentException("Unknown option: " + option);
            }
            options.put(Printer.SKIP_DEFAULT_OPTIONS, true);
            options.put(Printer.MAX_DEPTH, 1);
            options.put(Printer.INDENTION, 4);
            printer.println(options, out);
        } catch (Exception e) {
            saveException(e);
        }
        return null;
    }

    private Object classLoader(CommandInput input) {
        if (input.args().length > 2) {
            throw new IllegalArgumentException("Wrong number of command parameters: " + input.args().length);
        }
        String option = "--view";
        String arg = null;
        if (input.args().length > 0) {
            String[] args = input.args();
            int idx = optionIdx(args);
            option = idx > -1 ? args[idx] : "--view";
            if (option.contains("=")) {
                arg = option.substring(option.indexOf("=") + 1);
                option = option.substring(0, option.indexOf("="));
            } else if (input.args().length == 2 && idx > -1) {
                arg = idx == 0 ? args[1] : args[0];
            }
        }
        try {
            switch (option) {
                case "-?":
                case "--help":
                    printer.println(helpDesc(Command.CLASSLOADER));
                    break;
                case "-v":
                case "--view":
                    Map options = new HashMap<>();
                    options.put(Printer.SKIP_DEFAULT_OPTIONS, true);
                    options.put(
                            Printer.VALUE_STYLE, engine.groovyOption(GroovyEngine.NANORC_VALUE, DEFAULT_NANORC_VALUE));
                    options.put(Printer.MAX_DEPTH, 1);
                    options.put(Printer.INDENTION, 4);
                    options.put(Printer.COLUMNS, Arrays.asList("loadedClasses", "definedPackages", "classPath"));
                    printer.println(options, engine.classLoader);
                    break;
                case "-d":
                case "--delete":
                    engine.purgeClassCache(arg != null ? arg.replace("*", ".*") : null);
                    break;
                case "-a":
                case "--add":
                    File file = arg != null ? new File(arg) : null;
                    if (file == null || !file.exists()) {
                        throw new IllegalArgumentException("Bad or missing argument!");
                    }
                    if (file.isDirectory()) {
                        String separator = FileSystems.getDefault().getSeparator();
                        if (separator.equals("\\") && !arg.contains("\\") && arg.contains("/")) {
                            arg = arg.replace("/", "\\");
                        }
                        if (arg.endsWith(separator)) {
                            separator = "";
                        }
                        PathMatcher matcher = FileSystems.getDefault()
                                .getPathMatcher("regex:"
                                        + arg.replace("\\", "\\\\").replace(".", "\\.")
                                        + separator.replace("\\", "\\\\") + ".*\\.jar");
                        try (Stream pathStream = Files.walk(Paths.get(arg))) {
                            pathStream
                                    .filter(matcher::matches)
                                    .map(Path::toString)
                                    .forEach(engine.classLoader::addClasspath);
                        }
                    } else {
                        engine.classLoader.addClasspath(arg);
                    }
                    break;
            }
        } catch (Exception exp) {
            saveException(exp);
        }
        return null;
    }

    private CmdDesc helpDesc(Command command) {
        return doHelpDesc(command.toString().toLowerCase(), commandInfos.get(command), commandDescs.get(command));
    }

    private CmdDesc grabCmdDesc() {
        Map> optDescs = new HashMap<>();
        optDescs.put("-? --help", doDescription("Displays command help"));
        optDescs.put("-l --list", doDescription("List the modules in the cache"));
        optDescs.put("-v --verbose", doDescription("Report downloads"));
        CmdDesc out = new CmdDesc(new ArrayList<>(), optDescs);
        List mainDesc = new ArrayList<>();
        List info = new ArrayList<>();
        info.add("Add maven repository dependencies to classpath");
        commandInfos.put(Command.GRAB, info);
        mainDesc.add(new AttributedString("grab [OPTIONS] ::"));
        mainDesc.add(new AttributedString("grab --list"));
        out.setMainDesc(mainDesc);
        out.setHighlighted(false);
        return out;
    }

    private CmdDesc consoleCmdDesc() {
        Map> optDescs = new HashMap<>();
        optDescs.put("-? --help", doDescription("Displays command help"));
        CmdDesc out = new CmdDesc(new ArrayList<>(), optDescs);
        List mainDesc = new ArrayList<>();
        List info = new ArrayList<>();
        info.add("Launch Groovy console");
        commandInfos.put(Command.CONSOLE, info);
        mainDesc.add(new AttributedString("console"));
        out.setMainDesc(mainDesc);
        out.setHighlighted(false);
        return out;
    }

    private CmdDesc inspectCmdDesc() {
        Map> optDescs = new HashMap<>();
        optDescs.put("-? --help", doDescription("Displays command help"));
        if (consoleUi) {
            optDescs.put("-g --gui", doDescription("Launch object browser"));
        }
        optDescs.put("-i --info", doDescription("Object class info"));
        optDescs.put("-m --methods", doDescription("List object methods"));
        optDescs.put("-n --metaMethods", doDescription("List object metaMethods"));
        CmdDesc out = new CmdDesc(new ArrayList<>(), optDescs);
        List mainDesc = new ArrayList<>();
        List info = new ArrayList<>();
        info.add("Display object info on terminal");
        commandInfos.put(Command.INSPECT, info);
        mainDesc.add(new AttributedString("inspect [OPTION] OBJECT"));
        out.setMainDesc(mainDesc);
        out.setHighlighted(false);
        return out;
    }

    private CmdDesc classLoaderCmdDesc() {
        Map> optDescs = new HashMap<>();
        optDescs.put("-? --help", doDescription("Displays command help"));
        optDescs.put("-v --view", doDescription("View class loader info"));
        optDescs.put("-d --delete [REGEX]", doDescription("Delete loaded classes"));
        optDescs.put("-a --add PATH", doDescription("Add classpath PATH - a jar file or a directory"));
        CmdDesc out = new CmdDesc(new ArrayList<>(), optDescs);
        List mainDesc = new ArrayList<>();
        List info = new ArrayList<>();
        info.add("Display and manage Groovy classLoader data");
        commandInfos.put(Command.CLASSLOADER, info);
        mainDesc.add(new AttributedString("classloader"));
        out.setMainDesc(mainDesc);
        out.setHighlighted(false);
        return out;
    }

    private List doDescription(String description) {
        List out = new ArrayList<>();
        out.add(new AttributedString(description));
        return out;
    }

    private int optionIdx(String[] args) {
        int out = 0;
        for (String a : args) {
            if (a.startsWith("-")) {
                return out;
            }
            out++;
        }
        return -1;
    }

    private List variables() {
        List out = new ArrayList<>();
        for (String v : engine.find(null).keySet()) {
            out.add("$" + v);
        }
        return out;
    }

    private List compileOptDescs(String command) {
        List out = new ArrayList<>();
        Command cmd = Command.valueOf(command.toUpperCase());
        for (Map.Entry> entry :
                commandDescs.get(cmd).getOptsDesc().entrySet()) {
            String[] option = entry.getKey().split("\\s+");
            String desc = entry.getValue().get(0).toString();
            if (option.length == 2) {
                out.add(new OptDesc(option[0], option[1], desc));
            } else if (option[0].charAt(1) == '-') {
                out.add(new OptDesc(null, option[0], desc));
            } else {
                out.add(new OptDesc(option[0], null, desc));
            }
        }
        return out;
    }

    private List classloaderCompleter(String command) {
        List out = new ArrayList<>();
        List argsCompleters = Collections.singletonList(NullCompleter.INSTANCE);
        List options = new ArrayList<>();
        options.add(new OptDesc("-?", "--help", NullCompleter.INSTANCE));
        options.add(new OptDesc("-a", "--add", new Completers.FilesCompleter(new File("."), "*.jar")));
        options.add(new OptDesc("-d", "--delete", NullCompleter.INSTANCE));
        options.add(new OptDesc("-v", "--view", NullCompleter.INSTANCE));
        ArgumentCompleter ac =
                new ArgumentCompleter(NullCompleter.INSTANCE, new OptionCompleter(argsCompleters, options, 1));
        out.add(ac);
        return out;
    }

    private List inspectCompleter(String command) {
        List out = new ArrayList<>();
        ArgumentCompleter ac = new ArgumentCompleter(
                NullCompleter.INSTANCE,
                new OptionCompleter(
                        Arrays.asList(new StringsCompleter(this::variables), NullCompleter.INSTANCE),
                        this::compileOptDescs,
                        1));
        out.add(ac);
        return out;
    }

    private List defaultCompleter(String command) {
        List out = new ArrayList<>();
        ArgumentCompleter ac = new ArgumentCompleter(
                NullCompleter.INSTANCE, new OptionCompleter(NullCompleter.INSTANCE, this::compileOptDescs, 1));
        out.add(ac);
        return out;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy