Browse Source

Fix reusable archive creation with Gradle 4.1 and later

Closes gh-11468
pull/11460/merge
Andy Wilkinson 8 years ago
parent
commit
b545330d8e
  1. 25
      spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java
  2. 16
      spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java
  3. 14
      spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-reproducibleArchive.gradle
  4. 14
      spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-reproducibleArchive.gradle

25
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/BootZipCopyAction.java

@ -20,6 +20,8 @@ import java.io.File; @@ -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; @@ -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; @@ -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 { @@ -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 { @@ -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 { @@ -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;
}
}

16
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/java/org/springframework/boot/gradle/tasks/bundling/AbstractBootArchiveIntegrationTests.java

@ -29,6 +29,7 @@ import org.junit.runner.RunWith; @@ -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 { @@ -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 {

14
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootJarIntegrationTests-reproducibleArchive.gradle

@ -0,0 +1,14 @@ @@ -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
}

14
spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/test/resources/org/springframework/boot/gradle/tasks/bundling/BootWarIntegrationTests-reproducibleArchive.gradle

@ -0,0 +1,14 @@ @@ -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…
Cancel
Save