Add support for creating layered war files with Maven

See gh-22821
This commit is contained in:
Madhura Bhave
2021-01-28 12:39:19 -08:00
parent fd27c26e3b
commit 152698f2b2
47 changed files with 902 additions and 128 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
@@ -36,7 +36,7 @@ import org.springframework.util.Assert;
*/
class Context {
private final File jarFile;
private final File archiveFile;
private final File workingDir;
@@ -46,23 +46,31 @@ class Context {
* Create a new {@link Context} instance.
*/
Context() {
this(getSourceJarFile(), Paths.get(".").toAbsolutePath().normalize().toFile());
this(getSourceArchiveFile(), Paths.get(".").toAbsolutePath().normalize().toFile());
}
/**
* Create a new {@link Context} instance with the specified value.
* @param jarFile the source jar file
* @param archiveFile the source archive file
* @param workingDir the working directory
*/
Context(File jarFile, File workingDir) {
Assert.state(jarFile != null && jarFile.isFile() && jarFile.exists()
&& jarFile.getName().toLowerCase().endsWith(".jar"), "Unable to find source JAR");
this.jarFile = jarFile;
Context(File archiveFile, File workingDir) {
Assert.state(isExistingFile(archiveFile) && isJarOrWar(archiveFile), "Unable to find source archive");
this.archiveFile = archiveFile;
this.workingDir = workingDir;
this.relativeDir = deduceRelativeDir(jarFile.getParentFile(), this.workingDir);
this.relativeDir = deduceRelativeDir(archiveFile.getParentFile(), this.workingDir);
}
private static File getSourceJarFile() {
private boolean isExistingFile(File archiveFile) {
return archiveFile != null && archiveFile.isFile() && archiveFile.exists();
}
private boolean isJarOrWar(File jarFile) {
String name = jarFile.getName().toLowerCase();
return name.endsWith(".jar") || name.endsWith(".war");
}
private static File getSourceArchiveFile() {
try {
ProtectionDomain domain = Context.class.getProtectionDomain();
CodeSource codeSource = (domain != null) ? domain.getCodeSource() : null;
@@ -106,11 +114,11 @@ class Context {
}
/**
* Return the source jar file that is running in tools mode.
* @return the jar file
* Return the source archive file that is running in tools mode.
* @return the archive file
*/
File getJarFile() {
return this.jarFile;
File getArchiveFile() {
return this.archiveFile;
}
/**
@@ -122,11 +130,11 @@ class Context {
}
/**
* Return the directory relative to {@link #getWorkingDir()} that contains the jar or
* Return the directory relative to {@link #getWorkingDir()} that contains the archive or
* {@code null} if none relative directory can be deduced.
* @return the relative dir ending in {@code /} or {@code null}
*/
String getRelativeJarDir() {
String getRelativeArchiveDir() {
return this.relativeDir;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
@@ -65,9 +65,9 @@ class ExtractCommand extends Command {
mkDirs(new File(destination, layer));
}
}
try (ZipInputStream zip = new ZipInputStream(new FileInputStream(this.context.getJarFile()))) {
try (ZipInputStream zip = new ZipInputStream(new FileInputStream(this.context.getArchiveFile()))) {
ZipEntry entry = zip.getNextEntry();
Assert.state(entry != null, "File '" + this.context.getJarFile().toString()
Assert.state(entry != null, "File '" + this.context.getArchiveFile().toString()
+ "' is not compatible with layertools; ensure jar file is valid and launch script is not enabled");
while (entry != null) {
if (!entry.isDirectory()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
@@ -99,7 +99,7 @@ class HelpCommand extends Command {
}
private String getJavaCommand() {
return "java -Djarmode=layertools -jar " + this.context.getJarFile().getName();
return "java -Djarmode=layertools -jar " + this.context.getArchiveFile().getName();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2021 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.
@@ -27,6 +27,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import org.springframework.util.Assert;
@@ -34,7 +35,7 @@ import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
/**
* {@link Layers} implementation backed by a {@code BOOT-INF/layers.idx} file.
* {@link Layers} implementation backed by a {@code layers.idx} file.
*
* @author Phillip Webb
* @author Madhura Bhave
@@ -91,8 +92,10 @@ class IndexedLayers implements Layers {
*/
static IndexedLayers get(Context context) {
try {
try (JarFile jarFile = new JarFile(context.getJarFile())) {
ZipEntry entry = jarFile.getEntry("BOOT-INF/layers.idx");
try (JarFile jarFile = new JarFile(context.getArchiveFile())) {
Manifest manifest = jarFile.getManifest();
String location = manifest.getMainAttributes().getValue("Spring-Boot-Layers-Index");
ZipEntry entry = (location != null) ? jarFile.getEntry(location) : null;
if (entry != null) {
String indexFile = StreamUtils.copyToString(jarFile.getInputStream(entry), StandardCharsets.UTF_8);
return new IndexedLayers(indexFile);