Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
1e75c0a5
Commit
1e75c0a5
authored
Jan 04, 2014
by
Dave Syer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Extend programming model for script commands
parent
b5db4d3f
Changes
16
Hide whitespace changes
Inline
Side-by-side
Showing
16 changed files
with
468 additions
and
257 deletions
+468
-257
SpringCli.java
...src/main/java/org/springframework/boot/cli/SpringCli.java
+8
-1
InitCommand.java
...ava/org/springframework/boot/cli/command/InitCommand.java
+27
-2
ScriptCommand.java
...a/org/springframework/boot/cli/command/ScriptCommand.java
+46
-199
ScriptCompilationCustomizer.java
...amework/boot/cli/command/ScriptCompilationCustomizer.java
+91
-29
ShellCommand.java
...va/org/springframework/boot/cli/command/ShellCommand.java
+1
-1
ScriptCompilationCustomizerTests.java
...st/java/cli/command/ScriptCompilationCustomizerTests.java
+131
-0
InitCommandTests.java
...rg/springframework/boot/cli/command/InitCommandTests.java
+7
-1
ScriptCommandTests.java
.../springframework/boot/cli/command/ScriptCommandTests.java
+79
-0
command.groovy
spring-boot-cli/src/test/resources/command.groovy
+19
-0
command.groovy
spring-boot-cli/src/test/resources/commands/command.groovy
+6
-1
handler.groovy
spring-boot-cli/src/test/resources/commands/handler.groovy
+3
-3
options.groovy
spring-boot-cli/src/test/resources/commands/options.groovy
+3
-4
init.groovy
spring-boot-cli/src/test/resources/init.groovy
+1
-1
command.groovy
spring-boot-cli/src/test/resources/scripts/command.groovy
+21
-9
handler.groovy
spring-boot-cli/src/test/resources/scripts/handler.groovy
+20
-5
options.groovy
spring-boot-cli/src/test/resources/scripts/options.groovy
+5
-1
No files found.
spring-boot-cli/src/main/java/org/springframework/boot/cli/SpringCli.java
View file @
1e75c0a5
...
...
@@ -52,12 +52,15 @@ public class SpringCli {
private
String
displayName
=
CLI_APP
+
" "
;
private
InitCommand
init
;
/**
* Create a new {@link SpringCli} implementation with the default set of commands.
*/
public
SpringCli
()
{
try
{
new
InitCommand
(
this
).
run
();
this
.
init
=
new
InitCommand
(
this
);
this
.
init
.
run
();
}
catch
(
Exception
e
)
{
throw
new
IllegalStateException
(
"Cannot init with those args"
,
e
);
...
...
@@ -66,6 +69,10 @@ public class SpringCli {
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
* 'help' command will be automatically provided in addition to this list.
...
...
spring-boot-cli/src/main/java/org/springframework/boot/cli/command/InitCommand.java
View file @
1e75c0a5
...
...
@@ -16,11 +16,13 @@
package
org
.
springframework
.
boot
.
cli
.
command
;
import
groovy.lang.Closure
;
import
groovy.lang.GroovyClassLoader
;
import
groovy.lang.Script
;
import
java.io.File
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.ServiceLoader
;
import
joptsimple.OptionSet
;
...
...
@@ -87,6 +89,8 @@ 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
);
...
...
@@ -102,7 +106,25 @@ public class InitCommand extends OptionParsingCommand {
if
(
this
.
compiler
!=
null
&&
files
.
length
>
0
)
{
Class
<?>[]
classes
=
this
.
compiler
.
compile
(
files
);
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
();
}
}
...
...
@@ -121,7 +143,6 @@ public class InitCommand extends OptionParsingCommand {
}
}
}
private
static
class
InitGroovyCompilerConfigurationAdapter
extends
...
...
@@ -138,4 +159,8 @@ public class InitCommand extends OptionParsingCommand {
}
}
public
static
interface
Commands
{
Map
<
String
,
Closure
<?>>
getCommands
();
}
}
spring-boot-cli/src/main/java/org/springframework/boot/cli/command/ScriptCommand.java
View file @
1e75c0a5
...
...
@@ -17,30 +17,13 @@
package
org
.
springframework
.
boot
.
cli
.
command
;
import
groovy.lang.Closure
;
import
groovy.lang.GroovyObjectSupport
;
import
groovy.lang.MetaClass
;
import
groovy.lang.MetaMethod
;
import
groovy.lang.Script
;
import
groovy.lang.GroovyObject
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.net.URL
;
import
java.util.Collection
;
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.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.
...
...
@@ -49,27 +32,28 @@ import org.springframework.util.FileCopyUtils;
*/
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
String
n
ame
;
private
String
defaultN
ame
;
public
ScriptCommand
(
String
script
)
{
this
.
name
=
script
;
public
ScriptCommand
(
String
name
,
Object
main
)
{
this
.
main
=
main
;
this
.
defaultName
=
name
;
}
@Override
public
String
getName
()
{
if
(
getMain
()
instanceof
Command
)
{
return
((
Command
)
getMain
()
).
getName
();
if
(
this
.
main
instanceof
Command
)
{
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
...
...
@@ -79,210 +63,73 @@ public class ScriptCommand implements Command {
@Override
public
String
getDescription
()
{
if
(
getMain
()
instanceof
Command
)
{
return
((
Command
)
getMain
()
).
getDescription
();
if
(
this
.
main
instanceof
Command
)
{
return
((
Command
)
this
.
main
).
getDescription
();
}
return
this
.
n
ame
;
return
this
.
defaultN
ame
;
}
@Override
public
String
getHelp
()
{
if
(
getMain
()
instanceof
OptionHandler
)
{
return
((
OptionHandler
)
getMain
()
).
getHelp
();
if
(
this
.
main
instanceof
OptionHandler
)
{
return
((
OptionHandler
)
this
.
main
).
getHelp
();
}
if
(
getMain
()
instanceof
Command
)
{
return
((
Command
)
getMain
()
).
getHelp
();
if
(
this
.
main
instanceof
Command
)
{
return
((
Command
)
this
.
main
).
getHelp
();
}
return
null
;
}
@Override
public
Collection
<
OptionHelp
>
getOptionsHelp
()
{
if
(
getMain
()
instanceof
OptionHandler
)
{
return
((
OptionHandler
)
getMain
()
).
getOptionsHelp
();
if
(
this
.
main
instanceof
OptionHandler
)
{
return
((
OptionHandler
)
this
.
main
).
getOptionsHelp
();
}
if
(
getMain
()
instanceof
Command
)
{
return
((
Command
)
getMain
()
).
getOptionsHelp
();
if
(
this
.
main
instanceof
Command
)
{
return
((
Command
)
this
.
main
).
getOptionsHelp
();
}
return
Collections
.
emptyList
();
}
@Override
public
void
run
(
String
...
args
)
throws
Exception
{
run
(
getMain
(),
args
);
}
private
void
run
(
Object
main
,
String
[]
args
)
throws
Exception
{
if
(
main
instanceof
Command
)
{
((
Command
)
main
).
run
(
args
);
}
else
if
(
main
instanceof
OptionHandler
)
{
((
OptionHandler
)
getMain
()).
run
(
args
);
if
(
this
.
main
instanceof
Command
)
{
((
Command
)
this
.
main
).
run
(
args
);
}
else
if
(
main
instanceof
Closure
)
{
((
Closure
<?>)
main
).
call
((
Object
[])
args
);
else
if
(
this
.
main
instanceof
OptionHandler
)
{
((
OptionHandler
)
this
.
main
).
run
(
args
);
}
else
if
(
main
instanceof
Runnabl
e
)
{
((
Runnable
)
main
).
run
(
);
else
if
(
this
.
main
instanceof
Closur
e
)
{
((
Closure
<?>)
this
.
main
).
call
((
Object
[])
args
);
}
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
public
String
getUsageHelp
()
{
if
(
getMain
()
instanceof
Command
)
{
return
((
Command
)
getMain
()
).
getDescription
();
if
(
this
.
main
instanceof
Command
)
{
return
((
Command
)
this
.
main
).
getDescription
();
}
return
"[options] <args>"
;
}
protected
Object
getMain
()
{
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
;
}
public
static
ScriptCommand
command
(
Class
<?>
type
)
{
private
void
compile
()
{
GroovyCompiler
compiler
=
new
GroovyCompiler
(
new
ScriptConfiguration
());
compiler
.
addCompilationCustomizers
(
new
ScriptCompilationCustomizer
());
File
source
=
locateSource
(
this
.
name
);
Class
<?>[]
classes
;
Object
main
=
null
;
try
{
classes
=
compiler
.
compile
(
source
);
}
catch
(
CompilationFailedException
ex
)
{
throw
new
IllegalStateException
(
"Could not compile script"
,
ex
);
main
=
type
.
newInstance
();
}
catch
(
IOException
ex
)
{
throw
new
IllegalStateException
(
"Could not compile script"
,
ex
);
catch
(
Exception
ex
)
{
// Inner classes and closures will not be instantiatable
return
null
;
}
this
.
mainClass
=
classes
[
0
];
}
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
;
if
(
main
instanceof
Command
)
{
return
new
ScriptCommand
(
type
.
getSimpleName
(),
main
);
}
@Override
public
List
<
RepositoryConfiguration
>
getRepositoryConfiguration
()
{
return
RepositoryConfigurationFactory
.
createDefaultRepositoryConfiguration
();
else
if
(
main
instanceof
OptionHandler
)
{
((
OptionHandler
)
main
).
options
();
return
new
ScriptCommand
(
type
.
getSimpleName
(),
main
);
}
return
null
;
}
...
...
spring-boot-cli/src/main/java/org/springframework/boot/cli/command/ScriptCompilationCustomizer.java
View file @
1e75c0a5
...
...
@@ -16,8 +16,7 @@
package
org
.
springframework
.
boot
.
cli
.
command
;
import
groovy.lang.Mixin
;
import
java.lang.reflect.Modifier
;
import
java.util.ArrayList
;
import
java.util.List
;
...
...
@@ -25,15 +24,17 @@ import joptsimple.OptionParser;
import
joptsimple.OptionSet
;
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.ClassNode
;
import
org.codehaus.groovy.ast.MethodNode
;
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.ClassExpression
;
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.MapExpression
;
import
org.codehaus.groovy.ast.expr.MethodCallExpression
;
import
org.codehaus.groovy.ast.stmt.BlockStatement
;
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.springframework.asm.Opcodes
;
import
org.springframework.boot.cli.Command
;
import
org.springframework.boot.cli.command.InitCommand.Commands
;
/**
* Customizer for the compilation of CLI commands.
...
...
@@ -61,11 +63,80 @@ public class ScriptCompilationCustomizer extends CompilationCustomizer {
@Override
public
void
call
(
SourceUnit
source
,
GeneratorContext
context
,
ClassNode
classNode
)
throws
CompilationFailedException
{
addOptionHandlerMixin
(
classNode
);
findCommands
(
source
,
classNode
);
overrideOptionsMethod
(
source
,
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
* import {@link OptionParser}, {@link OptionSet}, {@link Command} or
...
...
@@ -104,6 +175,18 @@ public class ScriptCompilationCustomizer extends CompilationCustomizer {
*/
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
();
List
<
Statement
>
statements
=
block
.
getStatements
();
...
...
@@ -114,43 +197,22 @@ public class ScriptCompilationCustomizer extends CompilationCustomizer {
if
(
expression
instanceof
MethodCallExpression
)
{
MethodCallExpression
method
=
(
MethodCallExpression
)
expression
;
if
(
method
.
getMethod
().
getText
().
equals
(
"options"
))
{
statements
.
remove
(
statement
);
expression
=
method
.
getArguments
();
if
(
expression
instanceof
ArgumentListExpression
)
{
ArgumentListExpression
arguments
=
(
ArgumentListExpression
)
expression
;
expression
=
arguments
.
getExpression
(
0
);
if
(
expression
instanceof
ClosureExpression
)
{
ClosureExpression
closure
=
(
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
(
ClosureExpression
)
expression
;
}
}
}
}
}
}
}
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
);
}
}
}
spring-boot-cli/src/main/java/org/springframework/boot/cli/command/ShellCommand.java
View file @
1e75c0a5
...
...
@@ -99,7 +99,7 @@ public class ShellCommand extends AbstractCommand {
PromptCommand
prompt
=
new
PromptCommand
(
this
);
cli
.
register
(
prompt
);
cli
.
register
(
new
InitCommand
(
cli
));
cli
.
register
(
cli
.
getInitCommand
(
));
}
private
ConsoleReader
createConsoleReader
()
throws
IOException
{
...
...
spring-boot-cli/src/test/java/cli/command/ScriptCompilationCustomizerTests.java
0 → 100644
View file @
1e75c0a5
/*
* 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
();
}
}
}
spring-boot-cli/src/test/java/org/springframework/boot/cli/command/InitCommandTests.java
View file @
1e75c0a5
...
...
@@ -69,6 +69,12 @@ public class InitCommandTests {
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
)
public
void
initNonExistentScript
()
throws
Exception
{
this
.
command
.
run
(
"nonexistent.groovy"
);
...
...
@@ -78,7 +84,7 @@ public class InitCommandTests {
@Test
public
void
initDefault
()
throws
Exception
{
this
.
command
.
run
();
assertTrue
(
this
.
output
.
toString
().
contains
(
"Hello
World
"
));
assertTrue
(
this
.
output
.
toString
().
contains
(
"Hello
Init
"
));
}
}
spring-boot-cli/src/test/
resources/commands/test.groovy
→
spring-boot-cli/src/test/
java/org/springframework/boot/cli/command/ScriptCommandTests.java
View file @
1e75c0a5
...
...
@@ -14,10 +14,66 @@
* limitations under the License.
*/
options
{
option
"foo"
,
"Foo set"
option
"bar"
,
"Bar has an argument of type int"
withOptionalArg
()
ofType
Integer
}
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
;
org
.
springframework
.
boot
.
cli
.
command
.
ScriptCommandTests
.
executed
=
true
println
"Hello ${options.nonOptionArguments()}: ${options.has('foo')} ${options.valueOf('bar')}"
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
);
}
}
spring-boot-cli/src/test/resources/command.groovy
0 → 100644
View file @
1e75c0a5
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]}"
}
}
\ No newline at end of file
spring-boot-cli/src/test/resources/commands/command.groovy
View file @
1e75c0a5
...
...
@@ -16,6 +16,8 @@
package
org.test.command
import
java.util.Collection
;
class
TestCommand
implements
Command
{
String
name
=
"foo"
...
...
@@ -25,9 +27,12 @@ class TestCommand implements Command {
String
help
=
"No options"
String
usageHelp
=
"Not very useful"
Collection
<
String
>
optionsHelp
=
[
"No options"
]
boolean
optionCommand
=
false
void
run
(
String
...
args
)
{
org
.
springframework
.
boot
.
cli
.
command
.
ScriptCommandTests
.
executed
=
true
println
"Hello ${args[0]}"
}
...
...
spring-boot-cli/src/test/resources/commands/handler.groovy
View file @
1e75c0a5
...
...
@@ -16,13 +16,13 @@
package
org.test.command
import
joptsimple.OptionSet
@Grab
(
"org.eclipse.jgit:org.eclipse.jgit:2.3.1.201302201838-r"
)
import
org.eclipse.jgit.api.Git
class
TestCommand
extends
OptionHandler
{
String
name
=
"foo"
void
options
()
{
option
"foo"
,
"Foo set"
...
...
@@ -30,7 +30,7 @@ class TestCommand extends OptionHandler {
void
run
(
OptionSet
options
)
{
// 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
println
"Hello ${options.nonOptionArguments()}: ${options.has('foo')}"
}
...
...
spring-boot-cli/src/test/resources/commands/
closure
.groovy
→
spring-boot-cli/src/test/resources/commands/
options
.groovy
View file @
1e75c0a5
...
...
@@ -14,9 +14,8 @@
* limitations under the License.
*/
def
run
=
{
msg
->
command
(
"foo"
)
{
args
->
org
.
springframework
.
boot
.
cli
.
command
.
ScriptCommandTests
.
executed
=
true
println
"Hello ${
msg
}"
println
"Hello ${
options.nonOptionArguments()}: ${options.has('foo')} ${options.valueOf('bar')
}"
}
run
spring-boot-cli/src/test/resources/init.groovy
View file @
1e75c0a5
println
"Hello World"
\ No newline at end of file
println
"Hello Init"
\ No newline at end of file
spring-boot-cli/src/test/resources/
commands/runnable
.groovy
→
spring-boot-cli/src/test/resources/
scripts/command
.groovy
View file @
1e75c0a5
...
...
@@ -14,14 +14,26 @@
* limitations under the License.
*/
class
TestCommand
implements
Runnable
{
def
msg
TestCommand
(
String
msg
)
{
this
.
msg
=
msg
}
void
run
()
{
org
.
springframework
.
boot
.
cli
.
command
.
ScriptCommandTests
.
executed
=
true
println
"Hello ${msg}"
package
org.test.command
import
java.util.Collection
;
class
TestCommand
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]}"
}
}
new
TestCommand
(
args
[
0
])
spring-boot-cli/src/test/resources/
commands/mixin
.groovy
→
spring-boot-cli/src/test/resources/
scripts/handler
.groovy
View file @
1e75c0a5
...
...
@@ -14,9 +14,24 @@
* limitations under the License.
*/
void
options
()
{
option
"foo"
,
"Foo set"
}
package
org.test.command
@Grab
(
"org.eclipse.jgit:org.eclipse.jgit:2.3.1.201302201838-r"
)
import
org.eclipse.jgit.api.Git
class
TestCommand
extends
OptionHandler
{
String
name
=
"foo"
org
.
springframework
.
boot
.
cli
.
command
.
ScriptCommandTests
.
executed
=
true
println
"Hello ${options.nonOptionArguments()}: ${options.has('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')}"
}
}
spring-boot-cli/src/test/resources/
commands/script
.groovy
→
spring-boot-cli/src/test/resources/
scripts/options
.groovy
View file @
1e75c0a5
...
...
@@ -14,4 +14,8 @@
* limitations under the License.
*/
println
"Hello ${args[0]}"
command
(
"foo"
)
{
args
->
println
"Hello Command"
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment