From fbcd41ee9707dffa076c4d98dc713c33c50b9e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Gasc=C3=B3n?= <3040982+agascon@users.noreply.github.com> Date: Tue, 18 Apr 2023 15:16:14 +0200 Subject: [PATCH 1/5] Add test to validate PropertiesFileTransformer supports reproducible builds --- .../PropertiesFileTransformerTest.groovy | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy index ff23aed96..8128096b2 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy @@ -40,21 +40,42 @@ final class PropertiesFileTransformerTest extends TransformerTestSupport { void testTransformation() { transformer.transform(new TransformerContext(MANIFEST_NAME, getResourceStream(MANIFEST_NAME), Collections.emptyList(), new ShadowStats())) + def testableZipFile = doTransformAndGetTransformedFile(transformer, false) + def targetLines = readFrom(testableZipFile, MANIFEST_NAME) + + assertFalse(targetLines.isEmpty()) + + assertTrue(targetLines.contains("Manifest-Version=1.0")) + } + + @Test + void testTransformationPropertiesAreReproducible() { + transformer.transform(new TransformerContext(MANIFEST_NAME, getResourceStream(MANIFEST_NAME), Collections.emptyList(), new ShadowStats())) + + def firstRunTransformedFile = doTransformAndGetTransformedFile(transformer, true) + def firstRunTargetLines = readFrom(firstRunTransformedFile, MANIFEST_NAME) + + Thread.sleep(1000) // wait for 1sec to ensure timestamps in properties would change + + def secondRunTransformedFile = doTransformAndGetTransformedFile(transformer, true) + def secondRunTargetLines = readFrom(secondRunTransformedFile, MANIFEST_NAME) + + assertEquals(firstRunTargetLines, secondRunTargetLines) + } + + static File doTransformAndGetTransformedFile(final PropertiesFileTransformer transformer, final boolean preserveFileTimestamps) { def testableZipFile = File.createTempFile("testable-zip-file-", ".jar") def fileOutputStream = new FileOutputStream(testableZipFile) def bufferedOutputStream = new BufferedOutputStream(fileOutputStream) def zipOutputStream = new ZipOutputStream(bufferedOutputStream) try { - transformer.modifyOutputStream(zipOutputStream, false) + transformer.modifyOutputStream(zipOutputStream, preserveFileTimestamps) } finally { zipOutputStream.close() } - def targetLines = readFrom(testableZipFile, MANIFEST_NAME) - - assertFalse(targetLines.isEmpty()) - assertTrue(targetLines.contains("Manifest-Version=1.0")) + return testableZipFile; } static List readFrom(File jarFile, String resourceName) { From a7ef65b9e90597d40c48be86abb4b8996ea51994 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Gasc=C3=B3n?= <3040982+agascon@users.noreply.github.com> Date: Tue, 18 Apr 2023 15:18:04 +0200 Subject: [PATCH 2/5] Fix CleanProperties mechanism to strip Properties timestamp and support reproducible builds --- .../shadow/internal/CleanProperties.groovy | 38 ++++++++++--------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy index 5bed7a56d..1cf0501e4 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy @@ -1,32 +1,36 @@ -/* - * Source https://stackoverflow.com/a/39043903/519333 - */ package com.github.jengelman.gradle.plugins.shadow.internal class CleanProperties extends Properties { - private static class StripFirstLineStream extends FilterOutputStream { - private boolean firstLineSeen = false + private static class StripCommentsWithTimestampBufferedWriter extends BufferedWriter { - StripFirstLineStream(final OutputStream out) { - super(out) + private final int lengthOfExpectedTimestamp + + StripCommentsWithTimestampBufferedWriter(final Writer out) { + super(out); + + lengthOfExpectedTimestamp = ("#" + new Date().toString()).length() } @Override - void write(final int b) throws IOException { - if (firstLineSeen) { - super.write(b) - } else if (b == '\n') { - super.write(b) - - firstLineSeen = true + void write(final String str) throws IOException { + if (couldBeCommentWithTimestamp(str)) { + return } + + super.write(str) } + private boolean couldBeCommentWithTimestamp(final String str) { + return str != null && + str.startsWith("#") && + str.length() == lengthOfExpectedTimestamp + } } @Override - void store(final OutputStream out, final String comments) throws IOException { - super.store(new StripFirstLineStream(out), null) + void store(final Writer writer, final String comments) throws IOException + { + super.store(new StripCommentsWithTimestampBufferedWriter(writer), comments); } -} +} \ No newline at end of file From 57c78959ae39825fb6654ea9a358ec29a760b9f3 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 7 Jun 2024 17:54:31 +0800 Subject: [PATCH 3/5] Apply suggestions from code review --- .../gradle/plugins/shadow/internal/CleanProperties.groovy | 5 ++--- .../shadow/transformers/PropertiesFileTransformerTest.groovy | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy index 1cf0501e4..783cc22d5 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy @@ -29,8 +29,7 @@ class CleanProperties extends Properties { } @Override - void store(final Writer writer, final String comments) throws IOException - { + void store(final Writer writer, final String comments) throws IOException { super.store(new StripCommentsWithTimestampBufferedWriter(writer), comments); } -} \ No newline at end of file +} diff --git a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy index 8128096b2..a57ee221d 100644 --- a/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy +++ b/src/test/groovy/com/github/jengelman/gradle/plugins/shadow/transformers/PropertiesFileTransformerTest.groovy @@ -75,7 +75,7 @@ final class PropertiesFileTransformerTest extends TransformerTestSupport { zipOutputStream.close() } - return testableZipFile; + return testableZipFile } static List readFrom(File jarFile, String resourceName) { From 9d7d97e26fb91c079605f3c7a76fded4ac4cf1e0 Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 7 Jun 2024 20:29:06 +0800 Subject: [PATCH 4/5] Apply suggestions from code review --- .../gradle/plugins/shadow/internal/CleanProperties.groovy | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy index 783cc22d5..4c4e7604c 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy @@ -7,7 +7,7 @@ class CleanProperties extends Properties { private final int lengthOfExpectedTimestamp StripCommentsWithTimestampBufferedWriter(final Writer out) { - super(out); + super(out) lengthOfExpectedTimestamp = ("#" + new Date().toString()).length() } @@ -17,7 +17,6 @@ class CleanProperties extends Properties { if (couldBeCommentWithTimestamp(str)) { return } - super.write(str) } From 666b57cd4b74ba33e5aa080b7463fc2783853f2a Mon Sep 17 00:00:00 2001 From: Zongle Wang Date: Fri, 7 Jun 2024 20:29:30 +0800 Subject: [PATCH 5/5] Apply suggestions from code review --- .../gradle/plugins/shadow/internal/CleanProperties.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy index 4c4e7604c..b54b5271b 100644 --- a/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy +++ b/src/main/groovy/com/github/jengelman/gradle/plugins/shadow/internal/CleanProperties.groovy @@ -29,6 +29,6 @@ class CleanProperties extends Properties { @Override void store(final Writer writer, final String comments) throws IOException { - super.store(new StripCommentsWithTimestampBufferedWriter(writer), comments); + super.store(new StripCommentsWithTimestampBufferedWriter(writer), comments) } }