Add option to exclude devtools from fat jar
Add an `excludeDevtools` property to both the Maven and Gradle plugin that removes `org.springframework.boot:spring-boot-devtools` (if necessary) when repackaging the application. Closes gh-3171
This commit is contained in:
parent
e2fc30ef24
commit
e79ef9b73b
|
|
@ -395,6 +395,10 @@ want the other Boot features but not this one)
|
||||||
|`embeddedLaunchScriptProperties`
|
|`embeddedLaunchScriptProperties`
|
||||||
|Additional properties that to be expanded in the launch script. The default script
|
|Additional properties that to be expanded in the launch script. The default script
|
||||||
supports a `mode` property which can contain the values `auto`, `service` or `run`.
|
supports a `mode` property which can contain the values `auto`, `service` or `run`.
|
||||||
|
|
||||||
|
|`excludeDevtools`
|
||||||
|
|Boolean flag to indicate if the devtools jar should be excluded from the repackaged
|
||||||
|
archives. Defaults to `false`.
|
||||||
|===
|
|===
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -844,6 +844,10 @@ applied to other modules using your project. Gradle does not support `optional`
|
||||||
dependencies out-of-the-box so you may want to have a look to the
|
dependencies out-of-the-box so you may want to have a look to the
|
||||||
{propdeps-plugin}[`propdeps-plugin`] in the meantime.
|
{propdeps-plugin}[`propdeps-plugin`] in the meantime.
|
||||||
|
|
||||||
|
TIP: If you want to ensure that devtools is never included in a production build, you can
|
||||||
|
use set the `excludeDevtools` build property to completely remove the JAR. The property is
|
||||||
|
supported with both the Maven and Gradle plugins.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[using-boot-devtools-property-defaults]]
|
[[using-boot-devtools-property-defaults]]
|
||||||
|
|
|
||||||
|
|
@ -47,19 +47,24 @@ public class RepackagingTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void repackagingEnabled() {
|
public void repackagingEnabled() throws IOException {
|
||||||
project.newBuild().forTasks("clean", "build")
|
project.newBuild().forTasks("clean", "build")
|
||||||
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true").run();
|
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true",
|
||||||
|
"-PexcludeDevtools=false")
|
||||||
|
.run();
|
||||||
File buildLibs = new File("target/repackage/build/libs");
|
File buildLibs = new File("target/repackage/build/libs");
|
||||||
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
File repackageFile = new File(buildLibs, "repackage.jar");
|
||||||
|
assertTrue(repackageFile.exists());
|
||||||
assertTrue(new File(buildLibs, "repackage.jar.original").exists());
|
assertTrue(new File(buildLibs, "repackage.jar.original").exists());
|
||||||
assertFalse(new File(buildLibs, "repackage-sources.jar.original").exists());
|
assertFalse(new File(buildLibs, "repackage-sources.jar.original").exists());
|
||||||
|
assertTrue(isDevToolsJarIncluded(repackageFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void repackagingDisabled() {
|
public void repackagingDisabled() {
|
||||||
project.newBuild().forTasks("clean", "build")
|
project.newBuild().forTasks("clean", "build")
|
||||||
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=false")
|
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=false",
|
||||||
|
"-PexcludeDevtools=false")
|
||||||
.run();
|
.run();
|
||||||
File buildLibs = new File("target/repackage/build/libs");
|
File buildLibs = new File("target/repackage/build/libs");
|
||||||
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
||||||
|
|
@ -70,7 +75,8 @@ public class RepackagingTests {
|
||||||
@Test
|
@Test
|
||||||
public void repackagingDisabledWithCustomRepackagedJar() {
|
public void repackagingDisabledWithCustomRepackagedJar() {
|
||||||
project.newBuild().forTasks("clean", "build", "customRepackagedJar")
|
project.newBuild().forTasks("clean", "build", "customRepackagedJar")
|
||||||
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=false")
|
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=false",
|
||||||
|
"-PexcludeDevtools=false")
|
||||||
.run();
|
.run();
|
||||||
File buildLibs = new File("target/repackage/build/libs");
|
File buildLibs = new File("target/repackage/build/libs");
|
||||||
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
||||||
|
|
@ -84,7 +90,8 @@ public class RepackagingTests {
|
||||||
public void repackagingDisabledWithCustomRepackagedJarUsingStringJarTaskReference() {
|
public void repackagingDisabledWithCustomRepackagedJarUsingStringJarTaskReference() {
|
||||||
project.newBuild()
|
project.newBuild()
|
||||||
.forTasks("clean", "build", "customRepackagedJarWithStringReference")
|
.forTasks("clean", "build", "customRepackagedJarWithStringReference")
|
||||||
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=false")
|
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=false",
|
||||||
|
"-PexcludeDevtools=false")
|
||||||
.run();
|
.run();
|
||||||
File buildLibs = new File("target/repackage/build/libs");
|
File buildLibs = new File("target/repackage/build/libs");
|
||||||
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
||||||
|
|
@ -97,7 +104,9 @@ public class RepackagingTests {
|
||||||
@Test
|
@Test
|
||||||
public void repackagingEnabledWithCustomRepackagedJar() {
|
public void repackagingEnabledWithCustomRepackagedJar() {
|
||||||
project.newBuild().forTasks("clean", "build", "customRepackagedJar")
|
project.newBuild().forTasks("clean", "build", "customRepackagedJar")
|
||||||
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true").run();
|
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true",
|
||||||
|
"-PexcludeDevtools=false")
|
||||||
|
.run();
|
||||||
File buildLibs = new File("target/repackage/build/libs");
|
File buildLibs = new File("target/repackage/build/libs");
|
||||||
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
||||||
assertTrue(new File(buildLibs, "repackage.jar.original").exists());
|
assertTrue(new File(buildLibs, "repackage.jar.original").exists());
|
||||||
|
|
@ -110,7 +119,9 @@ public class RepackagingTests {
|
||||||
public void repackagingEnableWithCustomRepackagedJarUsingStringJarTaskReference() {
|
public void repackagingEnableWithCustomRepackagedJarUsingStringJarTaskReference() {
|
||||||
project.newBuild()
|
project.newBuild()
|
||||||
.forTasks("clean", "build", "customRepackagedJarWithStringReference")
|
.forTasks("clean", "build", "customRepackagedJarWithStringReference")
|
||||||
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true").run();
|
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true",
|
||||||
|
"-PexcludeDevtools=false")
|
||||||
|
.run();
|
||||||
File buildLibs = new File("target/repackage/build/libs");
|
File buildLibs = new File("target/repackage/build/libs");
|
||||||
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
assertTrue(new File(buildLibs, "repackage.jar").exists());
|
||||||
assertTrue(new File(buildLibs, "repackage.jar.original").exists());
|
assertTrue(new File(buildLibs, "repackage.jar.original").exists());
|
||||||
|
|
@ -124,10 +135,38 @@ public class RepackagingTests {
|
||||||
FileCopyUtils.copy(new File("src/test/resources/foo.jar"),
|
FileCopyUtils.copy(new File("src/test/resources/foo.jar"),
|
||||||
new File("target/repackage/foo.jar"));
|
new File("target/repackage/foo.jar"));
|
||||||
project.newBuild().forTasks("clean", "build")
|
project.newBuild().forTasks("clean", "build")
|
||||||
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true").run();
|
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true",
|
||||||
|
"-PexcludeDevtools=false")
|
||||||
|
.run();
|
||||||
File buildLibs = new File("target/repackage/build/libs");
|
File buildLibs = new File("target/repackage/build/libs");
|
||||||
JarFile jarFile = new JarFile(new File(buildLibs, "repackage.jar"));
|
JarFile jarFile = new JarFile(new File(buildLibs, "repackage.jar"));
|
||||||
assertThat(jarFile.getEntry("lib/foo.jar"), notNullValue());
|
assertThat(jarFile.getEntry("lib/foo.jar"), notNullValue());
|
||||||
jarFile.close();
|
jarFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void repackagingEnabledExcludeDevtools() throws IOException {
|
||||||
|
project.newBuild().forTasks("clean", "build")
|
||||||
|
.withArguments("-PbootVersion=" + BOOT_VERSION, "-Prepackage=true",
|
||||||
|
"-PexcludeDevtools=true")
|
||||||
|
.run();
|
||||||
|
File buildLibs = new File("target/repackage/build/libs");
|
||||||
|
File repackageFile = new File(buildLibs, "repackage.jar");
|
||||||
|
assertTrue(repackageFile.exists());
|
||||||
|
assertTrue(new File(buildLibs, "repackage.jar.original").exists());
|
||||||
|
assertFalse(new File(buildLibs, "repackage-sources.jar.original").exists());
|
||||||
|
assertFalse(isDevToolsJarIncluded(repackageFile));
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDevToolsJarIncluded(File repackageFile) throws IOException {
|
||||||
|
JarFile jarFile = new JarFile(repackageFile);
|
||||||
|
try {
|
||||||
|
String name = "lib/spring-boot-devtools-" + BOOT_VERSION + ".jar";
|
||||||
|
return jarFile.getEntry(name) != null;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
jarFile.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,13 @@ apply plugin: 'java'
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'org.springframework.boot:spring-boot-starter-freemarker'
|
compile 'org.springframework.boot:spring-boot-starter-freemarker'
|
||||||
compile 'org.springframework.boot:spring-boot-starter-web'
|
compile 'org.springframework.boot:spring-boot-starter-web'
|
||||||
|
compile 'org.springframework.boot:spring-boot-devtools'
|
||||||
compile files("foo.jar")
|
compile files("foo.jar")
|
||||||
}
|
}
|
||||||
|
|
||||||
springBoot {
|
springBoot {
|
||||||
mainClass = 'foo.bar.Baz'
|
mainClass = 'foo.bar.Baz'
|
||||||
|
excludeDevtools = Boolean.valueOf(project.excludeDevtools)
|
||||||
}
|
}
|
||||||
|
|
||||||
bootRepackage.enabled = Boolean.valueOf(project.repackage)
|
bootRepackage.enabled = Boolean.valueOf(project.repackage)
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import org.springframework.boot.loader.tools.Layouts;
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Dave Syer
|
* @author Dave Syer
|
||||||
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
public class SpringBootPluginExtension {
|
public class SpringBootPluginExtension {
|
||||||
|
|
||||||
|
|
@ -87,6 +88,11 @@ public class SpringBootPluginExtension {
|
||||||
*/
|
*/
|
||||||
Set<String> requiresUnpack;
|
Set<String> requiresUnpack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether Spring Boot Devtools should be excluded from the fat jar.
|
||||||
|
*/
|
||||||
|
boolean excludeDevtools = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Location of an agent jar to attach to the VM when running the application with
|
* Location of an agent jar to attach to the VM when running the application with
|
||||||
* runJar task.
|
* runJar task.
|
||||||
|
|
@ -186,6 +192,14 @@ public class SpringBootPluginExtension {
|
||||||
this.requiresUnpack = requiresUnpack;
|
this.requiresUnpack = requiresUnpack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isExcludeDevtools() {
|
||||||
|
return this.excludeDevtools;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExcludeDevtools(boolean excludeDevtools) {
|
||||||
|
this.excludeDevtools = excludeDevtools;
|
||||||
|
}
|
||||||
|
|
||||||
public File getAgent() {
|
public File getAgent() {
|
||||||
return this.agent;
|
return this.agent;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -155,12 +155,26 @@ class ProjectLibraries implements Libraries {
|
||||||
if (libraries != null) {
|
if (libraries != null) {
|
||||||
Set<String> duplicates = getDuplicates(libraries);
|
Set<String> duplicates = getDuplicates(libraries);
|
||||||
for (GradleLibrary library : libraries) {
|
for (GradleLibrary library : libraries) {
|
||||||
library.setIncludeGroupName(duplicates.contains(library.getName()));
|
if (!isExcluded(library)) {
|
||||||
callback.library(library);
|
library.setIncludeGroupName(duplicates.contains(library.getName()));
|
||||||
|
callback.library(library);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isExcluded(GradleLibrary library) {
|
||||||
|
if (this.extension.isExcludeDevtools() && isDevToolsJar(library)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isDevToolsJar(GradleLibrary library) {
|
||||||
|
return "org.springframework.boot".equals(library.getGroup())
|
||||||
|
&& library.getName().startsWith("spring-boot-devtools");
|
||||||
|
}
|
||||||
|
|
||||||
private Set<String> getDuplicates(Set<GradleLibrary> libraries) {
|
private Set<String> getDuplicates(Set<GradleLibrary> libraries) {
|
||||||
Set<String> duplicates = new HashSet<String>();
|
Set<String> duplicates = new HashSet<String>();
|
||||||
Set<String> seen = new HashSet<String>();
|
Set<String> seen = new HashSet<String>();
|
||||||
|
|
@ -187,6 +201,10 @@ class ProjectLibraries implements Libraries {
|
||||||
this.includeGroupName = includeGroupName;
|
this.includeGroupName = includeGroupName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getGroup() {
|
||||||
|
return this.group;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
String name = super.getName();
|
String name = super.getName();
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2014 the original author or authors.
|
* Copyright 2012-2015 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.boot.maven;
|
package org.springframework.boot.maven;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.maven.artifact.Artifact;
|
import org.apache.maven.artifact.Artifact;
|
||||||
|
|
@ -29,6 +30,10 @@ import org.apache.maven.artifact.Artifact;
|
||||||
*/
|
*/
|
||||||
public class ExcludeFilter extends DependencyFilter {
|
public class ExcludeFilter extends DependencyFilter {
|
||||||
|
|
||||||
|
public ExcludeFilter(Exclude... excludes) {
|
||||||
|
this(Arrays.asList(excludes));
|
||||||
|
}
|
||||||
|
|
||||||
public ExcludeFilter(List<Exclude> excludes) {
|
public ExcludeFilter(List<Exclude> excludes) {
|
||||||
super(excludes);
|
super(excludes);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import org.apache.maven.plugins.annotations.Parameter;
|
||||||
import org.apache.maven.plugins.annotations.ResolutionScope;
|
import org.apache.maven.plugins.annotations.ResolutionScope;
|
||||||
import org.apache.maven.project.MavenProject;
|
import org.apache.maven.project.MavenProject;
|
||||||
import org.apache.maven.project.MavenProjectHelper;
|
import org.apache.maven.project.MavenProjectHelper;
|
||||||
|
import org.apache.maven.shared.artifact.filter.collection.ArtifactsFilter;
|
||||||
import org.springframework.boot.loader.tools.DefaultLaunchScript;
|
import org.springframework.boot.loader.tools.DefaultLaunchScript;
|
||||||
import org.springframework.boot.loader.tools.LaunchScript;
|
import org.springframework.boot.loader.tools.LaunchScript;
|
||||||
import org.springframework.boot.loader.tools.Layout;
|
import org.springframework.boot.loader.tools.Layout;
|
||||||
|
|
@ -153,6 +154,13 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
|
||||||
@Parameter
|
@Parameter
|
||||||
private Properties embeddedLaunchScriptProperties;
|
private Properties embeddedLaunchScriptProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exclude Spring Boot devtools.
|
||||||
|
* @since 1.3
|
||||||
|
*/
|
||||||
|
@Parameter(defaultValue = "false")
|
||||||
|
private boolean excludeDevtools;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute() throws MojoExecutionException, MojoFailureException {
|
public void execute() throws MojoExecutionException, MojoFailureException {
|
||||||
if (this.project.getPackaging().equals("pom")) {
|
if (this.project.getPackaging().equals("pom")) {
|
||||||
|
|
@ -190,7 +198,7 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<Artifact> artifacts = filterDependencies(this.project.getArtifacts(),
|
Set<Artifact> artifacts = filterDependencies(this.project.getArtifacts(),
|
||||||
getFilters());
|
getFilters(getAdditionalFilters()));
|
||||||
|
|
||||||
Libraries libraries = new ArtifactsLibraries(artifacts, this.requiresUnpack,
|
Libraries libraries = new ArtifactsLibraries(artifacts, this.requiresUnpack,
|
||||||
getLog());
|
getLog());
|
||||||
|
|
@ -213,6 +221,17 @@ public class RepackageMojo extends AbstractDependencyFilterMojo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ArtifactsFilter[] getAdditionalFilters() {
|
||||||
|
if (this.excludeDevtools) {
|
||||||
|
Exclude exclude = new Exclude();
|
||||||
|
exclude.setGroupId("org.springframework.boot");
|
||||||
|
exclude.setArtifactId("spring-boot-devtools");
|
||||||
|
ExcludeFilter filter = new ExcludeFilter(exclude);
|
||||||
|
return new ArtifactsFilter[] { filter };
|
||||||
|
}
|
||||||
|
return new ArtifactsFilter[] {};
|
||||||
|
}
|
||||||
|
|
||||||
private File getTargetFile() {
|
private File getTargetFile() {
|
||||||
String classifier = (this.classifier == null ? "" : this.classifier.trim());
|
String classifier = (this.classifier == null ? "" : this.classifier.trim());
|
||||||
if (classifier.length() > 0 && !classifier.startsWith("-")) {
|
if (classifier.length() > 0 && !classifier.startsWith("-")) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue