You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2018/05/17 23:24:51 UTC
groovy git commit: GROOVY-8567 Migrate Groovyc to picocli
Repository: groovy
Updated Branches:
refs/heads/GROOVY_2_6_X 83c0d4df3 -> 0ac971717
GROOVY-8567 Migrate Groovyc to picocli
Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/0ac97171
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/0ac97171
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/0ac97171
Branch: refs/heads/GROOVY_2_6_X
Commit: 0ac971717ac07555ff9185b5a435a52b1a827ffe
Parents: 83c0d4d
Author: Remko Popma <re...@yahoo.com>
Authored: Sun May 6 16:21:17 2018 +0900
Committer: Paul King <pa...@asert.com.au>
Committed: Fri May 18 09:24:42 2018 +1000
----------------------------------------------------------------------
.../groovy/tools/FileSystemCompiler.java | 271 ++++++++++++-------
.../java/org/codehaus/groovy/ant/Groovyc.java | 19 +-
2 files changed, 172 insertions(+), 118 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/groovy/blob/0ac97171/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java b/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java
index df10a02..8b54b30 100644
--- a/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java
+++ b/src/main/java/org/codehaus/groovy/tools/FileSystemCompiler.java
@@ -20,12 +20,10 @@ package org.codehaus.groovy.tools;
import groovy.lang.GroovyResourceLoader;
import groovy.lang.GroovySystem;
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
-import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
+import picocli.CommandLine;
+import picocli.CommandLine.*;
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.ConfigurationException;
@@ -33,10 +31,7 @@ import org.codehaus.groovy.runtime.DefaultGroovyStaticMethods;
import org.codehaus.groovy.runtime.StringGroovyMethods;
import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
+import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
@@ -77,16 +72,37 @@ public class FileSystemCompiler {
unit.compile();
}
+ /** @deprecated use {@link #displayHelp(PrintWriter)} instead */
+ @Deprecated
public static void displayHelp(final Options options) {
final HelpFormatter formatter = new HelpFormatter();
formatter.printHelp(80, "groovyc [options] <source-files>", "options:", options, "");
}
+ /** Prints the usage help message for {@link CompilationOptions} to stderr.
+ * @see #displayHelp(PrintWriter)
+ * @since 2.5 */
+ public static void displayHelp() {
+ displayHelp(new PrintWriter(System.err, true));
+ }
+
+ /** Prints the usage help message for the {@link CompilationOptions} to the specified PrintWriter. */
+ public static void displayHelp(final PrintWriter writer) {
+ configureParser(new CompilationOptions()).usage(writer);
+ }
+
+ /** Prints version information to stderr.
+ * @see #displayVersion(PrintWriter)
+ * @since 2.5 */
public static void displayVersion() {
- String version = GroovySystem.getVersion();
- System.err.println("Groovy compiler version " + version);
- System.err.println("Copyright 2003-2018 The Apache Software Foundation. http://groovy-lang.org/");
- System.err.println("");
+ displayVersion(new PrintWriter(System.err, true));
+ }
+
+ /** Prints version information to the specified PrintWriter. */
+ public static void displayVersion(final PrintWriter writer) {
+ for (String line : new VersionProvider().getVersion()) {
+ writer.println(line);
+ }
}
public static int checkFiles(String[] filenames) {
@@ -125,32 +141,20 @@ public class FileSystemCompiler {
* the VM to exit and the lookup for .groovy files can be controlled
*/
public static void commandLineCompile(String[] args, boolean lookupUnnamedFiles) throws Exception {
- Options options = createCompilationOptions();
-
- CommandLineParser cliParser = new DefaultParser();
-
- CommandLine cli;
- cli = cliParser.parse(options, args);
-
- if (cli.hasOption('h')) {
- displayHelp(options);
+ CompilationOptions options = new CompilationOptions();
+ CommandLine parser = configureParser(options);
+ ParseResult parseResult = parser.parseArgs(args);
+ if (CommandLine.printHelpIfRequested(parseResult)) {
return;
}
-
- if (cli.hasOption('v')) {
- displayVersion();
- return;
- }
-
- displayStackTraceOnError = cli.hasOption('e');
-
- CompilerConfiguration configuration = generateCompilerConfigurationFromOptions(cli);
+ displayStackTraceOnError = options.printStack;
+ CompilerConfiguration configuration = options.toCompilerConfiguration();
// Load the file name list
- String[] filenames = generateFileNamesFromOptions(cli);
+ String[] filenames = options.generateFileNames();
boolean fileNameErrors = filenames == null;
if (!fileNameErrors && (filenames.length == 0)) {
- displayHelp(options);
+ parser.usage(System.err);
return;
}
@@ -161,6 +165,17 @@ public class FileSystemCompiler {
}
}
+ public static CommandLine configureParser(CompilationOptions options) {
+ CommandLine parser = new CommandLine(options);
+ parser.getCommandSpec().mixinStandardHelpOptions(true); // programmatically so these options appear last in usage help
+ parser.getCommandSpec().parser()
+ .unmatchedArgumentsAllowed(true)
+ .unmatchedOptionsArePositionalParams(true)
+ .expandAtFiles(false)
+ .toggleBooleanFlags(false);
+ return parser;
+ }
+
/**
* Primary entry point for compiling from the command line
* (using the groovyc script).
@@ -234,9 +249,11 @@ public class FileSystemCompiler {
}
}
- public static String[] generateFileNamesFromOptions(CommandLine cli) {
- String[] filenames = cli.getArgs();
- List<String> fileList = new ArrayList<String>(filenames.length);
+ private static String[] generateFileNamesFromOptions(List<String> filenames) {
+ if (filenames == null) {
+ return new String[0];
+ }
+ List<String> fileList = new ArrayList<String>(filenames.size());
boolean errors = false;
for (String filename : filenames) {
if (filename.startsWith("@")) {
@@ -271,94 +288,138 @@ public class FileSystemCompiler {
}
}
- public static CompilerConfiguration generateCompilerConfigurationFromOptions(CommandLine cli) throws IOException {
- // Setup the configuration data
- CompilerConfiguration configuration = new CompilerConfiguration();
-
- if (cli.hasOption("classpath")) {
- configuration.setClasspath(cli.getOptionValue("classpath"));
+ static class VersionProvider implements IVersionProvider {
+ @Override
+ public String[] getVersion() {
+ return new String[] {
+ "Groovy compiler version " + GroovySystem.getVersion(),
+ "Copyright 2003-2018 The Apache Software Foundation. http://groovy-lang.org/",
+ "",
+ };
}
+ }
- if (cli.hasOption('d')) {
- configuration.setTargetDirectory(cli.getOptionValue('d'));
- }
+ @Command(name = "groovyc",
+ customSynopsis = "groovyc [options] <source-files>",
+ sortOptions = false,
+ versionProvider = VersionProvider.class)
+ public static class CompilationOptions {
+ // 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 = "<path>", description = "Specify where to find the class files - must be first argument")
+ private String classpath;
- configuration.setParameters(cli.hasOption("pa"));
+ @Option(names = {"-sourcepath", "--sourcepath"}, paramLabel = "<path>", description = "Specify where to find the source files")
+ private File sourcepath;
- if (cli.hasOption("encoding")) {
- configuration.setSourceEncoding(cli.getOptionValue("encoding"));
- }
+ @Option(names = {"--temp"}, paramLabel = "<temp>", description = "Specify temporary directory")
+ private File temp;
- if (cli.hasOption("basescript")) {
- configuration.setScriptBaseClass(cli.getOptionValue("basescript"));
- }
+ @Option(names = {"--encoding"}, description = "Specify the encoding of the user class files")
+ private String encoding;
+
+ @Option(names = "-d", paramLabel = "<dir>", description = "Specify where to place generated class files")
+ private File targetDir;
- // joint compilation parameters
- if (cli.hasOption('j')) {
- Map<String, Object> compilerOptions = new HashMap<String, Object>();
+ @Option(names = {"-e", "--exception"}, description = "Print stack trace on error")
+ private boolean printStack;
- String[] namedValues = cli.getOptionValues("J");
- compilerOptions.put("namedValues", namedValues);
+ @Option(names = {"-pa", "--parameters"}, description = "Generate metadata for reflection on method parameter names (jdk8+ only)")
+ private boolean parameterMetadata;
- String[] flags = cli.getOptionValues("F");
- if (flags != null && cli.hasOption("pa")){
- flags = Arrays.copyOf(flags, flags.length + 1);
- flags[flags.length - 1] = "parameters";
+ @Option(names = {"-j", "--jointCompilation"}, description = "Attach javac compiler to compile .java files")
+ private boolean jointCompilation;
+
+ @Option(names = {"-b", "--basescript"}, paramLabel = "<class>", description = "Base class name for scripts (must derive from Script)")
+ private String scriptBaseClass;
+
+ @Option(names = "-J", paramLabel = "<property=value>", description = "Name-value pairs to pass to javac")
+ private Map<String, String> javacOptionsMap;
+
+ @Option(names = "-F", paramLabel = "<flag>", description = "Passed to javac for joint compilation")
+ private List<String> flags;
+
+ @Option(names = {"--indy"}, description = "Enables compilation using invokedynamic")
+ private boolean indy;
+
+ @Option(names = {"--configscript"}, paramLabel = "<script>", description = "A script for tweaking the configuration options")
+ private String configScript;
+
+ @Parameters(description = "The groovy source files to compile, or @-files containing a list of source files to compile",
+ paramLabel = "<source-files>")
+ private List<String> files;
+
+ public CompilerConfiguration toCompilerConfiguration() throws IOException {
+ // Setup the configuration data
+ CompilerConfiguration configuration = new CompilerConfiguration();
+
+ if (classpath != null) {
+ configuration.setClasspath(classpath);
+ }
+
+ if (targetDir != null && targetDir.getName().length() > 0) {
+ configuration.setTargetDirectory(targetDir);
+ }
+
+ configuration.setParameters(parameterMetadata);
+ configuration.setSourceEncoding(encoding);
+ configuration.setScriptBaseClass(scriptBaseClass);
+
+ // joint compilation parameters
+ if (jointCompilation) {
+ Map<String, Object> compilerOptions = new HashMap<String, Object>();
+ compilerOptions.put("namedValues", javacOptionsList());
+ compilerOptions.put("flags", flagsWithParameterMetaData());
+ configuration.setJointCompilationOptions(compilerOptions);
+ }
+
+ if (indy) {
+ configuration.getOptimizationOptions().put("int", false);
+ configuration.getOptimizationOptions().put("indy", true);
+ }
+
+ String configScripts = System.getProperty("groovy.starter.configscripts", null);
+ if (configScript != null || (configScripts != null && !configScripts.isEmpty())) {
+ List<String> scripts = new ArrayList<String>();
+ if (configScript != null) {
+ scripts.add(configScript);
+ }
+ if (configScripts != null) {
+ scripts.addAll(StringGroovyMethods.tokenize((CharSequence) configScripts, ','));
+ }
+ processConfigScripts(scripts, configuration);
}
- compilerOptions.put("flags", flags);
- configuration.setJointCompilationOptions(compilerOptions);
+ return configuration;
}
- if (cli.hasOption("indy")) {
- configuration.getOptimizationOptions().put("int", false);
- configuration.getOptimizationOptions().put("indy", true);
+ public String[] generateFileNames() {
+ return generateFileNamesFromOptions(files);
}
- String configScripts = System.getProperty("groovy.starter.configscripts", null);
- if (cli.hasOption("configscript") || (configScripts != null && !configScripts.isEmpty())) {
- List<String> scripts = new ArrayList<String>();
- if (cli.hasOption("configscript")) {
- scripts.add(cli.getOptionValue("configscript"));
+ String[] javacOptionsList() {
+ if (javacOptionsMap == null) {
+ return null;
}
- if (configScripts != null) {
- scripts.addAll(StringGroovyMethods.tokenize((CharSequence) configScripts, ','));
+ List<String> result = new ArrayList<String>();
+ for (Map.Entry<String, String> entry : javacOptionsMap.entrySet()) {
+ result.add(entry.getKey());
+ result.add(entry.getValue());
}
- processConfigScripts(scripts, configuration);
+ return result.toArray(new String[0]);
}
- return configuration;
- }
-
- @SuppressWarnings({"AccessStaticViaInstance"})
- public static Options createCompilationOptions() {
- Options options = new Options();
- options.addOption(Option.builder("classpath").hasArg().argName("path").desc("Specify where to find the class files - must be first argument").build());
- options.addOption(Option.builder("cp").longOpt("classpath").hasArg().argName("path").desc("Aliases for '-classpath'").build());
- options.addOption(Option.builder().longOpt("sourcepath").hasArg().argName("path").desc("Specify where to find the source files").build());
- options.addOption(Option.builder().longOpt("temp").hasArg().argName("temp").desc("Specify temporary directory").build());
- options.addOption(Option.builder().longOpt("encoding").hasArg().argName("encoding").desc("Specify the encoding of the user class files").build());
- options.addOption(Option.builder("d").hasArg().desc("Specify where to place generated class files").build());
- options.addOption(Option.builder("h").longOpt("help").desc("Print a synopsis of standard options").build());
- options.addOption(Option.builder("v").longOpt("version").desc("Print the version").build());
- options.addOption(Option.builder("e").longOpt("exception").desc("Print stack trace on error").build());
- options.addOption(Option.builder("pa").longOpt("parameters").desc("Generate metadata for reflection on method parameter names (jdk8+ only)").build());
- options.addOption(Option.builder("j").longOpt("jointCompilation").desc("Attach javac compiler to compile .java files").build());
- options.addOption(Option.builder("b").longOpt("basescript").hasArg().argName("class").desc("Base class name for scripts (must derive from Script)").build());
- options.addOption(
- Option.builder("J").argName("property=value")
- .valueSeparator()
- .numberOfArgs(2)
- .desc("Name-value pairs to pass to javac")
- .build());
- options.addOption(
- Option.builder("F").argName("flag")
- .hasArg()
- .desc("Passed to javac for joint compilation")
- .build());
- options.addOption(Option.builder().longOpt("indy").desc("Enables compilation using invokedynamic").build());
- options.addOption(Option.builder().longOpt("configscript").hasArg().desc("A script for tweaking the configuration options").build());
- return options;
+ String[] flagsWithParameterMetaData() {
+ if (flags == null) {
+ return null;
+ }
+ if (parameterMetadata) {
+ flags.add("parameters");
+ }
+ return flags.toArray(new String[0]);
+ }
}
/**
http://git-wip-us.apache.org/repos/asf/groovy/blob/0ac97171/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
----------------------------------------------------------------------
diff --git a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
index eae75e3..7a60ac8 100644
--- a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
+++ b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
@@ -20,10 +20,6 @@ package org.codehaus.groovy.ant;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyResourceLoader;
-import org.apache.commons.cli.CommandLine;
-import org.apache.commons.cli.CommandLineParser;
-import org.apache.commons.cli.DefaultParser;
-import org.apache.commons.cli.Options;
import org.apache.groovy.io.StringBuilderWriter;
import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
@@ -45,6 +41,7 @@ import org.codehaus.groovy.tools.ErrorReporter;
import org.codehaus.groovy.tools.FileSystemCompiler;
import org.codehaus.groovy.tools.RootLoader;
import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit;
+import picocli.CommandLine;
import java.io.File;
import java.io.FileWriter;
@@ -1182,14 +1179,10 @@ public class Groovyc extends MatchingTask {
private void runCompiler(String[] commandLine) {
// hand crank it so we can add our own compiler configuration
try {
- Options options = FileSystemCompiler.createCompilationOptions();
-
- CommandLineParser cliParser = new DefaultParser();
-
- CommandLine cli;
- cli = cliParser.parse(options, commandLine);
-
- configuration = FileSystemCompiler.generateCompilerConfigurationFromOptions(cli);
+ FileSystemCompiler.CompilationOptions options = new FileSystemCompiler.CompilationOptions();
+ CommandLine parser = FileSystemCompiler.configureParser(options);
+ parser.parseArgs(commandLine);
+ configuration = options.toCompilerConfiguration();
configuration.setScriptExtensions(getScriptExtensions());
String tmpExtension = getScriptExtension();
if (tmpExtension.startsWith("*."))
@@ -1197,7 +1190,7 @@ public class Groovyc extends MatchingTask {
configuration.setDefaultScriptExtension(tmpExtension);
// Load the file name list
- String[] filenames = FileSystemCompiler.generateFileNamesFromOptions(cli);
+ String[] filenames = options.generateFileNames();
boolean fileNameErrors = filenames == null;
fileNameErrors = fileNameErrors || !FileSystemCompiler.validateFiles(filenames);