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
208bf8fc
Commit
208bf8fc
authored
Jan 30, 2014
by
Phillip Webb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Polish CLI Jar generation
parent
d6486036
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
275 additions
and
249 deletions
+275
-249
pom.xml
spring-boot-cli/pom.xml
+0
-6
JarCommandIT.java
...rc/it/java/org/springframework/boot/cli/JarCommandIT.java
+20
-16
JarCommand.java
.../org/springframework/boot/cli/command/jar/JarCommand.java
+108
-105
ResourceMatcher.java
...springframework/boot/cli/command/jar/ResourceMatcher.java
+64
-44
ForkProcessCommand.java
...gframework/boot/cli/command/shell/ForkProcessCommand.java
+2
-25
GroovyCompiler.java
...org/springframework/boot/cli/compiler/GroovyCompiler.java
+4
-45
PackagedSpringApplicationLauncher.java
...ework/boot/cli/jar/PackagedSpringApplicationLauncher.java
+3
-1
JavaExecutable.java
...ava/org/springframework/boot/cli/util/JavaExecutable.java
+66
-0
ResourceMatcherTests.java
...gframework/boot/cli/command/jar/ResourceMatcherTests.java
+8
-7
No files found.
spring-boot-cli/pom.xml
View file @
208bf8fc
...
...
@@ -103,12 +103,6 @@
<artifactId>
aether-util
</artifactId>
</dependency>
<!-- Provided -->
<dependency>
<groupId>
${project.groupId}
</groupId>
<artifactId>
spring-boot-loader
</artifactId>
<version>
${project.version}
</version>
<scope>
provided
</scope>
</dependency>
<dependency>
<groupId>
org.codehaus.groovy
</groupId>
<artifactId>
groovy-templates
</artifactId>
...
...
spring-boot-cli/src/it/java/org/springframework/boot/cli/JarCommandIT.java
View file @
208bf8fc
...
...
@@ -19,13 +19,20 @@ package org.springframework.boot.cli;
import
java.io.File
;
import
org.junit.Test
;
import
org.springframework.boot.cli.command.jar.JarCommand
;
import
org.springframework.boot.cli.infrastructure.CommandLineInvoker
;
import
org.springframework.boot.cli.infrastructure.CommandLineInvoker.Invocation
;
import
org.springframework.boot.cli.util.JavaExecutable
;
import
static
org
.
hamcrest
.
Matchers
.
containsString
;
import
static
org
.
hamcrest
.
Matchers
.
equalTo
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.
assertThat
;
import
static
org
.
junit
.
Assert
.
assertTrue
;
/**
* Integration test for {@link JarCommand}.
*
* @author Andy Wilkinson
*/
public
class
JarCommandIT
{
...
...
@@ -37,20 +44,18 @@ public class JarCommandIT {
public
void
noArguments
()
throws
Exception
{
Invocation
invocation
=
this
.
cli
.
invoke
(
"jar"
);
invocation
.
await
();
assertEquals
(
0
,
invocation
.
getStandardOutput
().
length
());
assertEquals
(
"The name of the resulting jar and at least one source file must be specified"
,
invocation
.
getErrorOutput
().
trim
());
assertThat
(
invocation
.
getStandardOutput
(),
equalTo
(
""
));
assertThat
(
invocation
.
getErrorOutput
(),
containsString
(
"The name of the "
+
"resulting jar and at least one source file must be specified"
));
}
@Test
public
void
noSources
()
throws
Exception
{
Invocation
invocation
=
this
.
cli
.
invoke
(
"jar"
,
"test-app.jar"
);
invocation
.
await
();
assertEquals
(
0
,
invocation
.
getStandardOutput
().
length
());
assertEquals
(
"The name of the resulting jar and at least one source file must be specified"
,
invocation
.
getErrorOutput
().
trim
());
assertThat
(
invocation
.
getStandardOutput
(),
equalTo
(
""
));
assertThat
(
invocation
.
getErrorOutput
(),
containsString
(
"The name of the "
+
"resulting jar and at least one source file must be specified"
));
}
@Test
...
...
@@ -62,14 +67,13 @@ public class JarCommandIT {
assertEquals
(
0
,
invocation
.
getErrorOutput
().
length
());
assertTrue
(
jar
.
exists
());
ProcessBuilder
builder
=
new
ProcessBuilder
(
System
.
getProperty
(
"java.home"
)
+
"/bin/java"
,
"-jar"
,
jar
.
getAbsolutePath
());
Process
process
=
builder
.
start
();
Invocation
appInvocation
=
new
Invocation
(
process
);
appInvocation
.
await
();
Process
process
=
new
JavaExecutable
().
processBuilder
(
"-jar"
,
jar
.
getAbsolutePath
()).
start
();
invocation
=
new
Invocation
(
process
);
invocation
.
await
();
assert
Equals
(
0
,
appInvocation
.
getErrorOutput
().
length
(
));
assertT
rue
(
appInvocation
.
getStandardOutput
().
contains
(
"Hello World!"
));
assertT
rue
(
appInvocation
.
getStandardOutput
().
contains
(
"/static/test.txt"
));
assert
That
(
invocation
.
getErrorOutput
(),
equalTo
(
""
));
assertT
hat
(
invocation
.
getStandardOutput
(),
containsString
(
"Hello World!"
));
assertT
hat
(
invocation
.
getStandardOutput
(),
containsString
(
"/static/test.txt"
));
}
}
spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/JarCommand.java
View file @
208bf8fc
This diff is collapsed.
Click to expand it.
spring-boot-cli/src/main/java/org/springframework/boot/cli/command/jar/ResourceMatcher.java
View file @
208bf8fc
...
...
@@ -28,6 +28,7 @@ import java.util.List;
import
org.springframework.core.io.DefaultResourceLoader
;
import
org.springframework.core.io.FileSystemResource
;
import
org.springframework.core.io.Resource
;
import
org.springframework.core.io.ResourceLoader
;
import
org.springframework.core.io.support.PathMatchingResourcePatternResolver
;
import
org.springframework.util.AntPathMatcher
;
...
...
@@ -36,7 +37,7 @@ import org.springframework.util.AntPathMatcher;
*
* @author Andy Wilkinson
*/
final
class
ResourceMatcher
{
class
ResourceMatcher
{
private
final
AntPathMatcher
pathMatcher
=
new
AntPathMatcher
();
...
...
@@ -49,110 +50,128 @@ final class ResourceMatcher {
this
.
excludes
=
excludes
;
}
List
<
MatchedResource
>
matchResources
(
List
<
File
>
roots
)
throws
IOException
{
public
List
<
MatchedResource
>
find
(
List
<
File
>
roots
)
throws
IOException
{
List
<
MatchedResource
>
matchedResources
=
new
ArrayList
<
MatchedResource
>();
for
(
File
root
:
roots
)
{
if
(
root
.
isFile
())
{
matchedResources
.
add
(
new
MatchedResource
(
root
));
}
else
{
matchedResources
.
addAll
(
matchResources
(
root
));
matchedResources
.
addAll
(
findInFolder
(
root
));
}
}
return
matchedResources
;
}
private
List
<
MatchedResource
>
matchResources
(
File
root
)
throws
IOException
{
List
<
MatchedResource
>
r
esources
=
new
ArrayList
<
MatchedResource
>();
private
List
<
MatchedResource
>
findInFolder
(
File
folder
)
throws
IOException
{
List
<
MatchedResource
>
matchedR
esources
=
new
ArrayList
<
MatchedResource
>();
PathMatchingResourcePatternResolver
resolver
=
new
PathMatchingResourcePatternResolver
(
new
ResourceCollectionResourceLoader
(
root
));
new
FolderResourceLoader
(
folder
));
for
(
String
include
:
this
.
includes
)
{
Resource
[]
candidates
=
resolver
.
getResources
(
include
);
for
(
Resource
candidate
:
candidates
)
{
for
(
Resource
candidate
:
resolver
.
getResources
(
include
))
{
File
file
=
candidate
.
getFile
();
if
(
file
.
isFile
())
{
MatchedResource
matchedResource
=
new
MatchedResource
(
root
,
file
);
MatchedResource
matchedResource
=
new
MatchedResource
(
folder
,
file
);
if
(!
isExcluded
(
matchedResource
))
{
r
esources
.
add
(
matchedResource
);
matchedR
esources
.
add
(
matchedResource
);
}
}
}
}
return
r
esources
;
return
matchedR
esources
;
}
private
boolean
isExcluded
(
MatchedResource
matchedResource
)
{
for
(
String
exclude
:
this
.
excludes
)
{
if
(
this
.
pathMatcher
.
match
(
exclude
,
matchedResource
.
get
Path
()))
{
if
(
this
.
pathMatcher
.
match
(
exclude
,
matchedResource
.
get
Name
()))
{
return
true
;
}
}
return
false
;
}
private
static
final
class
ResourceCollectionResourceLoader
extends
DefaultResourceLoader
{
private
final
File
root
;
/**
* {@link ResourceLoader} to get load resource from a folder.
*/
private
static
class
FolderResourceLoader
extends
DefaultResourceLoader
{
ResourceCollectionResourceLoader
(
File
root
)
throws
MalformedURLException
{
super
(
new
URLClassLoader
(
new
URL
[]
{
root
.
toURI
().
toURL
()
})
{
@Override
public
Enumeration
<
URL
>
getResources
(
String
name
)
throws
IOException
{
return
findResources
(
name
);
}
private
final
File
rootFolder
;
@Override
public
URL
getResource
(
String
name
)
{
return
findResource
(
name
);
}
});
this
.
root
=
root
;
public
FolderResourceLoader
(
File
root
)
throws
MalformedURLException
{
super
(
new
FolderClassLoader
(
root
));
this
.
rootFolder
=
root
;
}
@Override
protected
Resource
getResourceByPath
(
String
path
)
{
return
new
FileSystemResource
(
new
File
(
this
.
root
,
path
));
return
new
FileSystemResource
(
new
File
(
this
.
root
Folder
,
path
));
}
}
static
final
class
MatchedResource
{
/**
* {@link ClassLoader} backed by a folder.
*/
private
static
class
FolderClassLoader
extends
URLClassLoader
{
public
FolderClassLoader
(
File
rootFolder
)
throws
MalformedURLException
{
super
(
new
URL
[]
{
rootFolder
.
toURI
().
toURL
()
});
}
@Override
public
Enumeration
<
URL
>
getResources
(
String
name
)
throws
IOException
{
return
findResources
(
name
);
}
@Override
public
URL
getResource
(
String
name
)
{
return
findResource
(
name
);
}
}
/**
* A single matched resource.
*/
public
static
final
class
MatchedResource
{
private
final
File
file
;
private
final
String
path
;
private
final
String
name
;
private
final
boolean
root
;
private
MatchedResource
(
File
resourceFile
)
{
this
(
resourceFile
,
resourceFile
.
getName
(),
true
);
private
MatchedResource
(
File
file
)
{
this
.
name
=
file
.
getName
();
this
.
file
=
file
;
this
.
root
=
false
;
}
private
MatchedResource
(
File
root
,
File
resourceFile
)
{
this
(
resourceFile
,
resourceFile
.
getAbsolutePath
().
substring
(
root
.
getAbsolutePath
().
length
()
+
1
),
false
);
private
MatchedResource
(
File
rootFolder
,
File
file
)
{
this
.
name
=
file
.
getAbsolutePath
().
substring
(
rootFolder
.
getAbsolutePath
().
length
()
+
1
);
this
.
file
=
file
;
this
.
root
=
false
;
}
private
MatchedResource
(
File
resourceFile
,
String
path
,
boolean
root
)
{
this
.
file
=
resourceFile
;
this
.
path
=
path
;
this
.
name
=
path
;
this
.
root
=
root
;
}
File
getFil
e
()
{
return
this
.
fil
e
;
public
String
getNam
e
()
{
return
this
.
nam
e
;
}
String
getPath
()
{
return
this
.
path
;
public
File
getFile
()
{
return
this
.
file
;
}
boolean
isRoot
()
{
public
boolean
isRoot
()
{
return
this
.
root
;
}
...
...
@@ -160,6 +179,7 @@ final class ResourceMatcher {
public
String
toString
()
{
return
this
.
file
.
getAbsolutePath
();
}
}
}
spring-boot-cli/src/main/java/org/springframework/boot/cli/command/shell/ForkProcessCommand.java
View file @
208bf8fc
...
...
@@ -16,8 +16,6 @@
package
org
.
springframework
.
boot
.
cli
.
command
.
shell
;
import
java.io.File
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collection
;
...
...
@@ -25,8 +23,7 @@ import java.util.List;
import
org.springframework.boot.cli.command.Command
;
import
org.springframework.boot.cli.command.OptionHelp
;
import
org.springframework.util.Assert
;
import
org.springframework.util.StringUtils
;
import
org.springframework.boot.cli.util.JavaExecutable
;
/**
* Decorate an existing command to run it by forking the current java process.
...
...
@@ -40,7 +37,7 @@ class ForkProcessCommand extends RunProcessCommand {
private
final
Command
command
;
public
ForkProcessCommand
(
Command
command
)
{
super
(
getJavaCommand
());
super
(
new
JavaExecutable
().
toString
());
this
.
command
=
command
;
}
...
...
@@ -80,24 +77,4 @@ class ForkProcessCommand extends RunProcessCommand {
run
(
fullArgs
);
}
private
static
String
getJavaCommand
()
{
String
javaHome
=
System
.
getProperty
(
"java.home"
);
Assert
.
state
(
StringUtils
.
hasLength
(
javaHome
),
"Unable to find java command to fork process"
);
try
{
return
getJavaCommand
(
javaHome
).
getCanonicalPath
();
}
catch
(
IOException
ex
)
{
throw
new
IllegalStateException
(
ex
);
}
}
private
static
File
getJavaCommand
(
String
javaHome
)
{
File
bin
=
new
File
(
new
File
(
javaHome
),
"bin"
);
File
command
=
new
File
(
bin
,
"java.exe"
);
command
=
(
command
.
exists
()
?
command
:
new
File
(
bin
,
"java"
));
Assert
.
state
(
command
.
exists
(),
"Unable to find java in "
+
javaHome
);
return
command
;
}
}
spring-boot-cli/src/main/java/org/springframework/boot/cli/compiler/GroovyCompiler.java
View file @
208bf8fc
...
...
@@ -34,7 +34,6 @@ import org.codehaus.groovy.ast.ClassNode;
import
org.codehaus.groovy.classgen.GeneratorContext
;
import
org.codehaus.groovy.control.CompilationFailedException
;
import
org.codehaus.groovy.control.CompilationUnit
;
import
org.codehaus.groovy.control.CompilationUnit.ClassgenCallback
;
import
org.codehaus.groovy.control.CompilePhase
;
import
org.codehaus.groovy.control.CompilerConfiguration
;
import
org.codehaus.groovy.control.Phases
;
...
...
@@ -43,8 +42,6 @@ import org.codehaus.groovy.control.customizers.CompilationCustomizer;
import
org.codehaus.groovy.control.customizers.ImportCustomizer
;
import
org.codehaus.groovy.transform.ASTTransformation
;
import
org.codehaus.groovy.transform.ASTTransformationVisitor
;
import
org.objectweb.asm.ClassVisitor
;
import
org.objectweb.asm.ClassWriter
;
import
org.springframework.boot.cli.compiler.grape.AetherGrapeEngine
;
import
org.springframework.boot.cli.compiler.grape.AetherGrapeEngineFactory
;
import
org.springframework.boot.cli.compiler.grape.GrapeEngineInstaller
;
...
...
@@ -120,6 +117,10 @@ public class GroovyCompiler {
}
}
/**
* Return a mutable list of the {@link ASTTransformation}s to be applied during
* {@link #compile(String...)}.
*/
public
List
<
ASTTransformation
>
getAstTransformations
()
{
return
this
.
transformations
;
}
...
...
@@ -210,42 +211,6 @@ public class GroovyCompiler {
return
classes
.
toArray
(
new
Class
<?>[
classes
.
size
()]);
}
public
void
compile
(
final
CompilationCallback
callback
,
String
...
sources
)
throws
CompilationFailedException
,
IOException
{
this
.
loader
.
clearCache
();
CompilerConfiguration
configuration
=
this
.
loader
.
getConfiguration
();
final
CompilationUnit
compilationUnit
=
new
CompilationUnit
(
configuration
,
null
,
this
.
loader
);
ClassgenCallback
classgenCallback
=
new
ClassgenCallback
()
{
@Override
public
void
call
(
ClassVisitor
writer
,
ClassNode
node
)
throws
CompilationFailedException
{
try
{
callback
.
byteCodeGenerated
(((
ClassWriter
)
writer
).
toByteArray
(),
node
);
}
catch
(
IOException
ioe
)
{
throw
new
CompilationFailedException
(
Phases
.
CLASS_GENERATION
,
compilationUnit
);
}
}
};
compilationUnit
.
setClassgenCallback
(
classgenCallback
);
for
(
String
source
:
sources
)
{
List
<
String
>
paths
=
ResourceUtils
.
getUrls
(
source
,
this
.
loader
);
for
(
String
path
:
paths
)
{
compilationUnit
.
addSource
(
new
URL
(
path
));
}
}
addAstTransformations
(
compilationUnit
);
compilationUnit
.
compile
(
Phases
.
CLASS_GENERATION
);
}
@SuppressWarnings
(
"rawtypes"
)
private
void
addAstTransformations
(
CompilationUnit
compilationUnit
)
{
LinkedList
[]
phaseOperations
=
getPhaseOperations
(
compilationUnit
);
...
...
@@ -329,10 +294,4 @@ public class GroovyCompiler {
}
public
static
interface
CompilationCallback
{
public
void
byteCodeGenerated
(
byte
[]
byteCode
,
ClassNode
classNode
)
throws
IOException
;
}
}
spring-boot-cli/src/main/java/org/springframework/boot/cli/jar/PackagedSpringApplicationLauncher.java
View file @
208bf8fc
...
...
@@ -29,6 +29,8 @@ import java.util.jar.Manifest;
*/
public
class
PackagedSpringApplicationLauncher
{
public
static
final
String
SOURCE_MANIFEST_ENTRY
=
"Spring-Application-Source-Classes"
;
private
static
final
String
SPRING_APPLICATION_CLASS
=
"org.springframework.boot.SpringApplication"
;
private
void
run
(
String
[]
args
)
throws
Exception
{
...
...
@@ -42,7 +44,7 @@ public class PackagedSpringApplicationLauncher {
private
Object
[]
getSources
(
URLClassLoader
classLoader
)
throws
Exception
{
URL
url
=
classLoader
.
findResource
(
"META-INF/MANIFEST.MF"
);
Manifest
manifest
=
new
Manifest
(
url
.
openStream
());
String
attribute
=
manifest
.
getMainAttributes
().
getValue
(
"Application-Classes"
);
String
attribute
=
manifest
.
getMainAttributes
().
getValue
(
SOURCE_MANIFEST_ENTRY
);
return
loadClasses
(
classLoader
,
attribute
.
split
(
","
));
}
...
...
spring-boot-cli/src/main/java/org/springframework/boot/cli/util/JavaExecutable.java
0 → 100644
View file @
208bf8fc
/*
* Copyright 2012-2014 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
.
util
;
import
java.io.File
;
import
java.io.IOException
;
import
java.util.Arrays
;
import
org.springframework.util.Assert
;
import
org.springframework.util.StringUtils
;
/**
* Provides access to the java binary executable, regardless of OS.
*
* @author Phillip Webb
*/
public
class
JavaExecutable
{
private
File
file
;
public
JavaExecutable
()
{
String
javaHome
=
System
.
getProperty
(
"java.home"
);
Assert
.
state
(
StringUtils
.
hasLength
(
javaHome
),
"Unable to find java executable due to missing 'java.home'"
);
this
.
file
=
findInJavaHome
(
javaHome
);
}
private
File
findInJavaHome
(
String
javaHome
)
{
File
bin
=
new
File
(
new
File
(
javaHome
),
"bin"
);
File
command
=
new
File
(
bin
,
"java.exe"
);
command
=
(
command
.
exists
()
?
command
:
new
File
(
bin
,
"java"
));
Assert
.
state
(
command
.
exists
(),
"Unable to find java in "
+
javaHome
);
return
command
;
}
public
ProcessBuilder
processBuilder
(
String
...
arguments
)
{
ProcessBuilder
processBuilder
=
new
ProcessBuilder
(
toString
());
processBuilder
.
command
().
addAll
(
Arrays
.
asList
(
arguments
));
return
processBuilder
;
}
@Override
public
String
toString
()
{
try
{
return
this
.
file
.
getCanonicalPath
();
}
catch
(
IOException
ex
)
{
throw
new
IllegalStateException
(
ex
);
}
}
}
spring-boot-cli/src/test/java/org/springframework/boot/cli/command/jar/ResourceMatcherTests.java
View file @
208bf8fc
...
...
@@ -29,7 +29,9 @@ import static org.junit.Assert.assertEquals;
import
static
org
.
junit
.
Assert
.
assertTrue
;
/**
* @author awilkinson
* Tests for {@link ResourceMatcher}.
*
* @author Andy Wilkinson
*/
public
class
ResourceMatcherTests
{
...
...
@@ -38,22 +40,21 @@ public class ResourceMatcherTests {
@Test
public
void
nonExistentRoot
()
throws
IOException
{
List
<
MatchedResource
>
matchedResources
=
this
.
resourceMatcher
.
matchResources
(
Arrays
.
asList
(
new
File
(
"does-not-exist"
)));
List
<
MatchedResource
>
matchedResources
=
this
.
resourceMatcher
.
find
(
Arrays
.
asList
(
new
File
(
"does-not-exist"
)));
assertEquals
(
0
,
matchedResources
.
size
());
}
@Test
public
void
resourceMatching
()
throws
IOException
{
List
<
MatchedResource
>
matchedResources
=
this
.
resourceMatcher
.
matchResources
(
Arrays
.
asList
(
new
File
(
"src/test/resources/resource-matcher/one"
),
new
File
(
List
<
MatchedResource
>
matchedResources
=
this
.
resourceMatcher
.
find
(
Arrays
.
asList
(
new
File
(
"src/test/resources/resource-matcher/one"
),
new
File
(
"src/test/resources/resource-matcher/two"
),
new
File
(
"src/test/resources/resource-matcher/three"
)));
System
.
out
.
println
(
matchedResources
);
List
<
String
>
paths
=
new
ArrayList
<
String
>();
for
(
MatchedResource
resource
:
matchedResources
)
{
paths
.
add
(
resource
.
get
Path
());
paths
.
add
(
resource
.
get
Name
());
}
assertEquals
(
6
,
paths
.
size
());
...
...
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