Skip to content

Commit 7bc7d86

Browse files
committed
Refine layer customization for Maven and Gradle
Simplify layer customization logic for both Maven and Gradle and refactor some internals of the Gradle plugin. Both Maven and Gradle now use a simpler customization format that consists of `application`, `dependencies` and `layer order` sections. The `application`, `dependencies` configurations support one or more `into` blocks that are used to select content for a specific layer. Closes gh-20526
1 parent 14718f3 commit 7bc7d86

File tree

61 files changed

+2033
-2040
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+2033
-2040
lines changed

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,17 @@ bootJar {
99

1010
// tag::layered[]
1111
bootJar {
12-
layers {
13-
layersOrder "dependencies", "snapshot-dependencies", "application"
14-
libraries {
15-
layerContent("snapshot-dependencies") {
16-
coordinates {
17-
include "*:*:*SNAPSHOT"
18-
}
19-
}
20-
layerContent("dependencies") {
21-
coordinates {
22-
include "*:*"
23-
}
24-
}
25-
}
12+
layered {
2613
application {
27-
layerContent("application") {
28-
locations {
29-
include "**"
30-
}
14+
intoLayer("application")
15+
}
16+
dependencies {
17+
intoLayer("snapshot-dependencies") {
18+
include "*:*:*SNAPSHOT"
3119
}
20+
intoLayer("dependencies")
3221
}
22+
layerOrder "dependencies", "snapshot-dependencies", "application"
3323
}
3424
}
3525
// end::layered[]

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered-custom.gradle.kts

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,17 @@ plugins {
77

88
// tag::layered[]
99
tasks.getByName<BootJar>("bootJar") {
10-
layers {
11-
layersOrder("dependencies", "snapshot-dependencies", "application")
12-
libraries {
13-
layerContent("snapshot-dependencies") {
14-
coordinates {
15-
include("*:*:*SNAPSHOT")
16-
}
17-
}
18-
layerContent("dependencies") {
19-
coordinates {
20-
include("*:*")
21-
}
22-
}
23-
}
10+
layered {
2411
application {
25-
layerContent("application") {
26-
locations {
27-
include("**")
28-
}
12+
intoLayer("application")
13+
}
14+
dependencies {
15+
intoLayer("snapshot-dependencies") {
16+
include("*:*:*SNAPSHOT")
2917
}
18+
intoLayer("dependencies") {
3019
}
20+
layersOrder("dependencies", "snapshot-dependencies", "application")
3121
}
3222
}
3323
// end::layered[]

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ bootJar {
99

1010
// tag::layered[]
1111
bootJar {
12-
layers()
12+
layered()
1313
}
1414
// end::layered[]

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/docs/gradle/packaging/boot-jar-layered.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ tasks.getByName<BootJar>("bootJar") {
1111

1212
// tag::layered[]
1313
tasks.getByName<BootJar>("bootJar") {
14-
layers()
14+
layered()
1515
}
1616
// end::layered[]

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/plugin/JavaPluginAction.java

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import org.gradle.api.Plugin;
2828
import org.gradle.api.Project;
2929
import org.gradle.api.Task;
30-
import org.gradle.api.artifacts.Configuration;
3130
import org.gradle.api.file.FileCollection;
3231
import org.gradle.api.internal.artifacts.dsl.LazyPublishArtifact;
3332
import org.gradle.api.plugins.ApplicationPlugin;
@@ -94,9 +93,6 @@ private TaskProvider<BootJar> configureBootJarTask(Project project) {
9493
SourceSet mainSourceSet = javaPluginConvention(project).getSourceSets()
9594
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
9695
bootJar.classpath((Callable<FileCollection>) mainSourceSet::getRuntimeClasspath);
97-
Configuration runtimeClasspathConfiguration = project.getConfigurations()
98-
.getByName(mainSourceSet.getRuntimeClasspathConfigurationName());
99-
runtimeClasspathConfiguration.getIncoming().afterResolve(bootJar::resolvedDependencies);
10096
bootJar.conventionMapping("mainClassName", new MainClassConvention(project, bootJar::getClasspath));
10197
});
10298
}

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootArchiveSupport.java

Lines changed: 73 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@
2727
import java.util.TreeMap;
2828
import java.util.function.Function;
2929

30+
import org.gradle.api.file.CopySpec;
3031
import org.gradle.api.file.FileCopyDetails;
3132
import org.gradle.api.file.FileTreeElement;
3233
import org.gradle.api.file.RelativePath;
3334
import org.gradle.api.internal.file.copy.CopyAction;
3435
import org.gradle.api.internal.file.copy.CopyActionProcessingStream;
3536
import org.gradle.api.internal.file.copy.FileCopyDetailsInternal;
3637
import org.gradle.api.java.archives.Attributes;
38+
import org.gradle.api.java.archives.Manifest;
3739
import org.gradle.api.specs.Spec;
3840
import org.gradle.api.specs.Specs;
3941
import org.gradle.api.tasks.WorkResult;
@@ -44,6 +46,9 @@
4446
* Support class for implementations of {@link BootArchive}.
4547
*
4648
* @author Andy Wilkinson
49+
* @author Phillip Webb
50+
* @see BootJar
51+
* @see BootWar
4752
*/
4853
class BootArchiveSupport {
4954

@@ -61,46 +66,71 @@ class BootArchiveSupport {
6166

6267
private final PatternSet requiresUnpack = new PatternSet();
6368

64-
private final Function<FileCopyDetails, ZipCompression> compressionResolver;
65-
6669
private final PatternSet exclusions = new PatternSet();
6770

6871
private final String loaderMainClass;
6972

73+
private final Spec<FileCopyDetails> librarySpec;
74+
75+
private final Function<FileCopyDetails, ZipCompression> compressionResolver;
76+
7077
private LaunchScriptConfiguration launchScript;
7178

7279
private boolean excludeDevtools = true;
7380

74-
BootArchiveSupport(String loaderMainClass, Function<FileCopyDetails, ZipCompression> compressionResolver) {
81+
BootArchiveSupport(String loaderMainClass, Spec<FileCopyDetails> librarySpec,
82+
Function<FileCopyDetails, ZipCompression> compressionResolver) {
7583
this.loaderMainClass = loaderMainClass;
84+
this.librarySpec = librarySpec;
7685
this.compressionResolver = compressionResolver;
7786
this.requiresUnpack.include(Specs.satisfyNone());
7887
configureExclusions();
7988
}
8089

81-
void configureManifest(Jar jar, String mainClassName, String springBootClasses, String springBootLib) {
82-
Attributes attributes = jar.getManifest().getAttributes();
90+
void configureManifest(Manifest manifest, String mainClass, String classes, String lib, String classPathIndex,
91+
String layersIndex) {
92+
Attributes attributes = manifest.getAttributes();
8393
attributes.putIfAbsent("Main-Class", this.loaderMainClass);
84-
attributes.putIfAbsent("Start-Class", mainClassName);
85-
attributes.computeIfAbsent("Spring-Boot-Version", (key) -> determineSpringBootVersion());
86-
attributes.putIfAbsent("Spring-Boot-Classes", springBootClasses);
87-
attributes.putIfAbsent("Spring-Boot-Lib", springBootLib);
94+
attributes.putIfAbsent("Start-Class", mainClass);
95+
attributes.computeIfAbsent("Spring-Boot-Version", (name) -> determineSpringBootVersion());
96+
if (classes != null) {
97+
attributes.putIfAbsent("Spring-Boot-Classes", classes);
98+
}
99+
if (lib != null) {
100+
attributes.putIfAbsent("Spring-Boot-Lib", lib);
101+
}
102+
if (classPathIndex != null) {
103+
attributes.putIfAbsent("Spring-Boot-Classpath-Index", classPathIndex);
104+
}
105+
if (layersIndex != null) {
106+
attributes.putIfAbsent("Spring-Boot-Layers-Index", layersIndex);
107+
}
88108
}
89109

90110
private String determineSpringBootVersion() {
91-
String implementationVersion = getClass().getPackage().getImplementationVersion();
92-
return (implementationVersion != null) ? implementationVersion : "unknown";
111+
String version = getClass().getPackage().getImplementationVersion();
112+
return (version != null) ? version : "unknown";
93113
}
94114

95115
CopyAction createCopyAction(Jar jar) {
96-
CopyAction copyAction = new BootZipCopyAction(jar.getArchiveFile().get().getAsFile(),
97-
jar.isPreserveFileTimestamps(), isUsingDefaultLoader(jar), this.requiresUnpack.getAsSpec(),
98-
this.exclusions.getAsExcludeSpec(), this.launchScript, this.compressionResolver,
99-
jar.getMetadataCharset());
100-
if (!jar.isReproducibleFileOrder()) {
101-
return copyAction;
102-
}
103-
return new ReproducibleOrderingCopyAction(copyAction);
116+
return createCopyAction(jar, null, false);
117+
}
118+
119+
CopyAction createCopyAction(Jar jar, LayerResolver layerResolver, boolean includeLayerTools) {
120+
File output = jar.getArchiveFile().get().getAsFile();
121+
Manifest manifest = jar.getManifest();
122+
boolean preserveFileTimestamps = jar.isPreserveFileTimestamps();
123+
boolean includeDefaultLoader = isUsingDefaultLoader(jar);
124+
Spec<FileTreeElement> requiresUnpack = this.requiresUnpack.getAsSpec();
125+
Spec<FileTreeElement> exclusions = this.exclusions.getAsExcludeSpec();
126+
LaunchScriptConfiguration launchScript = this.launchScript;
127+
Spec<FileCopyDetails> librarySpec = this.librarySpec;
128+
Function<FileCopyDetails, ZipCompression> compressionResolver = this.compressionResolver;
129+
String encoding = jar.getMetadataCharset();
130+
CopyAction action = new BootZipCopyAction(output, manifest, preserveFileTimestamps, includeDefaultLoader,
131+
includeLayerTools, requiresUnpack, exclusions, launchScript, librarySpec, compressionResolver, encoding,
132+
layerResolver);
133+
return jar.isReproducibleFileOrder() ? new ReproducibleOrderingCopyAction(action) : action;
104134
}
105135

106136
private boolean isUsingDefaultLoader(Jar jar) {
@@ -132,7 +162,19 @@ void setExcludeDevtools(boolean excludeDevtools) {
132162
configureExclusions();
133163
}
134164

135-
boolean isZip(File file) {
165+
void excludeNonZipLibraryFiles(FileCopyDetails details) {
166+
if (this.librarySpec.isSatisfiedBy(details)) {
167+
excludeNonZipFiles(details);
168+
}
169+
}
170+
171+
void excludeNonZipFiles(FileCopyDetails details) {
172+
if (!isZip(details.getFile())) {
173+
details.exclude();
174+
}
175+
}
176+
177+
private boolean isZip(File file) {
136178
try {
137179
try (FileInputStream fileInputStream = new FileInputStream(file)) {
138180
return isZip(fileInputStream);
@@ -160,6 +202,17 @@ private void configureExclusions() {
160202
this.exclusions.setExcludes(excludes);
161203
}
162204

205+
void moveModuleInfoToRoot(CopySpec spec) {
206+
spec.filesMatching("module-info.class", BootArchiveSupport::moveToRoot);
207+
}
208+
209+
private static void moveToRoot(FileCopyDetails details) {
210+
details.setRelativePath(details.getRelativeSourcePath());
211+
}
212+
213+
/**
214+
* {@link CopyAction} variant that sorts entries to ensure reproducible ordering.
215+
*/
163216
private static final class ReproducibleOrderingCopyAction implements CopyAction {
164217

165218
private final CopyAction delegate;

0 commit comments

Comments
 (0)