Extend programming model for script commands
This commit is contained in:
parent
b5db4d3ff4
commit
1e75c0a55b
|
|
@ -52,12 +52,15 @@ public class SpringCli {
|
||||||
|
|
||||||
private String displayName = CLI_APP + " ";
|
private String displayName = CLI_APP + " ";
|
||||||
|
|
||||||
|
private InitCommand init;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link SpringCli} implementation with the default set of commands.
|
* Create a new {@link SpringCli} implementation with the default set of commands.
|
||||||
*/
|
*/
|
||||||
public SpringCli() {
|
public SpringCli() {
|
||||||
try {
|
try {
|
||||||
new InitCommand(this).run();
|
this.init = new InitCommand(this);
|
||||||
|
this.init.run();
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
throw new IllegalStateException("Cannot init with those args", e);
|
throw new IllegalStateException("Cannot init with those args", e);
|
||||||
|
|
@ -66,6 +69,10 @@ public class SpringCli {
|
||||||
this.commands.add(new HintCommand());
|
this.commands.add(new HintCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public InitCommand getInitCommand() {
|
||||||
|
return this.init;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the command available to the CLI. Primarily used to support testing. NOTE: The
|
* Set the command available to the CLI. Primarily used to support testing. NOTE: The
|
||||||
* 'help' command will be automatically provided in addition to this list.
|
* 'help' command will be automatically provided in addition to this list.
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,13 @@
|
||||||
|
|
||||||
package org.springframework.boot.cli.command;
|
package org.springframework.boot.cli.command;
|
||||||
|
|
||||||
|
import groovy.lang.Closure;
|
||||||
import groovy.lang.GroovyClassLoader;
|
import groovy.lang.GroovyClassLoader;
|
||||||
import groovy.lang.Script;
|
import groovy.lang.Script;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
import joptsimple.OptionSet;
|
import joptsimple.OptionSet;
|
||||||
|
|
@ -87,6 +89,8 @@ public class InitCommand extends OptionParsingCommand {
|
||||||
options, this, repositoryConfiguration);
|
options, this, repositoryConfiguration);
|
||||||
|
|
||||||
this.compiler = new GroovyCompiler(configuration);
|
this.compiler = new GroovyCompiler(configuration);
|
||||||
|
this.compiler
|
||||||
|
.addCompilationCustomizers(new ScriptCompilationCustomizer());
|
||||||
loader = this.compiler.getLoader();
|
loader = this.compiler.getLoader();
|
||||||
Thread.currentThread().setContextClassLoader(loader);
|
Thread.currentThread().setContextClassLoader(loader);
|
||||||
|
|
||||||
|
|
@ -102,7 +106,25 @@ public class InitCommand extends OptionParsingCommand {
|
||||||
if (this.compiler != null && files.length > 0) {
|
if (this.compiler != null && files.length > 0) {
|
||||||
Class<?>[] classes = this.compiler.compile(files);
|
Class<?>[] classes = this.compiler.compile(files);
|
||||||
for (Class<?> type : classes) {
|
for (Class<?> type : classes) {
|
||||||
if (Script.class.isAssignableFrom(type)) {
|
Command script = ScriptCommand.command(type);
|
||||||
|
if (script != null) {
|
||||||
|
this.cli.register(script);
|
||||||
|
}
|
||||||
|
else if (CommandFactory.class.isAssignableFrom(type)) {
|
||||||
|
for (Command command : ((CommandFactory) type.newInstance())
|
||||||
|
.getCommands(this.cli)) {
|
||||||
|
this.cli.register(command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Commands.class.isAssignableFrom(type)) {
|
||||||
|
Map<String, Closure<?>> commands = ((Commands) type.newInstance())
|
||||||
|
.getCommands();
|
||||||
|
for (String command : commands.keySet()) {
|
||||||
|
this.cli.register(new ScriptCommand(command, commands
|
||||||
|
.get(command)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (Script.class.isAssignableFrom(type)) {
|
||||||
((Script) type.newInstance()).run();
|
((Script) type.newInstance()).run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -121,7 +143,6 @@ public class InitCommand extends OptionParsingCommand {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class InitGroovyCompilerConfigurationAdapter extends
|
private static class InitGroovyCompilerConfigurationAdapter extends
|
||||||
|
|
@ -138,4 +159,8 @@ public class InitCommand extends OptionParsingCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static interface Commands {
|
||||||
|
Map<String, Closure<?>> getCommands();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,30 +17,13 @@
|
||||||
package org.springframework.boot.cli.command;
|
package org.springframework.boot.cli.command;
|
||||||
|
|
||||||
import groovy.lang.Closure;
|
import groovy.lang.Closure;
|
||||||
import groovy.lang.GroovyObjectSupport;
|
import groovy.lang.GroovyObject;
|
||||||
import groovy.lang.MetaClass;
|
|
||||||
import groovy.lang.MetaMethod;
|
|
||||||
import groovy.lang.Script;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import joptsimple.OptionParser;
|
|
||||||
|
|
||||||
import org.codehaus.groovy.control.CompilationFailedException;
|
|
||||||
import org.springframework.boot.cli.Command;
|
import org.springframework.boot.cli.Command;
|
||||||
import org.springframework.boot.cli.OptionHelp;
|
import org.springframework.boot.cli.OptionHelp;
|
||||||
import org.springframework.boot.cli.compiler.GroovyCompiler;
|
|
||||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
|
||||||
import org.springframework.boot.cli.compiler.GroovyCompilerScope;
|
|
||||||
import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory;
|
|
||||||
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
|
||||||
import org.springframework.util.FileCopyUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link Command} to run a Groovy script.
|
* {@link Command} to run a Groovy script.
|
||||||
|
|
@ -49,27 +32,28 @@ import org.springframework.util.FileCopyUtils;
|
||||||
*/
|
*/
|
||||||
public class ScriptCommand implements Command {
|
public class ScriptCommand implements Command {
|
||||||
|
|
||||||
private static final String[] DEFAULT_PATHS = new String[] { "${SPRING_HOME}/ext",
|
|
||||||
"${SPRING_HOME}/bin" };
|
|
||||||
|
|
||||||
private String[] paths = DEFAULT_PATHS;
|
|
||||||
|
|
||||||
private Class<?> mainClass;
|
|
||||||
|
|
||||||
private Object main;
|
private Object main;
|
||||||
|
|
||||||
private String name;
|
private String defaultName;
|
||||||
|
|
||||||
public ScriptCommand(String script) {
|
public ScriptCommand(String name, Object main) {
|
||||||
this.name = script;
|
this.main = main;
|
||||||
|
this.defaultName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
if (getMain() instanceof Command) {
|
if (this.main instanceof Command) {
|
||||||
return ((Command) getMain()).getName();
|
return ((Command) this.main).getName();
|
||||||
}
|
}
|
||||||
return this.name;
|
else if (this.main instanceof GroovyObject) {
|
||||||
|
GroovyObject object = (GroovyObject) this.main;
|
||||||
|
if (object.getMetaClass().hasProperty(object, "name") != null) {
|
||||||
|
return (String) object.getProperty("name");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.defaultName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -79,210 +63,73 @@ public class ScriptCommand implements Command {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
if (getMain() instanceof Command) {
|
if (this.main instanceof Command) {
|
||||||
return ((Command) getMain()).getDescription();
|
return ((Command) this.main).getDescription();
|
||||||
}
|
}
|
||||||
return this.name;
|
return this.defaultName;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getHelp() {
|
public String getHelp() {
|
||||||
if (getMain() instanceof OptionHandler) {
|
if (this.main instanceof OptionHandler) {
|
||||||
return ((OptionHandler) getMain()).getHelp();
|
return ((OptionHandler) this.main).getHelp();
|
||||||
}
|
}
|
||||||
if (getMain() instanceof Command) {
|
if (this.main instanceof Command) {
|
||||||
return ((Command) getMain()).getHelp();
|
return ((Command) this.main).getHelp();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<OptionHelp> getOptionsHelp() {
|
public Collection<OptionHelp> getOptionsHelp() {
|
||||||
if (getMain() instanceof OptionHandler) {
|
if (this.main instanceof OptionHandler) {
|
||||||
return ((OptionHandler) getMain()).getOptionsHelp();
|
return ((OptionHandler) this.main).getOptionsHelp();
|
||||||
}
|
}
|
||||||
if (getMain() instanceof Command) {
|
if (this.main instanceof Command) {
|
||||||
return ((Command) getMain()).getOptionsHelp();
|
return ((Command) this.main).getOptionsHelp();
|
||||||
}
|
}
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(String... args) throws Exception {
|
public void run(String... args) throws Exception {
|
||||||
run(getMain(), args);
|
if (this.main instanceof Command) {
|
||||||
}
|
((Command) this.main).run(args);
|
||||||
|
|
||||||
private void run(Object main, String[] args) throws Exception {
|
|
||||||
if (main instanceof Command) {
|
|
||||||
((Command) main).run(args);
|
|
||||||
}
|
}
|
||||||
else if (main instanceof OptionHandler) {
|
else if (this.main instanceof OptionHandler) {
|
||||||
((OptionHandler) getMain()).run(args);
|
((OptionHandler) this.main).run(args);
|
||||||
}
|
}
|
||||||
else if (main instanceof Closure) {
|
else if (this.main instanceof Closure) {
|
||||||
((Closure<?>) main).call((Object[]) args);
|
((Closure<?>) this.main).call((Object[]) args);
|
||||||
}
|
}
|
||||||
else if (main instanceof Runnable) {
|
|
||||||
((Runnable) main).run();
|
|
||||||
}
|
|
||||||
else if (main instanceof Script) {
|
|
||||||
Script script = (Script) this.main;
|
|
||||||
script.setProperty("args", args);
|
|
||||||
if (this.main instanceof GroovyObjectSupport) {
|
|
||||||
GroovyObjectSupport object = (GroovyObjectSupport) this.main;
|
|
||||||
if (object.getMetaClass().hasProperty(object, "parser") != null) {
|
|
||||||
OptionParser parser = (OptionParser) object.getProperty("parser");
|
|
||||||
if (parser != null) {
|
|
||||||
script.setProperty("options", parser.parse(args));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Object result = script.run();
|
|
||||||
run(result, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Paths to search for script files.
|
|
||||||
*
|
|
||||||
* @param paths the paths to set
|
|
||||||
*/
|
|
||||||
public void setPaths(String[] paths) {
|
|
||||||
this.paths = (paths == null ? null : paths.clone());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUsageHelp() {
|
public String getUsageHelp() {
|
||||||
if (getMain() instanceof Command) {
|
if (this.main instanceof Command) {
|
||||||
return ((Command) getMain()).getDescription();
|
return ((Command) this.main).getDescription();
|
||||||
}
|
}
|
||||||
return "[options] <args>";
|
return "[options] <args>";
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Object getMain() {
|
public static ScriptCommand command(Class<?> type) {
|
||||||
if (this.main == null) {
|
|
||||||
try {
|
|
||||||
this.main = getMainClass().newInstance();
|
|
||||||
}
|
|
||||||
catch (Exception ex) {
|
|
||||||
throw new IllegalStateException("Cannot create main class: " + this.name,
|
|
||||||
ex);
|
|
||||||
}
|
|
||||||
if (this.main instanceof OptionHandler) {
|
|
||||||
((OptionHandler) this.main).options();
|
|
||||||
}
|
|
||||||
else if (this.main instanceof GroovyObjectSupport) {
|
|
||||||
GroovyObjectSupport object = (GroovyObjectSupport) this.main;
|
|
||||||
MetaClass metaClass = object.getMetaClass();
|
|
||||||
MetaMethod options = metaClass.getMetaMethod("options", null);
|
|
||||||
if (options != null) {
|
|
||||||
options.doMethodInvoke(this.main, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return this.main;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void compile() {
|
Object main = null;
|
||||||
GroovyCompiler compiler = new GroovyCompiler(new ScriptConfiguration());
|
|
||||||
compiler.addCompilationCustomizers(new ScriptCompilationCustomizer());
|
|
||||||
File source = locateSource(this.name);
|
|
||||||
Class<?>[] classes;
|
|
||||||
try {
|
try {
|
||||||
classes = compiler.compile(source);
|
main = type.newInstance();
|
||||||
}
|
}
|
||||||
catch (CompilationFailedException ex) {
|
catch (Exception ex) {
|
||||||
throw new IllegalStateException("Could not compile script", ex);
|
// Inner classes and closures will not be instantiatable
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
if (main instanceof Command) {
|
||||||
throw new IllegalStateException("Could not compile script", ex);
|
return new ScriptCommand(type.getSimpleName(), main);
|
||||||
}
|
}
|
||||||
this.mainClass = classes[0];
|
else if (main instanceof OptionHandler) {
|
||||||
}
|
((OptionHandler) main).options();
|
||||||
|
return new ScriptCommand(type.getSimpleName(), main);
|
||||||
private Class<?> getMainClass() {
|
|
||||||
if (this.mainClass == null) {
|
|
||||||
compile();
|
|
||||||
}
|
|
||||||
return this.mainClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
private File locateSource(String name) {
|
|
||||||
String resource = name;
|
|
||||||
if (!name.endsWith(".groovy")) {
|
|
||||||
resource = "commands/" + name + ".groovy";
|
|
||||||
}
|
|
||||||
|
|
||||||
URL url = getClass().getClassLoader().getResource(resource);
|
|
||||||
if (url != null) {
|
|
||||||
return locateSourceFromUrl(name, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
String home = System.getProperty("SPRING_HOME", System.getenv("SPRING_HOME"));
|
|
||||||
if (home == null) {
|
|
||||||
home = ".";
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String path : this.paths) {
|
|
||||||
String subbed = path.replace("${SPRING_HOME}", home);
|
|
||||||
File file = new File(subbed, resource);
|
|
||||||
if (file.exists()) {
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalStateException("No script found for : " + name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private File locateSourceFromUrl(String name, URL url) {
|
|
||||||
if (url.toString().startsWith("file:")) {
|
|
||||||
return new File(url.toString().substring("file:".length()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// probably in JAR file
|
|
||||||
try {
|
|
||||||
File file = File.createTempFile(name, ".groovy");
|
|
||||||
file.deleteOnExit();
|
|
||||||
FileCopyUtils.copy(url.openStream(), new FileOutputStream(file));
|
|
||||||
return file;
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
throw new IllegalStateException("Could not create temp file for source: "
|
|
||||||
+ name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ScriptConfiguration implements GroovyCompilerConfiguration {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GroovyCompilerScope getScope() {
|
|
||||||
return GroovyCompilerScope.EXTENSION;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isGuessImports() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAutoconfigure() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isGuessDependencies() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getClasspath() {
|
|
||||||
return DEFAULT_CLASSPATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<RepositoryConfiguration> getRepositoryConfiguration() {
|
|
||||||
return RepositoryConfigurationFactory.createDefaultRepositoryConfiguration();
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.boot.cli.command;
|
package org.springframework.boot.cli.command;
|
||||||
|
|
||||||
import groovy.lang.Mixin;
|
import java.lang.reflect.Modifier;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
@ -25,15 +24,17 @@ import joptsimple.OptionParser;
|
||||||
import joptsimple.OptionSet;
|
import joptsimple.OptionSet;
|
||||||
import joptsimple.OptionSpecBuilder;
|
import joptsimple.OptionSpecBuilder;
|
||||||
|
|
||||||
import org.codehaus.groovy.ast.AnnotationNode;
|
import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
|
||||||
import org.codehaus.groovy.ast.ClassHelper;
|
import org.codehaus.groovy.ast.ClassHelper;
|
||||||
import org.codehaus.groovy.ast.ClassNode;
|
import org.codehaus.groovy.ast.ClassNode;
|
||||||
import org.codehaus.groovy.ast.MethodNode;
|
import org.codehaus.groovy.ast.MethodNode;
|
||||||
import org.codehaus.groovy.ast.Parameter;
|
import org.codehaus.groovy.ast.Parameter;
|
||||||
|
import org.codehaus.groovy.ast.PropertyNode;
|
||||||
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
|
import org.codehaus.groovy.ast.expr.ArgumentListExpression;
|
||||||
import org.codehaus.groovy.ast.expr.ClassExpression;
|
|
||||||
import org.codehaus.groovy.ast.expr.ClosureExpression;
|
import org.codehaus.groovy.ast.expr.ClosureExpression;
|
||||||
|
import org.codehaus.groovy.ast.expr.ConstantExpression;
|
||||||
import org.codehaus.groovy.ast.expr.Expression;
|
import org.codehaus.groovy.ast.expr.Expression;
|
||||||
|
import org.codehaus.groovy.ast.expr.MapExpression;
|
||||||
import org.codehaus.groovy.ast.expr.MethodCallExpression;
|
import org.codehaus.groovy.ast.expr.MethodCallExpression;
|
||||||
import org.codehaus.groovy.ast.stmt.BlockStatement;
|
import org.codehaus.groovy.ast.stmt.BlockStatement;
|
||||||
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
|
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
|
||||||
|
|
@ -46,6 +47,7 @@ import org.codehaus.groovy.control.customizers.CompilationCustomizer;
|
||||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||||
import org.springframework.asm.Opcodes;
|
import org.springframework.asm.Opcodes;
|
||||||
import org.springframework.boot.cli.Command;
|
import org.springframework.boot.cli.Command;
|
||||||
|
import org.springframework.boot.cli.command.InitCommand.Commands;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Customizer for the compilation of CLI commands.
|
* Customizer for the compilation of CLI commands.
|
||||||
|
|
@ -61,11 +63,80 @@ public class ScriptCompilationCustomizer extends CompilationCustomizer {
|
||||||
@Override
|
@Override
|
||||||
public void call(SourceUnit source, GeneratorContext context, ClassNode classNode)
|
public void call(SourceUnit source, GeneratorContext context, ClassNode classNode)
|
||||||
throws CompilationFailedException {
|
throws CompilationFailedException {
|
||||||
addOptionHandlerMixin(classNode);
|
findCommands(source, classNode);
|
||||||
overrideOptionsMethod(source, classNode);
|
overrideOptionsMethod(source, classNode);
|
||||||
addImports(source, context, classNode);
|
addImports(source, context, classNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void findCommands(SourceUnit source, ClassNode classNode) {
|
||||||
|
CommandVisitor visitor = new CommandVisitor(source);
|
||||||
|
classNode.visitContents(visitor);
|
||||||
|
visitor.addFactory(classNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CommandVisitor extends ClassCodeVisitorSupport {
|
||||||
|
|
||||||
|
private SourceUnit source;
|
||||||
|
private MapExpression map = new MapExpression();
|
||||||
|
private List<ExpressionStatement> statements = new ArrayList<ExpressionStatement>();
|
||||||
|
private ExpressionStatement statement;
|
||||||
|
|
||||||
|
public CommandVisitor(SourceUnit source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasCommands() {
|
||||||
|
return !this.map.getMapEntryExpressions().isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addFactory(ClassNode classNode) {
|
||||||
|
if (!hasCommands()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
classNode.addInterface(ClassHelper.make(Commands.class));
|
||||||
|
classNode.addProperty(new PropertyNode("commands", Modifier.PUBLIC
|
||||||
|
| Modifier.FINAL, ClassHelper.MAP_TYPE.getPlainNodeReference(),
|
||||||
|
classNode, this.map, null, null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected SourceUnit getSourceUnit() {
|
||||||
|
return this.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitBlockStatement(BlockStatement block) {
|
||||||
|
this.statements.clear();
|
||||||
|
super.visitBlockStatement(block);
|
||||||
|
block.getStatements().removeAll(this.statements);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitExpressionStatement(ExpressionStatement statement) {
|
||||||
|
this.statement = statement;
|
||||||
|
super.visitExpressionStatement(statement);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void visitMethodCallExpression(MethodCallExpression call) {
|
||||||
|
Expression methodCall = call.getMethod();
|
||||||
|
if (methodCall instanceof ConstantExpression) {
|
||||||
|
ConstantExpression method = (ConstantExpression) methodCall;
|
||||||
|
if ("command".equals(method.getValue())) {
|
||||||
|
ArgumentListExpression arguments = (ArgumentListExpression) call
|
||||||
|
.getArguments();
|
||||||
|
this.statements.add(this.statement);
|
||||||
|
ConstantExpression name = (ConstantExpression) arguments
|
||||||
|
.getExpression(0);
|
||||||
|
ClosureExpression closure = (ClosureExpression) arguments
|
||||||
|
.getExpression(1);
|
||||||
|
this.map.addMapEntryExpression(name, closure);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add imports to the class node to make writing simple commands easier. No need to
|
* Add imports to the class node to make writing simple commands easier. No need to
|
||||||
* import {@link OptionParser}, {@link OptionSet}, {@link Command} or
|
* import {@link OptionParser}, {@link OptionSet}, {@link Command} or
|
||||||
|
|
@ -104,6 +175,18 @@ public class ScriptCompilationCustomizer extends CompilationCustomizer {
|
||||||
*/
|
*/
|
||||||
private void overrideOptionsMethod(SourceUnit source, ClassNode classNode) {
|
private void overrideOptionsMethod(SourceUnit source, ClassNode classNode) {
|
||||||
|
|
||||||
|
ClosureExpression closure = options(source, classNode);
|
||||||
|
if (closure != null) {
|
||||||
|
classNode.addMethod(new MethodNode("options", Opcodes.ACC_PROTECTED,
|
||||||
|
ClassHelper.VOID_TYPE, new Parameter[0], new ClassNode[0], closure
|
||||||
|
.getCode()));
|
||||||
|
classNode.setSuperClass(ClassHelper.make(OptionHandler.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClosureExpression options(SourceUnit source, ClassNode classNode) {
|
||||||
|
|
||||||
BlockStatement block = source.getAST().getStatementBlock();
|
BlockStatement block = source.getAST().getStatementBlock();
|
||||||
List<Statement> statements = block.getStatements();
|
List<Statement> statements = block.getStatements();
|
||||||
|
|
||||||
|
|
@ -114,43 +197,22 @@ public class ScriptCompilationCustomizer extends CompilationCustomizer {
|
||||||
if (expression instanceof MethodCallExpression) {
|
if (expression instanceof MethodCallExpression) {
|
||||||
MethodCallExpression method = (MethodCallExpression) expression;
|
MethodCallExpression method = (MethodCallExpression) expression;
|
||||||
if (method.getMethod().getText().equals("options")) {
|
if (method.getMethod().getText().equals("options")) {
|
||||||
|
statements.remove(statement);
|
||||||
expression = method.getArguments();
|
expression = method.getArguments();
|
||||||
if (expression instanceof ArgumentListExpression) {
|
if (expression instanceof ArgumentListExpression) {
|
||||||
ArgumentListExpression arguments = (ArgumentListExpression) expression;
|
ArgumentListExpression arguments = (ArgumentListExpression) expression;
|
||||||
expression = arguments.getExpression(0);
|
expression = arguments.getExpression(0);
|
||||||
|
|
||||||
if (expression instanceof ClosureExpression) {
|
if (expression instanceof ClosureExpression) {
|
||||||
ClosureExpression closure = (ClosureExpression) expression;
|
return (ClosureExpression) expression;
|
||||||
classNode.addMethod(new MethodNode("options",
|
|
||||||
Opcodes.ACC_PROTECTED, ClassHelper.VOID_TYPE,
|
|
||||||
new Parameter[0], new ClassNode[0], closure
|
|
||||||
.getCode()));
|
|
||||||
statements.remove(statement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
return null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Add {@link OptionHandler} as a mixin to the class node if it doesn't already
|
|
||||||
* declare it as a super class.
|
|
||||||
*
|
|
||||||
* @param classNode the class node to manipulate
|
|
||||||
*/
|
|
||||||
private void addOptionHandlerMixin(ClassNode classNode) {
|
|
||||||
// If we are not an OptionHandler then add that class as a mixin
|
|
||||||
if (!classNode.isDerivedFrom(ClassHelper.make(OptionHandler.class))
|
|
||||||
&& !classNode.isDerivedFrom(ClassHelper.make("OptionHandler"))) {
|
|
||||||
AnnotationNode mixin = new AnnotationNode(ClassHelper.make(Mixin.class));
|
|
||||||
mixin.addMember("value",
|
|
||||||
new ClassExpression(ClassHelper.make(OptionHandler.class)));
|
|
||||||
classNode.addAnnotation(mixin);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ public class ShellCommand extends AbstractCommand {
|
||||||
|
|
||||||
PromptCommand prompt = new PromptCommand(this);
|
PromptCommand prompt = new PromptCommand(this);
|
||||||
cli.register(prompt);
|
cli.register(prompt);
|
||||||
cli.register(new InitCommand(cli));
|
cli.register(cli.getInitCommand());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ConsoleReader createConsoleReader() throws IOException {
|
private ConsoleReader createConsoleReader() throws IOException {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed 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 cli.command;
|
||||||
|
|
||||||
|
import groovy.lang.Closure;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.boot.OutputCapture;
|
||||||
|
import org.springframework.boot.cli.Command;
|
||||||
|
import org.springframework.boot.cli.command.InitCommand.Commands;
|
||||||
|
import org.springframework.boot.cli.command.OptionHandler;
|
||||||
|
import org.springframework.boot.cli.command.ScriptCompilationCustomizer;
|
||||||
|
import org.springframework.boot.cli.compiler.GroovyCompiler;
|
||||||
|
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration;
|
||||||
|
import org.springframework.boot.cli.compiler.GroovyCompilerScope;
|
||||||
|
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
public class ScriptCompilationCustomizerTests {
|
||||||
|
|
||||||
|
private TestGroovyCompilerConfiguration configuration = new TestGroovyCompilerConfiguration();
|
||||||
|
private GroovyCompiler compiler = new GroovyCompiler(this.configuration);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public OutputCapture output = new OutputCapture();
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
this.compiler.addCompilationCustomizers(new ScriptCompilationCustomizer());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void simpleCompile() throws Exception {
|
||||||
|
Class<?>[] types = this.compiler.compile(new File(
|
||||||
|
"src/test/resources/scripts/command.groovy"));
|
||||||
|
Class<?> main = types[0];
|
||||||
|
assertEquals("org.test.command.TestCommand", main.getName());
|
||||||
|
assertTrue(Command.class.isAssignableFrom(main));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addsOptionHandler() throws Exception {
|
||||||
|
Class<?>[] types = this.compiler.compile(new File(
|
||||||
|
"src/test/resources/scripts/handler.groovy"));
|
||||||
|
Class<?> main = types[0];
|
||||||
|
assertTrue(OptionHandler.class.isAssignableFrom(main));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addsCommands() throws Exception {
|
||||||
|
Class<?>[] types = this.compiler.compile(new File(
|
||||||
|
"src/test/resources/scripts/options.groovy"));
|
||||||
|
Class<?> main = types[0];
|
||||||
|
assertTrue(Commands.class.isAssignableFrom(main));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void commandsExecutable() throws Exception {
|
||||||
|
Class<?>[] types = this.compiler.compile(new File(
|
||||||
|
"src/test/resources/scripts/options.groovy"));
|
||||||
|
Class<?> main = types[0];
|
||||||
|
Map<String, Closure<?>> commands = ((Commands) main.newInstance()).getCommands();
|
||||||
|
assertEquals(1, commands.size());
|
||||||
|
assertEquals("foo", commands.keySet().iterator().next());
|
||||||
|
Closure<?> closure = commands.values().iterator().next();
|
||||||
|
closure.call(); // what about args?
|
||||||
|
assertTrue(this.output.toString().contains("Hello Command"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TestGroovyCompilerConfiguration implements
|
||||||
|
GroovyCompilerConfiguration {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GroovyCompilerScope getScope() {
|
||||||
|
return GroovyCompilerScope.EXTENSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGuessImports() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isGuessDependencies() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAutoconfigure() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getClasspath() {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RepositoryConfiguration> getRepositoryConfiguration() {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -69,6 +69,12 @@ public class InitCommandTests {
|
||||||
assertTrue(this.output.toString().contains("Hello Grab"));
|
assertTrue(this.output.toString().contains("Hello Grab"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void initCommand() throws Exception {
|
||||||
|
this.command.run("src/test/resources/command.groovy");
|
||||||
|
verify(this.cli, times(this.defaultCount + 1)).register(any(Command.class));
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class)
|
@Test(expected = IllegalArgumentException.class)
|
||||||
public void initNonExistentScript() throws Exception {
|
public void initNonExistentScript() throws Exception {
|
||||||
this.command.run("nonexistent.groovy");
|
this.command.run("nonexistent.groovy");
|
||||||
|
|
@ -78,7 +84,7 @@ public class InitCommandTests {
|
||||||
@Test
|
@Test
|
||||||
public void initDefault() throws Exception {
|
public void initDefault() throws Exception {
|
||||||
this.command.run();
|
this.command.run();
|
||||||
assertTrue(this.output.toString().contains("Hello World"));
|
assertTrue(this.output.toString().contains("Hello Init"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2013 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed 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 org.springframework.boot.cli.command;
|
||||||
|
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.boot.OutputCapture;
|
||||||
|
import org.springframework.boot.cli.SpringCli;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Dave Syer
|
||||||
|
*/
|
||||||
|
public class ScriptCommandTests {
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public OutputCapture output = new OutputCapture();
|
||||||
|
|
||||||
|
public static boolean executed = false;
|
||||||
|
|
||||||
|
private SpringCli cli;
|
||||||
|
private InitCommand init;
|
||||||
|
|
||||||
|
private ClassLoader classLoader;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
this.classLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
this.cli = new SpringCli();
|
||||||
|
this.init = this.cli.getInitCommand();
|
||||||
|
executed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void close() {
|
||||||
|
Thread.currentThread().setContextClassLoader(this.classLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void command() throws Exception {
|
||||||
|
this.init.run("src/test/resources/commands/command.groovy");
|
||||||
|
this.cli.find("foo").run("Foo");
|
||||||
|
assertTrue(this.output.toString().contains("Hello Foo"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void handler() throws Exception {
|
||||||
|
this.init.run("src/test/resources/commands/handler.groovy");
|
||||||
|
this.cli.find("foo").run("Foo", "--foo=bar");
|
||||||
|
assertTrue(executed);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore
|
||||||
|
public void options() throws Exception {
|
||||||
|
this.init.run("src/test/resources/commands/options.groovy");
|
||||||
|
this.cli.find("foo").run("Foo", "--foo=bar");
|
||||||
|
assertTrue(executed);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
class MyCommand implements Command {
|
||||||
|
|
||||||
|
String name = "foo"
|
||||||
|
|
||||||
|
String description = "My script command"
|
||||||
|
|
||||||
|
String help = "No options"
|
||||||
|
|
||||||
|
String usageHelp = "Not very useful"
|
||||||
|
|
||||||
|
Collection<String> optionsHelp = ["No options"]
|
||||||
|
|
||||||
|
boolean optionCommand = false
|
||||||
|
|
||||||
|
void run(String... args) {
|
||||||
|
println "Hello ${args[0]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -16,6 +16,8 @@
|
||||||
|
|
||||||
package org.test.command
|
package org.test.command
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
class TestCommand implements Command {
|
class TestCommand implements Command {
|
||||||
|
|
||||||
String name = "foo"
|
String name = "foo"
|
||||||
|
|
@ -25,9 +27,12 @@ class TestCommand implements Command {
|
||||||
String help = "No options"
|
String help = "No options"
|
||||||
|
|
||||||
String usageHelp = "Not very useful"
|
String usageHelp = "Not very useful"
|
||||||
|
|
||||||
|
Collection<String> optionsHelp = ["No options"]
|
||||||
|
|
||||||
|
boolean optionCommand = false
|
||||||
|
|
||||||
void run(String... args) {
|
void run(String... args) {
|
||||||
org.springframework.boot.cli.command.ScriptCommandTests.executed = true
|
|
||||||
println "Hello ${args[0]}"
|
println "Hello ${args[0]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@
|
||||||
|
|
||||||
package org.test.command
|
package org.test.command
|
||||||
|
|
||||||
import joptsimple.OptionSet
|
|
||||||
|
|
||||||
@Grab("org.eclipse.jgit:org.eclipse.jgit:2.3.1.201302201838-r")
|
@Grab("org.eclipse.jgit:org.eclipse.jgit:2.3.1.201302201838-r")
|
||||||
import org.eclipse.jgit.api.Git
|
import org.eclipse.jgit.api.Git
|
||||||
|
|
||||||
|
|
||||||
class TestCommand extends OptionHandler {
|
class TestCommand extends OptionHandler {
|
||||||
|
|
||||||
|
String name = "foo"
|
||||||
|
|
||||||
void options() {
|
void options() {
|
||||||
option "foo", "Foo set"
|
option "foo", "Foo set"
|
||||||
|
|
@ -30,7 +30,7 @@ class TestCommand extends OptionHandler {
|
||||||
|
|
||||||
void run(OptionSet options) {
|
void run(OptionSet options) {
|
||||||
// Demonstrate use of Grape.grab to load dependencies before running
|
// Demonstrate use of Grape.grab to load dependencies before running
|
||||||
println "Clean : " + Git.open(".." as File).status().call().isClean()
|
println "Clean: " + Git.open(".." as File).status().call().isClean()
|
||||||
org.springframework.boot.cli.command.ScriptCommandTests.executed = true
|
org.springframework.boot.cli.command.ScriptCommandTests.executed = true
|
||||||
println "Hello ${options.nonOptionArguments()}: ${options.has('foo')}"
|
println "Hello ${options.nonOptionArguments()}: ${options.has('foo')}"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
def run = { msg ->
|
command("foo") { args ->
|
||||||
org.springframework.boot.cli.command.ScriptCommandTests.executed = true
|
|
||||||
println "Hello ${msg}"
|
|
||||||
}
|
|
||||||
|
|
||||||
run
|
org.springframework.boot.cli.command.ScriptCommandTests.executed = true
|
||||||
|
println "Hello ${options.nonOptionArguments()}: ${options.has('foo')} ${options.valueOf('bar')}"
|
||||||
|
}
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2012-2013 the original author or authors.
|
|
||||||
*
|
|
||||||
* Licensed 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
options {
|
|
||||||
option "foo", "Foo set"
|
|
||||||
option "bar", "Bar has an argument of type int" withOptionalArg() ofType Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
org.springframework.boot.cli.command.ScriptCommandTests.executed = true
|
|
||||||
println "Hello ${options.nonOptionArguments()}: ${options.has('foo')} ${options.valueOf('bar')}"
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
println "Hello World"
|
println "Hello Init"
|
||||||
|
|
@ -14,14 +14,26 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class TestCommand implements Runnable {
|
package org.test.command
|
||||||
def msg
|
|
||||||
TestCommand(String msg) {
|
import java.util.Collection;
|
||||||
this.msg = msg
|
|
||||||
}
|
class TestCommand implements Command {
|
||||||
void run() {
|
|
||||||
org.springframework.boot.cli.command.ScriptCommandTests.executed = true
|
String name = "foo"
|
||||||
println "Hello ${msg}"
|
|
||||||
|
String description = "My script command"
|
||||||
|
|
||||||
|
String help = "No options"
|
||||||
|
|
||||||
|
String usageHelp = "Not very useful"
|
||||||
|
|
||||||
|
Collection<String> optionsHelp = ["No options"]
|
||||||
|
|
||||||
|
boolean optionCommand = false
|
||||||
|
|
||||||
|
void run(String... args) {
|
||||||
|
println "Hello ${args[0]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
new TestCommand(args[0])
|
|
||||||
|
|
@ -14,9 +14,24 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void options() {
|
package org.test.command
|
||||||
option "foo", "Foo set"
|
|
||||||
}
|
|
||||||
|
|
||||||
org.springframework.boot.cli.command.ScriptCommandTests.executed = true
|
@Grab("org.eclipse.jgit:org.eclipse.jgit:2.3.1.201302201838-r")
|
||||||
println "Hello ${options.nonOptionArguments()}: ${options.has('foo')}"
|
import org.eclipse.jgit.api.Git
|
||||||
|
|
||||||
|
|
||||||
|
class TestCommand extends OptionHandler {
|
||||||
|
|
||||||
|
String name = "foo"
|
||||||
|
|
||||||
|
void options() {
|
||||||
|
option "foo", "Foo set"
|
||||||
|
}
|
||||||
|
|
||||||
|
void run(OptionSet options) {
|
||||||
|
// Demonstrate use of Grape.grab to load dependencies before running
|
||||||
|
println "Clean: " + Git.open(".." as File).status().call().isClean()
|
||||||
|
println "Hello ${options.nonOptionArguments()}: ${options.has('foo')}"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -14,4 +14,8 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
println "Hello ${args[0]}"
|
command("foo") { args ->
|
||||||
|
|
||||||
|
println "Hello Command"
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue