Commit fa186aa1 authored by Scott Frederick's avatar Scott Frederick

Preserve timestamps on loader directories

Prior to this commit, when the Maven plugin copied
spring-boot-loader.jar to a repackaged archive the timestamps of class
files were preserved but the timestamps of directories were not
preserved. This resulted in the directories having a current timestamp.

This commit copies the directory timestamps from spring-boot-loader.jar
to the repackaged archive and adds tests to verify the proper
behavior.

See gh-20927
parent e83c3b87
...@@ -209,13 +209,21 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter { ...@@ -209,13 +209,21 @@ public abstract class AbstractJarWriter implements LoaderClassesWriter {
try (JarInputStream inputStream = new JarInputStream(new BufferedInputStream(loaderJar.openStream()))) { try (JarInputStream inputStream = new JarInputStream(new BufferedInputStream(loaderJar.openStream()))) {
JarEntry entry; JarEntry entry;
while ((entry = inputStream.getNextJarEntry()) != null) { while ((entry = inputStream.getNextJarEntry()) != null) {
if (entry.getName().endsWith(".class")) { if (isDirectoryEntry(entry) || isClassEntry(entry)) {
writeEntry(new JarArchiveEntry(entry), new InputStreamEntryWriter(inputStream)); writeEntry(new JarArchiveEntry(entry), new InputStreamEntryWriter(inputStream));
} }
} }
} }
} }
private boolean isDirectoryEntry(JarEntry entry) {
return entry.isDirectory() && !entry.getName().equals("META-INF/");
}
private boolean isClassEntry(JarEntry entry) {
return entry.getName().endsWith(".class");
}
private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter) throws IOException { private void writeEntry(JarArchiveEntry entry, EntryWriter entryWriter) throws IOException {
writeEntry(entry, entryWriter, UnpackHandler.NEVER); writeEntry(entry, entryWriter, UnpackHandler.NEVER);
} }
......
...@@ -20,7 +20,10 @@ import java.io.File; ...@@ -20,7 +20,10 @@ import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.attribute.FileTime;
import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermission;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Enumeration; import java.util.Enumeration;
...@@ -156,6 +159,36 @@ class RepackagerTests extends AbstractPackagerTests<Repackager> { ...@@ -156,6 +159,36 @@ class RepackagerTests extends AbstractPackagerTests<Repackager> {
} }
} }
@Test
void allLoaderDirectoriesAndFilesUseSameTimestamp() throws IOException {
this.testJarFile.addClass("A.class", ClassWithMainMethod.class);
Repackager repackager = createRepackager(this.testJarFile.getFile(), true);
Long timestamp = null;
repackager.repackage(this.destination, NO_LIBRARIES);
for (ZipArchiveEntry entry : getAllPackagedEntries()) {
if (entry.getName().startsWith("org/springframework/boot/loader")) {
if (timestamp == null) {
timestamp = entry.getTime();
}
else {
assertThat(entry.getTime()).withFailMessage("Expected time %d to be equal to %d for entry %s",
entry.getTime(), timestamp, entry.getName()).isEqualTo(timestamp);
}
}
}
}
@Test
void allEntriesUseProvidedTimestamp() throws IOException {
this.testJarFile.addClass("A.class", ClassWithMainMethod.class);
Repackager repackager = createRepackager(this.testJarFile.getFile(), true);
long timestamp = OffsetDateTime.of(2000, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC).toInstant().toEpochMilli();
repackager.repackage(this.destination, NO_LIBRARIES, null, FileTime.fromMillis(timestamp));
for (ZipArchiveEntry entry : getAllPackagedEntries()) {
assertThat(entry.getTime()).isEqualTo(timestamp);
}
}
private boolean hasLauncherClasses(File file) throws IOException { private boolean hasLauncherClasses(File file) throws IOException {
return hasEntry(file, "org/springframework/boot/") return hasEntry(file, "org/springframework/boot/")
&& hasEntry(file, "org/springframework/boot/loader/JarLauncher.class"); && hasEntry(file, "org/springframework/boot/loader/JarLauncher.class");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment