Set timestamps of nested jars

Update JarWriter to set the entry timestamp for nested jars. The
timestamp is set to same time as the first (non directory) entry in
the nested jar.

This change should make it easier to created layered docker images.

Fixes gh-2807
This commit is contained in:
Phillip Webb 2015-04-16 21:16:30 -07:00
parent a6644991be
commit 2176afb49e
3 changed files with 50 additions and 4 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-2015 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.
@ -162,6 +162,7 @@ public class JarWriter {
throws IOException {
File file = library.getFile();
JarEntry entry = new JarEntry(destination + library.getName());
entry.setTime(getNestedLibraryTime(file));
if (library.isUnpackRequired()) {
entry.setComment("UNPACK:" + FileUtils.sha1Hash(file));
}
@ -169,6 +170,28 @@ public class JarWriter {
writeEntry(entry, new InputStreamEntryWriter(new FileInputStream(file), true));
}
private long getNestedLibraryTime(File file) {
try {
JarFile jarFile = new JarFile(file);
try {
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry entry = entries.nextElement();
if (!entry.isDirectory()) {
return entry.getTime();
}
}
}
finally {
jarFile.close();
}
}
catch (Exception ex) {
// Ignore and just use the source file timestamp
}
return file.lastModified();
}
/**
* Write the required spring-boot-loader classes to the JAR.
* @throws IOException

View File

@ -20,6 +20,7 @@ import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Calendar;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
@ -58,6 +59,17 @@ public class RepackagerTests {
}
};
private static final long JAN_1_1980;
private static final long JAN_1_1985;
static {
Calendar calendar = Calendar.getInstance();
calendar.set(1980, 0, 1, 0, 0, 0);
calendar.set(Calendar.MILLISECOND, 0);
JAN_1_1980 = calendar.getTime().getTime();
calendar.set(Calendar.YEAR, 1985);
JAN_1_1985 = calendar.getTime().getTime();
}
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
@ -275,7 +287,7 @@ public class RepackagerTests {
@Test
public void libraries() throws Exception {
TestJarFile libJar = new TestJarFile(this.temporaryFolder);
libJar.addClass("a/b/C.class", ClassWithoutMainMethod.class);
libJar.addClass("a/b/C.class", ClassWithoutMainMethod.class, JAN_1_1985);
final File libJarFile = libJar.getFile();
final File libJarFileToUnpack = libJar.getFile();
final File libNonJarFile = this.temporaryFolder.newFile();
@ -284,6 +296,7 @@ public class RepackagerTests {
this.testJarFile.addFile("lib/" + libJarFileToUnpack.getName(),
libJarFileToUnpack);
File file = this.testJarFile.getFile();
libJarFile.setLastModified(JAN_1_1980);
Repackager repackager = new Repackager(file);
repackager.repackage(new Libraries() {
@Override
@ -297,7 +310,9 @@ public class RepackagerTests {
assertThat(hasEntry(file, "lib/" + libJarFile.getName()), equalTo(true));
assertThat(hasEntry(file, "lib/" + libJarFileToUnpack.getName()), equalTo(true));
assertThat(hasEntry(file, "lib/" + libNonJarFile.getName()), equalTo(false));
JarEntry entry = getEntry(file, "lib/" + libJarFileToUnpack.getName());
JarEntry entry = getEntry(file, "lib/" + libJarFile.getName());
assertThat(entry.getTime(), equalTo(JAN_1_1985));
entry = getEntry(file, "lib/" + libJarFileToUnpack.getName());
assertThat(entry.getComment(), startsWith("UNPACK:"));
assertThat(entry.getComment().length(), equalTo(47));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-2015 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.
@ -46,11 +46,19 @@ public class TestJarFile {
}
public void addClass(String filename, Class<?> classToCopy) throws IOException {
addClass(filename, classToCopy, null);
}
public void addClass(String filename, Class<?> classToCopy, Long time)
throws IOException {
File file = getFilePath(filename);
file.getParentFile().mkdirs();
InputStream inputStream = getClass().getResourceAsStream(
"/" + classToCopy.getName().replace(".", "/") + ".class");
copyToFile(inputStream, file);
if (time != null) {
file.setLastModified(time);
}
}
public void addFile(String filename, File fileToCopy) throws IOException {