Browse Source
InitCommand runs on creation of SpringCli so it can search for additional Commands in updated classpath. Also added as interactive command in Shell session.pull/192/head
18 changed files with 347 additions and 78 deletions
@ -0,0 +1,141 @@
@@ -0,0 +1,141 @@
|
||||
/* |
||||
* 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.GroovyClassLoader; |
||||
import groovy.lang.Script; |
||||
|
||||
import java.io.File; |
||||
import java.util.List; |
||||
import java.util.ServiceLoader; |
||||
|
||||
import joptsimple.OptionSet; |
||||
|
||||
import org.springframework.boot.cli.Command; |
||||
import org.springframework.boot.cli.CommandFactory; |
||||
import org.springframework.boot.cli.SpringCli; |
||||
import org.springframework.boot.cli.compiler.GroovyCompiler; |
||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfiguration; |
||||
import org.springframework.boot.cli.compiler.GroovyCompilerConfigurationAdapter; |
||||
import org.springframework.boot.cli.compiler.GroovyCompilerScope; |
||||
import org.springframework.boot.cli.compiler.RepositoryConfigurationFactory; |
||||
import org.springframework.boot.cli.compiler.grape.RepositoryConfiguration; |
||||
|
||||
/** |
||||
* <p> |
||||
* Command to initialize the Spring CLI with commands from the classpath. If the current |
||||
* context class loader is a GroovyClassLoader then it can be enhanced by passing in |
||||
* compiler options (e.g. <code>--classpath=...</code>). |
||||
* </p> |
||||
* <p> |
||||
* If the current context class loader is not already GroovyClassLoader then one will be |
||||
* created and will replace the current context loader. In this case command arguments can |
||||
* include files to compile that have <code>@Grab</code> annotations to process. By |
||||
* default a script called "init.groovy" or "spring.groovy" is used if it exists in the |
||||
* current directory or the root of the classpath. |
||||
* </p> |
||||
* |
||||
* @author Dave Syer |
||||
*/ |
||||
public class InitCommand extends OptionParsingCommand { |
||||
|
||||
public static final String NAME = "init"; |
||||
|
||||
public InitCommand(SpringCli cli) { |
||||
super(NAME, "(Re)-initialize the Spring cli", new InitOptionHandler(cli)); |
||||
} |
||||
|
||||
private static class InitOptionHandler extends CompilerOptionHandler { |
||||
|
||||
private SpringCli cli; |
||||
private GroovyCompiler compiler; |
||||
|
||||
public InitOptionHandler(SpringCli cli) { |
||||
this.cli = cli; |
||||
} |
||||
|
||||
@Override |
||||
protected void run(OptionSet options) throws Exception { |
||||
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader(); |
||||
boolean enhanced = false; |
||||
|
||||
FileOptions fileOptions = new FileOptions(options, loader, "init.groovy", |
||||
"spring.groovy"); |
||||
File[] files = fileOptions.getFilesArray(); |
||||
|
||||
if (!(loader instanceof GroovyClassLoader)) { |
||||
|
||||
List<RepositoryConfiguration> repositoryConfiguration = RepositoryConfigurationFactory |
||||
.createDefaultRepositoryConfiguration(); |
||||
|
||||
GroovyCompilerConfiguration configuration = new InitGroovyCompilerConfigurationAdapter( |
||||
options, this, repositoryConfiguration); |
||||
|
||||
this.compiler = new GroovyCompiler(configuration); |
||||
loader = this.compiler.getLoader(); |
||||
Thread.currentThread().setContextClassLoader(loader); |
||||
|
||||
} |
||||
else { |
||||
String classpath = getClasspathOption().value(options); |
||||
if (classpath != null && classpath.length() > 0) { |
||||
((GroovyClassLoader) loader).addClasspath(classpath); |
||||
enhanced = true; |
||||
} |
||||
} |
||||
|
||||
if (this.compiler != null && files.length > 0) { |
||||
Class<?>[] classes = this.compiler.compile(files); |
||||
for (Class<?> type : classes) { |
||||
if (Script.class.isAssignableFrom(type)) { |
||||
((Script) type.newInstance()).run(); |
||||
} |
||||
} |
||||
enhanced = true; |
||||
} |
||||
|
||||
if (this.cli.getCommands().isEmpty() || enhanced) { |
||||
|
||||
for (CommandFactory factory : ServiceLoader.load(CommandFactory.class, |
||||
loader)) { |
||||
for (Command command : factory.getCommands(this.cli)) { |
||||
this.cli.register(command); |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
private static class InitGroovyCompilerConfigurationAdapter extends |
||||
GroovyCompilerConfigurationAdapter { |
||||
private InitGroovyCompilerConfigurationAdapter(OptionSet optionSet, |
||||
CompilerOptionHandler compilerOptionHandler, |
||||
List<RepositoryConfiguration> repositoryConfiguration) { |
||||
super(optionSet, compilerOptionHandler, repositoryConfiguration); |
||||
} |
||||
|
||||
@Override |
||||
public GroovyCompilerScope getScope() { |
||||
return GroovyCompilerScope.EXTENSION; |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
/* |
||||
* 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 org.springframework.boot.cli.command.AbstractCommand; |
||||
|
||||
/** |
||||
* @author Dave Syer |
||||
*/ |
||||
public class CustomCommand extends AbstractCommand { |
||||
|
||||
public CustomCommand() { |
||||
super("custom", "Custom command added in tests"); |
||||
} |
||||
|
||||
@Override |
||||
public void run(String... args) throws Exception { |
||||
System.err.println("Custom Command Hello"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,36 @@
@@ -0,0 +1,36 @@
|
||||
/* |
||||
* 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 java.util.Collection; |
||||
import java.util.Collections; |
||||
|
||||
import org.springframework.boot.cli.Command; |
||||
import org.springframework.boot.cli.CommandFactory; |
||||
import org.springframework.boot.cli.SpringCli; |
||||
|
||||
/** |
||||
* @author Dave Syer |
||||
*/ |
||||
public class CustomCommandFactory implements CommandFactory { |
||||
|
||||
@Override |
||||
public Collection<Command> getCommands(SpringCli cli) { |
||||
return Collections.<Command> singleton(new CustomCommand()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,84 @@
@@ -0,0 +1,84 @@
|
||||
/* |
||||
* 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.GroovyClassLoader; |
||||
|
||||
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.Command; |
||||
import org.springframework.boot.cli.SpringCli; |
||||
|
||||
import static org.junit.Assert.assertTrue; |
||||
import static org.mockito.Matchers.any; |
||||
import static org.mockito.Mockito.mock; |
||||
import static org.mockito.Mockito.times; |
||||
import static org.mockito.Mockito.verify; |
||||
|
||||
/** |
||||
* @author Dave Syer |
||||
*/ |
||||
public class InitCommandTests { |
||||
|
||||
@Rule |
||||
public OutputCapture output = new OutputCapture(); |
||||
|
||||
private SpringCli cli = mock(SpringCli.class); |
||||
private InitCommand command = new InitCommand(this.cli); |
||||
private int defaultCount = new DefaultCommandFactory().getCommands(this.cli).size(); |
||||
private ClassLoader classLoader; |
||||
|
||||
@Before |
||||
public void init() { |
||||
this.classLoader = Thread.currentThread().getContextClassLoader(); |
||||
} |
||||
|
||||
@After |
||||
public void close() { |
||||
Thread.currentThread().setContextClassLoader(this.classLoader); |
||||
} |
||||
|
||||
@Test |
||||
public void explicitClasspath() throws Exception { |
||||
Thread.currentThread().setContextClassLoader(new GroovyClassLoader()); |
||||
this.command.run("--cp=src/test/plugins/custom/custom/0.0.1/custom-0.0.1.jar"); |
||||
verify(this.cli, times(this.defaultCount + 1)).register(any(Command.class)); |
||||
} |
||||
|
||||
@Test |
||||
public void initScript() throws Exception { |
||||
this.command.run("src/test/resources/grab.groovy"); |
||||
verify(this.cli, times(this.defaultCount + 1)).register(any(Command.class)); |
||||
assertTrue(this.output.toString().contains("Hello Grab")); |
||||
} |
||||
|
||||
@Test(expected = IllegalArgumentException.class) |
||||
public void initNonExistentScript() throws Exception { |
||||
this.command.run("nonexistent.groovy"); |
||||
} |
||||
|
||||
// There is an init.groovy on the test classpath so this succeeds
|
||||
@Test |
||||
public void initDefault() throws Exception { |
||||
this.command.run(); |
||||
assertTrue(this.output.toString().contains("Hello World")); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1 @@
@@ -0,0 +1 @@
|
||||
cli.command.CustomCommandFactory |
||||
Binary file not shown.
@ -0,0 +1,6 @@
@@ -0,0 +1,6 @@
|
||||
@GrabResolver(name="test", root="file:./src/test/plugins") |
||||
@Grab("custom:custom:0.0.1") |
||||
@Controller |
||||
class Foo {} |
||||
|
||||
println "Hello Grab" |
||||
Loading…
Reference in new issue