Use YAML compatible classpath.idx format
Update the `classpath.idx` format to align with `layers.idx` and allow third-parties can parse it as YAML Closes gh-20861
This commit is contained in:
@@ -26,9 +26,11 @@ import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
import org.apache.commons.compress.archivers.zip.UnixStat;
|
||||
@@ -345,8 +347,9 @@ class BootZipCopyAction implements CopyAction {
|
||||
Attributes manifestAttributes = BootZipCopyAction.this.manifest.getAttributes();
|
||||
String classPathIndex = (String) manifestAttributes.get("Spring-Boot-Classpath-Index");
|
||||
if (classPathIndex != null) {
|
||||
writeEntry(classPathIndex,
|
||||
ZipEntryWriter.fromLines(BootZipCopyAction.this.encoding, this.writtenLibraries), true);
|
||||
List<String> lines = this.writtenLibraries.stream().map((line) -> "- \"" + line + "\"")
|
||||
.collect(Collectors.toList());
|
||||
writeEntry(classPathIndex, ZipEntryWriter.fromLines(BootZipCopyAction.this.encoding, lines), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,8 +185,8 @@ class BootJarTests extends AbstractBootArchiveTests<TestBootJar> {
|
||||
@Test
|
||||
void whenJarIsLayeredClasspathIndexPointsToLayeredLibs() throws IOException {
|
||||
try (JarFile jarFile = new JarFile(createLayeredJar())) {
|
||||
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly("first-library.jar",
|
||||
"second-library.jar", "third-library-SNAPSHOT.jar");
|
||||
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly("- \"first-library.jar\"",
|
||||
"- \"second-library.jar\"", "- \"third-library-SNAPSHOT.jar\"");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,8 +208,8 @@ class BootJarTests extends AbstractBootArchiveTests<TestBootJar> {
|
||||
try (JarFile jarFile = new JarFile(createPopulatedJar())) {
|
||||
assertThat(jarFile.getManifest().getMainAttributes().getValue("Spring-Boot-Classpath-Index"))
|
||||
.isEqualTo("BOOT-INF/classpath.idx");
|
||||
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly("first-library.jar",
|
||||
"second-library.jar", "third-library-SNAPSHOT.jar");
|
||||
assertThat(entryLines(jarFile, "BOOT-INF/classpath.idx")).containsExactly("- \"first-library.jar\"",
|
||||
"- \"second-library.jar\"", "- \"third-library-SNAPSHOT.jar\"");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -505,7 +505,8 @@ public abstract class Packager {
|
||||
}
|
||||
|
||||
private void writeClasspathIndex(RepackagingLayout layout, AbstractJarWriter writer) throws IOException {
|
||||
List<String> names = this.libraries.keySet().stream().map(this::getJarName).collect(Collectors.toList());
|
||||
List<String> names = this.libraries.keySet().stream().map(this::getJarName)
|
||||
.map((name) -> "- \"" + name + "\"").collect(Collectors.toList());
|
||||
writer.writeIndexFile(layout.getClasspathIndexFileLocation(), names);
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ abstract class AbstractPackagerTests<P extends Packager> {
|
||||
}
|
||||
|
||||
@Test
|
||||
void index() throws Exception {
|
||||
void classPathIndex() throws Exception {
|
||||
TestJarFile libJar1 = new TestJarFile(this.tempDir);
|
||||
libJar1.addClass("a/b/C.class", ClassWithoutMainMethod.class, JAN_1_1985);
|
||||
File libJarFile1 = libJar1.getFile();
|
||||
@@ -233,8 +233,9 @@ abstract class AbstractPackagerTests<P extends Packager> {
|
||||
assertThat(hasPackagedEntry("BOOT-INF/classpath.idx")).isTrue();
|
||||
String index = getPackagedEntryContent("BOOT-INF/classpath.idx");
|
||||
String[] libraries = index.split("\\r?\\n");
|
||||
assertThat(Arrays.asList(libraries)).contains(libJarFile1.getName(), libJarFile2.getName(),
|
||||
libJarFile3.getName());
|
||||
List<String> expected = Stream.of(libJarFile1, libJarFile2, libJarFile3)
|
||||
.map((jar) -> "- \"" + jar.getName() + "\"").collect(Collectors.toList());
|
||||
assertThat(Arrays.asList(libraries)).containsExactlyElementsOf(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -263,8 +264,9 @@ abstract class AbstractPackagerTests<P extends Packager> {
|
||||
});
|
||||
assertThat(hasPackagedEntry("BOOT-INF/classpath.idx")).isTrue();
|
||||
String classpathIndex = getPackagedEntryContent("BOOT-INF/classpath.idx");
|
||||
assertThat(Arrays.asList(classpathIndex.split("\\n"))).containsExactly(libJarFile1.getName(),
|
||||
libJarFile2.getName(), libJarFile3.getName());
|
||||
List<String> expectedClasspathIndex = Stream.of(libJarFile1, libJarFile2, libJarFile3)
|
||||
.map((file) -> "- \"" + file.getName() + "\"").collect(Collectors.toList());
|
||||
assertThat(Arrays.asList(classpathIndex.split("\\n"))).containsExactlyElementsOf(expectedClasspathIndex);
|
||||
assertThat(hasPackagedEntry("BOOT-INF/layers.idx")).isTrue();
|
||||
String layersIndex = getPackagedEntryContent("BOOT-INF/layers.idx");
|
||||
List<String> expectedLayers = new ArrayList<>();
|
||||
@@ -293,7 +295,8 @@ abstract class AbstractPackagerTests<P extends Packager> {
|
||||
execute(packager, Libraries.NONE);
|
||||
assertThat(hasPackagedEntry("BOOT-INF/classpath.idx")).isTrue();
|
||||
String classpathIndex = getPackagedEntryContent("BOOT-INF/classpath.idx");
|
||||
assertThat(Arrays.asList(classpathIndex.split("\\n"))).containsExactly("spring-boot-jarmode-layertools.jar");
|
||||
assertThat(Arrays.asList(classpathIndex.split("\\n")))
|
||||
.containsExactly("- \"spring-boot-jarmode-layertools.jar\"");
|
||||
assertThat(hasPackagedEntry("BOOT-INF/layers.idx")).isTrue();
|
||||
String layersIndex = getPackagedEntryContent("BOOT-INF/layers.idx");
|
||||
List<String> expectedLayers = new ArrayList<>();
|
||||
|
||||
@@ -31,6 +31,8 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A class path index file that provides ordering information for JARs.
|
||||
*
|
||||
@@ -45,7 +47,12 @@ final class ClassPathIndexFile {
|
||||
|
||||
private ClassPathIndexFile(File root, List<String> lines) {
|
||||
this.root = root;
|
||||
this.lines = lines;
|
||||
this.lines = lines.stream().map(this::extractName).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String extractName(String line) {
|
||||
Assert.state(line.startsWith("- \"") && line.endsWith("\""), "Malformed classpath index line [" + line + "]");
|
||||
return line.substring(3, line.length() - 1);
|
||||
}
|
||||
|
||||
int size() {
|
||||
|
||||
@@ -68,9 +68,9 @@ public abstract class AbstractExecutableArchiveLauncherTests {
|
||||
JarEntry indexEntry = new JarEntry(entryPrefix + "/classpath.idx");
|
||||
jarOutputStream.putNextEntry(indexEntry);
|
||||
Writer writer = new OutputStreamWriter(jarOutputStream, StandardCharsets.UTF_8);
|
||||
writer.write("BOOT-INF/lib/foo.jar\n");
|
||||
writer.write("BOOT-INF/lib/bar.jar\n");
|
||||
writer.write("BOOT-INF/lib/baz.jar\n");
|
||||
writer.write("- \"BOOT-INF/lib/foo.jar\"\n");
|
||||
writer.write("- \"BOOT-INF/lib/bar.jar\"\n");
|
||||
writer.write("- \"BOOT-INF/lib/baz.jar\"\n");
|
||||
writer.flush();
|
||||
}
|
||||
addNestedJars(entryPrefix, "/lib/foo.jar", jarOutputStream);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
a.jar
|
||||
b.jar
|
||||
c.jar
|
||||
d.jar
|
||||
e.jar
|
||||
- "a.jar"
|
||||
- "b.jar"
|
||||
- "c.jar"
|
||||
- "d.jar"
|
||||
- "e.jar"
|
||||
|
||||
Reference in New Issue
Block a user