mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Remove ScriptCommand support
InitCommand remains for now, so that you can @Grab a jar with custom commands if you so choose. Contributes to gh-212
This commit is contained in:
parent
c921c9410b
commit
a5f16d46fe
@ -16,12 +16,10 @@
|
||||
|
||||
package org.springframework.boot.cli.command;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.GroovyClassLoader;
|
||||
import groovy.lang.Script;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
|
||||
import joptsimple.OptionSet;
|
||||
@ -101,8 +99,6 @@ public class InitCommand extends OptionParsingCommand {
|
||||
options, this, repositoryConfiguration);
|
||||
|
||||
this.compiler = new GroovyCompiler(configuration);
|
||||
this.compiler
|
||||
.addCompilationCustomizers(new ScriptCompilationCustomizer());
|
||||
loader = this.compiler.getLoader();
|
||||
Thread.currentThread().setContextClassLoader(loader);
|
||||
|
||||
@ -118,37 +114,9 @@ public class InitCommand extends OptionParsingCommand {
|
||||
if (this.compiler != null && sources.length > 0) {
|
||||
Class<?>[] classes = this.compiler.compile(sources);
|
||||
for (Class<?> type : classes) {
|
||||
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)) {
|
||||
Commands instance = (Commands) type.newInstance();
|
||||
Map<String, Closure<?>> commands = instance.getCommands();
|
||||
Map<String, OptionHandler> handlers = instance.getOptions();
|
||||
for (String command : commands.keySet()) {
|
||||
if (handlers.containsKey(command)) {
|
||||
// An OptionHandler is available
|
||||
OptionHandler handler = handlers.get(command);
|
||||
handler.setClosure(commands.get(command));
|
||||
this.cli.register(new ScriptCommand(command, handler));
|
||||
}
|
||||
else {
|
||||
// Otherwise just a plain Closure
|
||||
this.cli.register(new ScriptCommand(command, commands
|
||||
.get(command)));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (Script.class.isAssignableFrom(type)) {
|
||||
((Script) type.newInstance()).run();
|
||||
if (Script.class.isAssignableFrom(type)) {
|
||||
Script script = (Script) type.newInstance();
|
||||
script.run();
|
||||
}
|
||||
}
|
||||
enhanced = true;
|
||||
@ -182,10 +150,4 @@ public class InitCommand extends OptionParsingCommand {
|
||||
}
|
||||
}
|
||||
|
||||
public static interface Commands {
|
||||
Map<String, Closure<?>> getCommands();
|
||||
|
||||
Map<String, OptionHandler> getOptions();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,136 +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.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cli.command;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
import groovy.lang.GroovyObject;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.boot.cli.Command;
|
||||
import org.springframework.boot.cli.OptionHelp;
|
||||
|
||||
/**
|
||||
* {@link Command} to run a Groovy script.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class ScriptCommand implements Command {
|
||||
|
||||
private Object main;
|
||||
|
||||
private String defaultName;
|
||||
|
||||
public ScriptCommand(String name, Object main) {
|
||||
this.main = main;
|
||||
this.defaultName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
if (this.main instanceof Command) {
|
||||
return ((Command) this.main).getName();
|
||||
}
|
||||
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
|
||||
public boolean isOptionCommand() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
if (this.main instanceof Command) {
|
||||
return ((Command) this.main).getDescription();
|
||||
}
|
||||
return this.defaultName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelp() {
|
||||
if (this.main instanceof OptionHandler) {
|
||||
return ((OptionHandler) this.main).getHelp();
|
||||
}
|
||||
if (this.main instanceof Command) {
|
||||
return ((Command) this.main).getHelp();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<OptionHelp> getOptionsHelp() {
|
||||
if (this.main instanceof OptionHandler) {
|
||||
return ((OptionHandler) this.main).getOptionsHelp();
|
||||
}
|
||||
if (this.main instanceof Command) {
|
||||
return ((Command) this.main).getOptionsHelp();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
if (this.main instanceof Command) {
|
||||
((Command) this.main).run(args);
|
||||
}
|
||||
else if (this.main instanceof OptionHandler) {
|
||||
((OptionHandler) this.main).run(args);
|
||||
}
|
||||
else if (this.main instanceof Closure) {
|
||||
((Closure<?>) this.main).call((Object[]) args);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsageHelp() {
|
||||
if (this.main instanceof Command) {
|
||||
return ((Command) this.main).getDescription();
|
||||
}
|
||||
return "[options] <args>";
|
||||
}
|
||||
|
||||
public static ScriptCommand command(Class<?> type) {
|
||||
|
||||
Object main = null;
|
||||
try {
|
||||
main = type.newInstance();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// Inner classes and closures will not be instantiatable
|
||||
return null;
|
||||
}
|
||||
if (main instanceof Command) {
|
||||
return new ScriptCommand(type.getSimpleName(), main);
|
||||
}
|
||||
else if (main instanceof OptionHandler) {
|
||||
((OptionHandler) main).options();
|
||||
return new ScriptCommand(type.getSimpleName(), main);
|
||||
}
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,298 +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.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cli.command;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import joptsimple.OptionParser;
|
||||
import joptsimple.OptionSet;
|
||||
import joptsimple.OptionSpecBuilder;
|
||||
|
||||
import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
|
||||
import org.codehaus.groovy.ast.ClassHelper;
|
||||
import org.codehaus.groovy.ast.ClassNode;
|
||||
import org.codehaus.groovy.ast.InnerClassNode;
|
||||
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.ClosureExpression;
|
||||
import org.codehaus.groovy.ast.expr.ConstantExpression;
|
||||
import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
|
||||
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.stmt.BlockStatement;
|
||||
import org.codehaus.groovy.ast.stmt.EmptyStatement;
|
||||
import org.codehaus.groovy.ast.stmt.ExpressionStatement;
|
||||
import org.codehaus.groovy.classgen.GeneratorContext;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
import org.codehaus.groovy.control.CompilePhase;
|
||||
import org.codehaus.groovy.control.SourceUnit;
|
||||
import org.codehaus.groovy.control.customizers.CompilationCustomizer;
|
||||
import org.codehaus.groovy.control.customizers.ImportCustomizer;
|
||||
import org.springframework.boot.cli.Command;
|
||||
import org.springframework.boot.cli.command.InitCommand.Commands;
|
||||
|
||||
/**
|
||||
* Customizer for the compilation of CLI script commands.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class ScriptCompilationCustomizer extends CompilationCustomizer {
|
||||
|
||||
public ScriptCompilationCustomizer() {
|
||||
super(CompilePhase.CONVERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void call(SourceUnit source, GeneratorContext context, ClassNode classNode)
|
||||
throws CompilationFailedException {
|
||||
findCommands(source, classNode);
|
||||
addImports(source, context, classNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the script defines a block in this form:
|
||||
*
|
||||
* <pre>
|
||||
* command("foo") { args ->
|
||||
* println "Command foo called with args: ${args}"
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* Then the block is taken and used to create a Command named "foo" that runs the
|
||||
* closure when it is executed.
|
||||
*
|
||||
* If you want to declare options (and provide help text), use this form:
|
||||
*
|
||||
* <pre>
|
||||
* command("foo") {
|
||||
*
|
||||
* options {
|
||||
* option "foo", "My Foo option"
|
||||
* option "bar", "Bar has a value" withOptionalArg() ofType Integer
|
||||
* }
|
||||
*
|
||||
* run { options ->
|
||||
* println "Command foo called with bar=${options.valueOf('bar')}"
|
||||
* }
|
||||
*
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* In this case the "options" block is taken and used to override the
|
||||
* {@link OptionHandler#options()} method. Each "option" is a call to
|
||||
* {@link OptionHandler#option(String, String)}, and hence returns an
|
||||
* {@link OptionSpecBuilder}. Makes a nice readable DSL for adding options.
|
||||
*
|
||||
* @param source the source node
|
||||
* @param classNode the class node to manipulate
|
||||
*/
|
||||
private void findCommands(SourceUnit source, ClassNode classNode) {
|
||||
CommandVisitor visitor = new CommandVisitor(source, classNode);
|
||||
classNode.visitContents(visitor);
|
||||
visitor.addFactory(classNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add imports to the class node to make writing simple commands easier. No need to
|
||||
* import {@link OptionParser}, {@link OptionSet}, {@link Command} or
|
||||
* {@link OptionHandler}.
|
||||
*
|
||||
* @param source the source node
|
||||
* @param context the current context
|
||||
* @param classNode the class node to manipulate
|
||||
*/
|
||||
private void addImports(SourceUnit source, GeneratorContext context,
|
||||
ClassNode classNode) {
|
||||
ImportCustomizer importCustomizer = new ImportCustomizer();
|
||||
importCustomizer.addImports("joptsimple.OptionParser", "joptsimple.OptionSet",
|
||||
OptionParsingCommand.class.getCanonicalName(),
|
||||
Command.class.getCanonicalName(), OptionHandler.class.getCanonicalName());
|
||||
importCustomizer.call(source, context, classNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to extract a Commands instance (adding that interface to the current class
|
||||
* node) so individual commands can be registered with the CLI.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
private static class CommandVisitor extends ClassCodeVisitorSupport {
|
||||
|
||||
private SourceUnit source;
|
||||
private MapExpression closures = new MapExpression();
|
||||
private MapExpression options = new MapExpression();
|
||||
private List<ExpressionStatement> statements = new ArrayList<ExpressionStatement>();
|
||||
private ExpressionStatement statement;
|
||||
private ClassNode classNode;
|
||||
|
||||
public CommandVisitor(SourceUnit source, ClassNode classNode) {
|
||||
this.source = source;
|
||||
this.classNode = classNode;
|
||||
}
|
||||
|
||||
private boolean hasCommands() {
|
||||
return !this.closures.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.closures, null, null));
|
||||
classNode.addProperty(new PropertyNode("options", Modifier.PUBLIC
|
||||
| Modifier.FINAL, ClassHelper.MAP_TYPE.getPlainNodeReference(),
|
||||
classNode, this.options, 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);
|
||||
Expression expression = arguments.getExpression(1);
|
||||
if (expression instanceof ClosureExpression) {
|
||||
ClosureExpression closure = (ClosureExpression) expression;
|
||||
ActionExtractorVisitor action = new ActionExtractorVisitor(
|
||||
this.source, this.classNode, name.getText());
|
||||
closure.getCode().visit(action);
|
||||
if (action.hasOptions()) {
|
||||
this.options.addMapEntryExpression(name, action.getOptions());
|
||||
expression = action.getAction();
|
||||
}
|
||||
else {
|
||||
expression = new ClosureExpression(
|
||||
new Parameter[] { new Parameter(
|
||||
ClassHelper.make(String[].class), "args") },
|
||||
closure.getCode());
|
||||
}
|
||||
this.closures.addMapEntryExpression(name, expression);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to pull out options and action closures from a command declaration (if they
|
||||
* are there).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
private static class ActionExtractorVisitor extends ClassCodeVisitorSupport {
|
||||
|
||||
private static final Parameter[] OPTIONS_PARAMETERS = new Parameter[] { new Parameter(
|
||||
ClassHelper.make(OptionSet.class), "options") };
|
||||
private SourceUnit source;
|
||||
private ClassNode classNode;
|
||||
private Expression options;
|
||||
private ClosureExpression action;
|
||||
private String name;
|
||||
|
||||
public ActionExtractorVisitor(SourceUnit source, ClassNode classNode, String name) {
|
||||
this.source = source;
|
||||
this.classNode = classNode;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SourceUnit getSourceUnit() {
|
||||
return this.source;
|
||||
}
|
||||
|
||||
public boolean hasOptions() {
|
||||
return this.options != null;
|
||||
}
|
||||
|
||||
public Expression getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
public ClosureExpression getAction() {
|
||||
return this.action != null ? this.action : new ClosureExpression(
|
||||
OPTIONS_PARAMETERS, new EmptyStatement());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodCallExpression(MethodCallExpression call) {
|
||||
Expression methodCall = call.getMethod();
|
||||
if (methodCall instanceof ConstantExpression) {
|
||||
ConstantExpression method = (ConstantExpression) methodCall;
|
||||
if ("options".equals(method.getValue())) {
|
||||
ArgumentListExpression arguments = (ArgumentListExpression) call
|
||||
.getArguments();
|
||||
Expression expression = arguments.getExpression(0);
|
||||
if (expression instanceof ClosureExpression) {
|
||||
ClosureExpression closure = (ClosureExpression) expression;
|
||||
InnerClassNode type = new InnerClassNode(this.classNode,
|
||||
this.classNode.getName() + "$" + this.name
|
||||
+ "OptionHandler", Modifier.PUBLIC,
|
||||
ClassHelper.make(OptionHandler.class));
|
||||
type.addMethod("options", Modifier.PROTECTED,
|
||||
ClassHelper.VOID_TYPE, Parameter.EMPTY_ARRAY,
|
||||
ClassNode.EMPTY_ARRAY, closure.getCode());
|
||||
this.classNode.getModule().addClass(type);
|
||||
this.options = new ConstructorCallExpression(type,
|
||||
ArgumentListExpression.EMPTY_ARGUMENTS);
|
||||
}
|
||||
}
|
||||
else if ("run".equals(method.getValue())) {
|
||||
ArgumentListExpression arguments = (ArgumentListExpression) call
|
||||
.getArguments();
|
||||
Expression expression = arguments.getExpression(0);
|
||||
if (expression instanceof ClosureExpression) {
|
||||
ClosureExpression closure = (ClosureExpression) expression;
|
||||
this.action = new ClosureExpression(OPTIONS_PARAMETERS,
|
||||
closure.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -72,39 +72,6 @@ public class InitCommandTests {
|
||||
assertTrue(this.output.toString().contains("Hello Grab"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initCommand() throws Exception {
|
||||
this.command.run("src/test/resources/commands/command.groovy");
|
||||
verify(this.cli, times(this.defaultCount + 1)).register(any(Command.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initHandler() throws Exception {
|
||||
this.command.run("src/test/resources/commands/handler.groovy");
|
||||
verify(this.cli, times(this.defaultCount + 1)).register(any(Command.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initClosure() throws Exception {
|
||||
this.command.run("src/test/resources/commands/closure.groovy");
|
||||
verify(this.cli, times(this.defaultCount + 1)).register(any(Command.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void initOptions() throws Exception {
|
||||
this.command.run("src/test/resources/commands/options.groovy");
|
||||
verify(this.cli, times(this.defaultCount + 1)).register(any(Command.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runOptions() throws Exception {
|
||||
SpringCli cli = new SpringCli();
|
||||
InitCommand command = new InitCommand(cli);
|
||||
command.run("src/test/resources/commands/options.groovy");
|
||||
cli.find("foo").run("--foo=bar", "--bar=123");
|
||||
assertTrue(this.output.toString().contains("Hello Foo: bar=123"));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void initNonExistentScript() throws Exception {
|
||||
this.command.run("nonexistent.groovy");
|
||||
|
@ -1,77 +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.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cli.command;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
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 = new InitCommand(this.cli);
|
||||
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(this.output.toString().contains("Hello [Foo]"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void options() throws Exception {
|
||||
this.init.run("src/test/resources/commands/options.groovy");
|
||||
this.cli.find("foo").run("Foo", "--foo=bar");
|
||||
assertTrue(this.output.toString().contains("Hello Foo"));
|
||||
}
|
||||
|
||||
}
|
@ -1,156 +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.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.cli.command;
|
||||
|
||||
import groovy.lang.Closure;
|
||||
|
||||
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.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 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("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("classpath:/scripts/handler.groovy");
|
||||
Class<?> main = types[0];
|
||||
assertTrue(OptionHandler.class.isAssignableFrom(main));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addsCommands() throws Exception {
|
||||
Class<?>[] types = this.compiler.compile("classpath:scripts/commands.groovy");
|
||||
Class<?> main = types[0];
|
||||
assertTrue(Commands.class.isAssignableFrom(main));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void closureWithStringArgs() throws Exception {
|
||||
Class<?>[] types = this.compiler.compile("classpath:scripts/commands.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("foo", "bar");
|
||||
assertTrue(this.output.toString().contains("Hello Command"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void closureWithEmptyArgs() throws Exception {
|
||||
Class<?>[] types = this.compiler
|
||||
.compile("src/test/resources/scripts/commands.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();
|
||||
assertTrue(this.output.toString().contains("Hello Command"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void closureAndOptionsDefined() throws Exception {
|
||||
Class<?>[] types = this.compiler
|
||||
.compile("src/test/resources/scripts/options.groovy");
|
||||
Class<?> main = types[0];
|
||||
Commands commands = (Commands) main.newInstance();
|
||||
Map<String, Closure<?>> closures = commands.getCommands();
|
||||
assertEquals(1, closures.size());
|
||||
assertEquals("foo", closures.keySet().iterator().next());
|
||||
final Closure<?> closure = closures.values().iterator().next();
|
||||
Map<String, OptionHandler> options = commands.getOptions();
|
||||
assertEquals(1, options.size());
|
||||
OptionHandler handler = options.get("foo");
|
||||
handler.setClosure(closure);
|
||||
handler.run("--foo=bar", "--bar=blah", "spam");
|
||||
assertTrue(this.output.toString().contains("Hello [spam]: true blah"));
|
||||
}
|
||||
|
||||
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 RepositoryConfigurationFactory.createDefaultRepositoryConfiguration();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user