Skip to content

Commit bc6774c

Browse files
committed
Propagate project.build.outputTimestamp to our packaging
This improves the reproducibility of the zip files.
1 parent 545907d commit bc6774c

File tree

3 files changed

+25
-11
lines changed

3 files changed

+25
-11
lines changed

core/deployment/src/main/java/io/quarkus/deployment/pkg/PackageConfig.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.quarkus.deployment.pkg;
22

33
import java.nio.file.Path;
4+
import java.time.Instant;
45
import java.util.List;
56
import java.util.Map;
67
import java.util.Optional;
@@ -49,6 +50,13 @@ public interface PackageConfig {
4950
*/
5051
Optional<String> outputName();
5152

53+
/**
54+
* The timestamp used as a reference for generating the packages (e.g. for the creation timestamp of ZIP entries).
55+
* <p>
56+
* The approach is similar to what is done by the maven-jar-plugin with `project.build.outputTimestamp`.
57+
*/
58+
Optional<Instant> outputTimestamp();
59+
5260
/**
5361
* Setting this switch to {@code true} will cause Quarkus to write the transformed application bytecode
5462
* to the build tool's output directory.

core/deployment/src/main/java/io/quarkus/deployment/pkg/steps/JarResultBuildStep.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -350,7 +350,7 @@ private void buildUberJar0(CurateOutcomeBuildItem curateOutcomeBuildItem,
350350
MainClassBuildItem mainClassBuildItem,
351351
ClassLoadingConfig classLoadingConfig,
352352
Path runnerJar) throws Exception {
353-
try (FileSystem runnerZipFs = createNewZip(runnerJar, packageConfig)) {
353+
try (FileSystem runnerZipFs = createNewReproducibleZipFileSystem(runnerJar, packageConfig)) {
354354

355355
log.info("Building uber jar: " + runnerJar);
356356

@@ -549,7 +549,7 @@ private JarBuildItem buildLegacyThinJar(CurateOutcomeBuildItem curateOutcomeBuil
549549
Files.deleteIfExists(runnerJar);
550550
IoUtils.createOrEmptyDir(libDir);
551551

552-
try (FileSystem runnerZipFs = createNewZip(runnerJar, packageConfig)) {
552+
try (FileSystem runnerZipFs = createNewReproducibleZipFileSystem(runnerJar, packageConfig)) {
553553

554554
log.info("Building thin jar: " + runnerJar);
555555

@@ -647,7 +647,7 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
647647
if (!transformedClasses.getTransformedClassesByJar().isEmpty()) {
648648
Path transformedZip = quarkus.resolve(TRANSFORMED_BYTECODE_JAR);
649649
fastJarJarsBuilder.setTransformed(transformedZip);
650-
try (FileSystem out = createNewZip(transformedZip, packageConfig)) {
650+
try (FileSystem out = createNewReproducibleZipFileSystem(transformedZip, packageConfig)) {
651651
for (Set<TransformedClassesBuildItem.TransformedClass> transformedSet : transformedClasses
652652
.getTransformedClassesByJar().values()) {
653653
for (TransformedClassesBuildItem.TransformedClass transformed : transformedSet) {
@@ -668,7 +668,7 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
668668
//now generated classes and resources
669669
Path generatedZip = quarkus.resolve(GENERATED_BYTECODE_JAR);
670670
fastJarJarsBuilder.setGenerated(generatedZip);
671-
try (FileSystem out = createNewZip(generatedZip, packageConfig)) {
671+
try (FileSystem out = createNewReproducibleZipFileSystem(generatedZip, packageConfig)) {
672672
for (GeneratedClassBuildItem i : generatedClasses) {
673673
String fileName = fromClassNameToResourceName(i.getName());
674674
Path target = out.getPath(fileName);
@@ -703,7 +703,7 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
703703
.setResolvedDependency(applicationArchivesBuildItem.getRootArchive().getResolvedDependency())
704704
.setPath(runnerJar));
705705
Predicate<String> ignoredEntriesPredicate = getThinJarIgnoredEntriesPredicate(packageConfig);
706-
try (FileSystem runnerZipFs = createNewZip(runnerJar, packageConfig)) {
706+
try (FileSystem runnerZipFs = createNewReproducibleZipFileSystem(runnerJar, packageConfig)) {
707707
copyFiles(applicationArchivesBuildItem.getRootArchive(), runnerZipFs, null, ignoredEntriesPredicate);
708708
}
709709
}
@@ -793,7 +793,7 @@ private JarBuildItem buildThinJar(CurateOutcomeBuildItem curateOutcomeBuildItem,
793793
}
794794
}
795795
if (!rebuild) {
796-
try (FileSystem runnerZipFs = createNewZip(initJar, packageConfig)) {
796+
try (FileSystem runnerZipFs = createNewReproducibleZipFileSystem(initJar, packageConfig)) {
797797
ResolvedDependency appArtifact = curateOutcomeBuildItem.getApplicationModel().getAppArtifact();
798798
generateManifest(runnerZipFs, classPath.toString(), packageConfig, appArtifact,
799799
QuarkusEntryPoint.class.getName(),
@@ -997,7 +997,7 @@ public static String getJarFileName(ResolvedDependency dep, Path resolvedPath) {
997997
}
998998

999999
private void packageClasses(Path resolvedDep, final Path targetPath, PackageConfig packageConfig) throws IOException {
1000-
try (FileSystem runnerZipFs = createNewZip(targetPath, packageConfig)) {
1000+
try (FileSystem runnerZipFs = createNewReproducibleZipFileSystem(targetPath, packageConfig)) {
10011001
Files.walkFileTree(resolvedDep, EnumSet.of(FileVisitOption.FOLLOW_LINKS), Integer.MAX_VALUE,
10021002
new SimpleFileVisitor<Path>() {
10031003
@Override
@@ -1063,7 +1063,7 @@ private NativeImageSourceJarBuildItem buildNativeImageThinJar(CurateOutcomeBuild
10631063
Path libDir = targetDirectory.resolve(LIB);
10641064
Files.createDirectories(libDir);
10651065

1066-
try (FileSystem runnerZipFs = ZipUtils.newZip(runnerJar)) {
1066+
try (FileSystem runnerZipFs = createNewReproducibleZipFileSystem(runnerJar, packageConfig)) {
10671067

10681068
log.info("Building native image source jar: " + runnerJar);
10691069

@@ -1657,12 +1657,13 @@ public boolean decompile(Path jarToDecompile) {
16571657
}
16581658
}
16591659

1660-
private static FileSystem createNewZip(Path runnerJar, PackageConfig config) throws IOException {
1660+
private static FileSystem createNewReproducibleZipFileSystem(Path runnerJar, PackageConfig config) throws IOException {
16611661
boolean useUncompressedJar = !config.jar().compress();
16621662
if (useUncompressedJar) {
1663-
return ZipUtils.newZip(runnerJar, Map.of("compressionMethod", "STORED"));
1663+
return ZipUtils.createNewReproducibleZipFileSystem(runnerJar, Map.of("compressionMethod", "STORED"),
1664+
config.outputTimestamp().orElse(null));
16641665
}
1665-
return ZipUtils.newZip(runnerJar);
1666+
return ZipUtils.createNewReproducibleZipFileSystem(runnerJar, config.outputTimestamp().orElse(null));
16661667
}
16671668

16681669
}

devtools/maven/src/main/java/io/quarkus/maven/QuarkusBootstrapProvider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,11 @@ public Properties getBuildSystemProperties(QuarkusBootstrapMojo mojo, boolean qu
348348

349349
effectiveProperties.putIfAbsent("quarkus.application.name", mojo.mavenProject().getArtifactId());
350350
effectiveProperties.putIfAbsent("quarkus.application.version", mojo.mavenProject().getVersion());
351+
// pass the project.build.outputTimestamp to Quarkus packaging subsystem
352+
if (mojo.mavenProject().getProperties().containsKey("project.build.outputTimestamp")) {
353+
effectiveProperties.putIfAbsent("quarkus.package.output-timestamp",
354+
mojo.mavenProject().getProperties().getProperty("project.build.outputTimestamp"));
355+
}
351356

352357
for (Map.Entry<String, String> attribute : mojo.manifestEntries().entrySet()) {
353358
if (attribute.getValue() == null) {

0 commit comments

Comments
 (0)