Fix reusable archive creation with Gradle 4.1 and later
Closes gh-11468
This commit is contained in:
parent
a6c301edb4
commit
b545330d8e
|
|
@ -20,6 +20,8 @@ import java.io.File;
|
|||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
|
@ -39,7 +41,6 @@ import org.gradle.api.internal.file.copy.FileCopyDetailsInternal;
|
|||
import org.gradle.api.specs.Spec;
|
||||
import org.gradle.api.specs.Specs;
|
||||
import org.gradle.api.tasks.WorkResult;
|
||||
import org.gradle.util.GUtil;
|
||||
|
||||
import org.springframework.boot.loader.tools.DefaultLaunchScript;
|
||||
import org.springframework.boot.loader.tools.FileUtils;
|
||||
|
|
@ -52,6 +53,9 @@ import org.springframework.boot.loader.tools.FileUtils;
|
|||
*/
|
||||
class BootZipCopyAction implements CopyAction {
|
||||
|
||||
private static final long CONSTANT_TIME_FOR_ZIP_ENTRIES = new GregorianCalendar(1980,
|
||||
Calendar.FEBRUARY, 1, 0, 0, 0).getTimeInMillis();
|
||||
|
||||
private final File output;
|
||||
|
||||
private final boolean preserveFileTimestamps;
|
||||
|
|
@ -158,20 +162,14 @@ class BootZipCopyAction implements CopyAction {
|
|||
|
||||
private void writeDirectory(ZipArchiveEntry entry, ZipArchiveOutputStream out)
|
||||
throws IOException {
|
||||
if (!this.preserveFileTimestamps) {
|
||||
entry.setTime(GUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES);
|
||||
}
|
||||
entry.setUnixMode(UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM);
|
||||
prepareEntry(entry, UnixStat.DIR_FLAG | UnixStat.DEFAULT_DIR_PERM);
|
||||
out.putArchiveEntry(entry);
|
||||
out.closeArchiveEntry();
|
||||
}
|
||||
|
||||
private void writeClass(ZipArchiveEntry entry, ZipInputStream in,
|
||||
ZipArchiveOutputStream out) throws IOException {
|
||||
if (!this.preserveFileTimestamps) {
|
||||
entry.setTime(GUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES);
|
||||
}
|
||||
entry.setUnixMode(UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM);
|
||||
prepareEntry(entry, UnixStat.FILE_FLAG | UnixStat.DEFAULT_FILE_PERM);
|
||||
out.putArchiveEntry(entry);
|
||||
byte[] buffer = new byte[4096];
|
||||
int read;
|
||||
|
|
@ -181,6 +179,13 @@ class BootZipCopyAction implements CopyAction {
|
|||
out.closeArchiveEntry();
|
||||
}
|
||||
|
||||
private void prepareEntry(ZipArchiveEntry entry, int unixMode) {
|
||||
if (!this.preserveFileTimestamps) {
|
||||
entry.setTime(CONSTANT_TIME_FOR_ZIP_ENTRIES);
|
||||
}
|
||||
entry.setUnixMode(unixMode);
|
||||
}
|
||||
|
||||
private void writeLaunchScriptIfNecessary(FileOutputStream fileStream) {
|
||||
try {
|
||||
if (this.launchScript != null) {
|
||||
|
|
@ -280,7 +285,7 @@ class BootZipCopyAction implements CopyAction {
|
|||
|
||||
private long getTime(FileCopyDetails details) {
|
||||
return this.preserveFileTimestamps ? details.getLastModified()
|
||||
: GUtil.CONSTANT_TIME_FOR_ZIP_ENTRIES;
|
||||
: CONSTANT_TIME_FOR_ZIP_ENTRIES;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import org.junit.runner.RunWith;
|
|||
|
||||
import org.springframework.boot.gradle.junit.GradleCompatibilitySuite;
|
||||
import org.springframework.boot.gradle.testkit.GradleBuild;
|
||||
import org.springframework.boot.loader.tools.FileUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
|
|
@ -56,6 +57,21 @@ public abstract class AbstractBootArchiveIntegrationTests {
|
|||
.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void reproducibleArchive() throws InvalidRunnerConfigurationException,
|
||||
UnexpectedBuildFailure, IOException, InterruptedException {
|
||||
assertThat(this.gradleBuild.build(this.taskName).task(":" + this.taskName)
|
||||
.getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
File jar = new File(this.gradleBuild.getProjectDir(), "build/libs")
|
||||
.listFiles()[0];
|
||||
String firstHash = FileUtils.sha1Hash(jar);
|
||||
Thread.sleep(1500);
|
||||
assertThat(this.gradleBuild.build("clean", this.taskName)
|
||||
.task(":" + this.taskName).getOutcome()).isEqualTo(TaskOutcome.SUCCESS);
|
||||
String secondHash = FileUtils.sha1Hash(jar);
|
||||
assertThat(firstHash).isEqualTo(secondHash);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void upToDateWhenBuiltTwice() throws InvalidRunnerConfigurationException,
|
||||
UnexpectedBuildFailure, IOException {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
buildscript {
|
||||
dependencies {
|
||||
classpath files(pluginClasspath.split(','))
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'java'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
|
||||
bootJar {
|
||||
mainClassName = 'com.example.Application'
|
||||
preserveFileTimestamps = false
|
||||
reproducibleFileOrder = true
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
buildscript {
|
||||
dependencies {
|
||||
classpath files(pluginClasspath.split(','))
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'war'
|
||||
apply plugin: 'org.springframework.boot'
|
||||
|
||||
bootWar {
|
||||
mainClassName = 'com.example.Application'
|
||||
preserveFileTimestamps = false
|
||||
reproducibleFileOrder = true
|
||||
}
|
||||
Loading…
Reference in New Issue