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

groovy.ui.GroovyMain Maven / Gradle / Ivy

The newest version!
/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */
package groovy.ui;

import groovy.lang.Binding;
import groovy.lang.GroovyCodeSource;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.GroovyShell;
import groovy.lang.GroovySystem;
import groovy.lang.MissingMethodException;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilationFailedException;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.ImportCustomizer;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.runtime.InvokerInvocationException;
import org.codehaus.groovy.runtime.ResourceGroovyMethods;
import org.codehaus.groovy.runtime.StackTraceUtils;
import org.codehaus.groovy.runtime.StringGroovyMethods;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.IVersionProvider;
import picocli.CommandLine.Option;
import picocli.CommandLine.ParameterException;
import picocli.CommandLine.ParseResult;
import picocli.CommandLine.Unmatched;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * A Command line to execute groovy.
 */
public class GroovyMain {

    // arguments to the script
    private List args;

    // is this a file on disk
    private boolean isScriptFile;

    // filename or content of script
    private String script;

    // process args as input files
    private boolean processFiles;

    // edit input files in place
    private boolean editFiles;

    // automatically output the result of each script
    private boolean autoOutput;

    // automatically split each line using the splitpattern
    private boolean autoSplit;

    // The pattern used to split the current line
    private String splitPattern = " ";

    // process sockets
    private boolean processSockets;

    // port to listen on when processing sockets
    private int port;

    // backup input files with extension
    private String backupExtension;

    // do you want full stack traces in script exceptions?
    private boolean debug = false;

    // Compiler configuration, used to set the encodings of the scripts/classes
    private CompilerConfiguration conf = new CompilerConfiguration(System.getProperties());

    /**
     * Main CLI interface.
     *
     * @param args all command line args.
     */
    public static void main(String[] args) {
        processArgs(args, System.out, System.err);
    }

    // package-level visibility for testing purposes (just usage/errors at this stage)
    @Deprecated
    static void processArgs(String[] args, final PrintStream out) {
        processArgs(args, out, out);
    }

    // package-level visibility for testing purposes (just usage/errors at this stage)
    static void processArgs(String[] args, final PrintStream out, final PrintStream err) {
        GroovyCommand groovyCommand = new GroovyCommand();

        CommandLine parser = new CommandLine(groovyCommand)
                .setOut(new PrintWriter(out))
                .setErr(new PrintWriter(err))
                .setUnmatchedArgumentsAllowed(true)
                .setStopAtUnmatched(true);

        try {
            ParseResult result = parser.parseArgs(args);

            if (CommandLine.printHelpIfRequested(result)) {
                return;
            }

            // TODO: pass printstream(s) down through process
            if (!groovyCommand.process(parser)) {
                // If we fail, then exit with an error so scripting frameworks can catch it.
                System.exit(1);
            }

        } catch (ParameterException ex) { // command line arguments could not be parsed
            err.println(ex.getMessage());
            ex.getCommandLine().usage(err);
        } catch (IOException ioe) {
            err.println("error: " + ioe.getMessage());
        }
    }

    public static class VersionProvider implements IVersionProvider {
        @Override
        public String[] getVersion() {
            return new String[] {
                    "Groovy Version: " + GroovySystem.getVersion() + " JVM: " + System.getProperty("java.version") +
                    " Vendor: " + System.getProperty("java.vm.vendor")  + " OS: " + System.getProperty("os.name")
            };
        }
    }

    @Command(name = "groovy",
            customSynopsis = "groovy [options] [filename] [args]",
            description = "The Groovy command line processor.",
            sortOptions = false,
            versionProvider = VersionProvider.class)
    private static class GroovyCommand {

        // IMPLEMENTATION NOTE:
        // classpath must be the first argument, so that the `startGroovy(.bat)` script
        // can extract it and the JVM can be started with the classpath already correctly set.
        // This saves us from having to fork a new JVM process with the classpath set from the processed arguments.
        @Option(names = {"-cp", "-classpath", "--classpath"}, paramLabel = "", description = "Specify where to find the class files - must be first argument")
        private String classpath;

        @Option(names = {"-D", "--define"}, paramLabel = "", description = "Define a system property")
        private Map systemProperties = new LinkedHashMap();

        @Option(names = "--disableopt", paramLabel = "optlist", split = ",",
                description = {
                        "Disables one or all optimization elements; optlist can be a comma separated list with the elements: ",
                                "all (disables all optimizations), ",
                                "int (disable any int based optimizations)"})
        private List disableopt = new ArrayList();

        @Option(names = {"-d", "--debug"}, description = "Debug mode will print out full stack traces")
        private boolean debug;

        @Option(names = {"-c", "--encoding"}, paramLabel = "", description = "Specify the encoding of the files")
        private String encoding;

        @Option(names = {"-e"}, paramLabel = "