RFR: 8276766: Enable jar and jmod to produce deterministic timestamped content

Andrew Leonard aleonard at openjdk.java.net
Tue Nov 23 11:16:07 UTC 2021


On Mon, 22 Nov 2021 02:36:00 GMT, John Neffenger <jgneff 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);
>     }
> }

@jgneff Hi John, thanks for the comment, I hadn't realized that aspect, but sort of obvious when you look at the ZIP spec for dostime, which has no timezone info.
So with this in mind the --source-date=<timestamp> option I am looking to add for jar/jmod, will need to state the timestamp is an "Epoch timestamp", ie. seconds since Jan1 1970 in UTC, and that as such the jar/jmod dostime will represent UTC "local time", akin to the EPOCH_SOURCE_DATE spec: https://reproducible-builds.org/specs/source-date-epoch/
I will update my PR to to use this.
thanks

-------------

PR: https://git.openjdk.java.net/jdk/pull/6481


More information about the compiler-dev mailing list