mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Enhance JarCommand to support lists of includes and excludes
The lists are comma separated. In addition, user can add prefixes "+" or "-", to signal that those values should be removed from the default list, not added to a fresh one. E.g. $ spring jar app.jar --include lib/*.jar,-static/** --exclude -**/*.jar to include a jar file specifically, and make sure it is not excluded, and additionally not include the static/** resources that would otherwise be included in the defaults. As soon as "+" or "-" prefixes are detected the default entries are all added (except the ones exlcuded with "-"). Fixes gh-1090
This commit is contained in:
parent
d842446186
commit
2c691e5ae5
@ -26,6 +26,7 @@ import org.springframework.boot.loader.tools.JavaExecutable;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
@ -80,7 +81,32 @@ public class JarCommandIT {
|
||||
assertThat(invocation.getStandardOutput(), containsString("/static/static.txt"));
|
||||
assertThat(invocation.getStandardOutput(),
|
||||
containsString("/templates/template.txt"));
|
||||
assertThat(invocation.getStandardOutput(), containsString("Goodbye Mama"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jarCreationWithIncludes() throws Exception {
|
||||
File jar = new File("target/test-app.jar");
|
||||
Invocation invocation = this.cli.invoke("jar", jar.getAbsolutePath(),
|
||||
"--include", "-public/**,-resources/**", "jar.groovy");
|
||||
invocation.await();
|
||||
assertEquals(invocation.getErrorOutput(), 0, invocation.getErrorOutput().length());
|
||||
assertTrue(jar.exists());
|
||||
|
||||
Process process = new JavaExecutable().processBuilder("-jar",
|
||||
jar.getAbsolutePath()).start();
|
||||
invocation = new Invocation(process);
|
||||
invocation.await();
|
||||
|
||||
assertThat(invocation.getErrorOutput(), equalTo(""));
|
||||
assertThat(invocation.getStandardOutput(), containsString("Hello World!"));
|
||||
assertThat(invocation.getStandardOutput(),
|
||||
containsString("Goodbye Mama"));
|
||||
not(containsString("/public/public.txt")));
|
||||
assertThat(invocation.getStandardOutput(),
|
||||
not(containsString("/resources/resource.txt")));
|
||||
assertThat(invocation.getStandardOutput(), containsString("/static/static.txt"));
|
||||
assertThat(invocation.getStandardOutput(),
|
||||
containsString("/templates/template.txt"));
|
||||
assertThat(invocation.getStandardOutput(), containsString("Goodbye Mama"));
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +169,9 @@ public class CommandRunner implements Iterable<Command> {
|
||||
try {
|
||||
ExitStatus result = run(argsWithoutDebugFlags);
|
||||
// The caller will hang up if it gets a non-zero status
|
||||
return result==null ? 0 : result.isHangup() ? (result.getCode()>0 ? result.getCode() : 1) : 0;
|
||||
return result == null ? 0
|
||||
: result.isHangup() ? (result.getCode() > 0 ? result.getCode() : 0)
|
||||
: 0;
|
||||
}
|
||||
catch (NoArgumentsException ex) {
|
||||
showUsage();
|
||||
|
@ -68,12 +68,6 @@ import org.springframework.util.Assert;
|
||||
*/
|
||||
public class JarCommand extends OptionParsingCommand {
|
||||
|
||||
private static final String[] DEFAULT_INCLUDES = { "public/**", "resources/**",
|
||||
"static/**", "templates/**", "META-INF/**", "*" };
|
||||
|
||||
private static final String[] DEFAULT_EXCLUDES = { ".*", "repository/**", "build/**",
|
||||
"target/**", "**/*.jar", "**/*.groovy" };
|
||||
|
||||
private static final Layout LAYOUT = new Layouts.Jar();
|
||||
|
||||
public JarCommand() {
|
||||
@ -98,11 +92,11 @@ public class JarCommand extends OptionParsingCommand {
|
||||
this.includeOption = option(
|
||||
"include",
|
||||
"Pattern applied to directories on the classpath to find files to include in the resulting jar")
|
||||
.withRequiredArg().defaultsTo(DEFAULT_INCLUDES);
|
||||
.withRequiredArg().withValuesSeparatedBy(",").defaultsTo("");
|
||||
this.excludeOption = option(
|
||||
"exclude",
|
||||
"Pattern applied to directories on the claspath to find files to exclude from the resulting jar")
|
||||
.withRequiredArg().defaultsTo(DEFAULT_EXCLUDES);
|
||||
.withRequiredArg().withValuesSeparatedBy(",").defaultsTo("");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -23,7 +23,9 @@ import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
@ -39,6 +41,12 @@ import org.springframework.util.AntPathMatcher;
|
||||
*/
|
||||
class ResourceMatcher {
|
||||
|
||||
private static final String[] DEFAULT_INCLUDES = { "public/**", "resources/**",
|
||||
"static/**", "templates/**", "META-INF/**", "*" };
|
||||
|
||||
private static final String[] DEFAULT_EXCLUDES = { ".*", "repository/**", "build/**",
|
||||
"target/**", "**/*.jar", "**/*.groovy" };
|
||||
|
||||
private final AntPathMatcher pathMatcher = new AntPathMatcher();
|
||||
|
||||
private final List<String> includes;
|
||||
@ -46,8 +54,8 @@ class ResourceMatcher {
|
||||
private final List<String> excludes;
|
||||
|
||||
ResourceMatcher(List<String> includes, List<String> excludes) {
|
||||
this.includes = includes;
|
||||
this.excludes = excludes;
|
||||
this.includes = getOptions(includes, DEFAULT_INCLUDES);
|
||||
this.excludes = getOptions(excludes, DEFAULT_EXCLUDES);
|
||||
}
|
||||
|
||||
public List<MatchedResource> find(List<File> roots) throws IOException {
|
||||
@ -93,6 +101,33 @@ class ResourceMatcher {
|
||||
return false;
|
||||
}
|
||||
|
||||
private List<String> getOptions(List<String> values, String[] defaults) {
|
||||
Set<String> result = new LinkedHashSet<String>();
|
||||
Set<String> minus = new LinkedHashSet<String>();
|
||||
boolean deltasFound = false;
|
||||
for (String value : values) {
|
||||
if (value.startsWith("+")) {
|
||||
deltasFound = true;
|
||||
value = value.substring(1);
|
||||
result.add(value);
|
||||
}
|
||||
else if (value.startsWith("-")) {
|
||||
deltasFound = true;
|
||||
value = value.substring(1);
|
||||
minus.add(value);
|
||||
}
|
||||
else if (value.trim().length() > 0) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
for (String value : defaults) {
|
||||
if (!minus.contains(value) || !deltasFound) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
return new ArrayList<String>(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ResourceLoader} to get load resource from a folder.
|
||||
*/
|
||||
|
@ -20,16 +20,19 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Description;
|
||||
import org.hamcrest.TypeSafeMatcher;
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.cli.command.jar.ResourceMatcher.MatchedResource;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@ -40,16 +43,26 @@ import static org.junit.Assert.assertTrue;
|
||||
*/
|
||||
public class ResourceMatcherTests {
|
||||
|
||||
private final ResourceMatcher resourceMatcher = new ResourceMatcher(Arrays.asList(
|
||||
"alpha/**", "bravo/*", "*"), Arrays.asList(".*", "alpha/**/excluded"));
|
||||
|
||||
@Test
|
||||
public void nonExistentRoot() throws IOException {
|
||||
List<MatchedResource> matchedResources = this.resourceMatcher.find(Arrays
|
||||
ResourceMatcher resourceMatcher = new ResourceMatcher(Arrays.asList("alpha/**",
|
||||
"bravo/*", "*"), Arrays.asList(".*", "alpha/**/excluded"));
|
||||
List<MatchedResource> matchedResources = resourceMatcher.find(Arrays
|
||||
.asList(new File("does-not-exist")));
|
||||
assertEquals(0, matchedResources.size());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void defaults() throws Exception {
|
||||
ResourceMatcher resourceMatcher = new ResourceMatcher(Arrays.asList(""),
|
||||
Arrays.asList(""));
|
||||
assertTrue(((Collection<String>) ReflectionTestUtils.getField(resourceMatcher,
|
||||
"includes")).contains("static/**"));
|
||||
assertTrue(((Collection<String>) ReflectionTestUtils.getField(resourceMatcher,
|
||||
"excludes")).contains("**/*.jar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void excludedWins() throws Exception {
|
||||
ResourceMatcher resourceMatcher = new ResourceMatcher(Arrays.asList("*"),
|
||||
@ -59,6 +72,40 @@ public class ResourceMatcherTests {
|
||||
assertThat(found, not(hasItem(new FooJarMatcher(MatchedResource.class))));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void includedDeltas() throws Exception {
|
||||
ResourceMatcher resourceMatcher = new ResourceMatcher(
|
||||
Arrays.asList("-static/**"), Arrays.asList(""));
|
||||
Collection<String> includes = (Collection<String>) ReflectionTestUtils.getField(
|
||||
resourceMatcher, "includes");
|
||||
assertTrue(includes.contains("templates/**"));
|
||||
assertFalse(includes.contains("static/**"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void includedDeltasAndNewEntries() throws Exception {
|
||||
ResourceMatcher resourceMatcher = new ResourceMatcher(Arrays.asList("-static/**",
|
||||
"foo.jar"), Arrays.asList("-**/*.jar"));
|
||||
Collection<String> includes = (Collection<String>) ReflectionTestUtils.getField(
|
||||
resourceMatcher, "includes");
|
||||
assertTrue(includes.contains("foo.jar"));
|
||||
assertTrue(includes.contains("templates/**"));
|
||||
assertFalse(includes.contains("static/**"));
|
||||
assertFalse(((Collection<String>) ReflectionTestUtils.getField(resourceMatcher,
|
||||
"excludes")).contains("**/*.jar"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void excludedDeltas() throws Exception {
|
||||
ResourceMatcher resourceMatcher = new ResourceMatcher(Arrays.asList(""),
|
||||
Arrays.asList("-**/*.jar"));
|
||||
assertFalse(((Collection<String>) ReflectionTestUtils.getField(resourceMatcher,
|
||||
"excludes")).contains("**/*.jar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void jarFileAlwaysMatches() throws Exception {
|
||||
ResourceMatcher resourceMatcher = new ResourceMatcher(Arrays.asList("*"),
|
||||
@ -73,7 +120,9 @@ public class ResourceMatcherTests {
|
||||
|
||||
@Test
|
||||
public void resourceMatching() throws IOException {
|
||||
List<MatchedResource> matchedResources = this.resourceMatcher.find(Arrays.asList(
|
||||
ResourceMatcher resourceMatcher = new ResourceMatcher(Arrays.asList("alpha/**",
|
||||
"bravo/*", "*"), Arrays.asList(".*", "alpha/**/excluded"));
|
||||
List<MatchedResource> matchedResources = 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")));
|
||||
|
@ -265,9 +265,25 @@ executable jar file. For example:
|
||||
$ spring jar my-app.jar *.groovy
|
||||
----
|
||||
|
||||
The resulting jar will contain the classes produced by compiling the application and all
|
||||
of the application's dependencies so that it can then be run using `java -jar`. The jar
|
||||
file will also contain entries from the application's classpath.
|
||||
The resulting jar will contain the classes produced by compiling the
|
||||
application and all of the application's dependencies so that it can
|
||||
then be run using `java -jar`. The jar file will also contain entries
|
||||
from the application's classpath. You can add explicit paths to the
|
||||
jar using `--include` and `--exclude` (both are comma separated, and
|
||||
both accept prefixes to the values "+" and "-" to signify that they
|
||||
shoudl be removed from the defaults). The default includes are
|
||||
|
||||
[indent=0]
|
||||
----
|
||||
public/**, resources/**, static/**, templates/**, META-INF/**, *
|
||||
----
|
||||
|
||||
and the default excludes are
|
||||
|
||||
[indent=0]
|
||||
----
|
||||
.*, repository/**, build/**, target/**, **/*.jar, **/*.groovy
|
||||
----
|
||||
|
||||
See the output of `spring help jar` for more information.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user