RFR: 8276766: Enable jar and jmod to produce deterministic timestamped content
John Neffenger
jgneff at openjdk.java.net
Mon Nov 22 02:39:09 UTC 2021
On Fri, 19 Nov 2021 16:52:36 GMT, Andrew Leonard <aleonard at openjdk.org> wrote:
> Add a new --source-date <TIMESTAMP> (epoch milliseconds) option to jar and jmod to allow specification of time to use for created/updated jar/jmod entries. This then allows the ability to make the content deterministic.
>
> Signed-off-by: Andrew Leonard <anleonar at redhat.com>
Thank you for this timely pull request, Andrew! I need this pull request and also #6395 to [enable reproducible builds in JavaFX](https://github.com/openjdk/jfx/pull/446). I drove myself crazy this weekend with time zones, and if I understand your proposed changes correctly, it looks as if you're hitting the same problems as I did:
1. The [`SOURCE_DATE_EPOCH` environment variable](https://reproducible-builds.org/specs/source-date-epoch/) is defined as the number of **seconds** since the epoch of 1970-01-01T00:00:00Z, but the new command option is defined as the number of milliseconds. That makes it difficult to set `--source-date=$SOURCE_DATE_EPOCH` on the command line.
2. Calling the method `ZipEntry.setTime(long)` will not allow for reproducible builds when the builds run in different time zones.
For the second problem, run the included Java Time program as shown below:
$ javac Time.java
$ echo $SOURCE_DATE_EPOCH
1637085342
$ date --date="@$SOURCE_DATE_EPOCH"
Tue 16 Nov 2021 09:55:42 AM PST
$ java Time
Build timestamp = 2021-11-16T17:55:42Z
$ for f in *.zip; do zipinfo -v $f | grep -e Archive -e modified; done
Archive: FailsInNome.zip
file last modified on (DOS date/time): 2021 Nov 16 08:55:42
Archive: FailsInRome.zip
file last modified on (DOS date/time): 2021 Nov 16 18:55:42
Archive: WorksInNome.zip
file last modified on (DOS date/time): 2021 Nov 16 17:55:42
Archive: WorksInRome.zip
file last modified on (DOS date/time): 2021 Nov 16 17:55:42
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.TimeZone;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class Time {
static void writeZipFile(String name, ZipEntry entry) throws IOException {
var output = new ZipOutputStream(new FileOutputStream(name));
output.putNextEntry(entry);
output.closeEntry();
output.close();
}
public static void main(String[] args) throws IOException {
var instant = Instant.now().truncatedTo(ChronoUnit.SECONDS);
var sourceDateEpoch = System.getenv("SOURCE_DATE_EPOCH");
if (sourceDateEpoch != null) {
long seconds = Long.parseLong(sourceDateEpoch);
instant = Instant.ofEpochSecond(seconds);
}
System.out.println("Build timestamp = " + instant);
var entry = new ZipEntry("Entry");
long newTime = 1000 * instant.getEpochSecond();
TimeZone.setDefault(TimeZone.getTimeZone("America/Nome"));
entry.setTime(newTime);
writeZipFile("FailsInNome.zip", entry);
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Rome"));
entry.setTime(newTime);
writeZipFile("FailsInRome.zip", entry);
var dosTime = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
TimeZone.setDefault(TimeZone.getTimeZone("America/Nome"));
entry.setTimeLocal(dosTime);
writeZipFile("WorksInNome.zip", entry);
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Rome"));
entry.setTimeLocal(dosTime);
writeZipFile("WorksInRome.zip", entry);
}
}
-------------
PR: https://git.openjdk.java.net/jdk/pull/6481
More information about the core-libs-dev
mailing list