From 36359a26b1ed58d8536098d4d2cc3030c8d55c51 Mon Sep 17 00:00:00 2001 From: PtJade Ceramic <185668489+PtJade-Ceramic@users.noreply.github.com> Date: Mon, 17 Aug 2026 13:38:12 +0800 Subject: [PATCH] release scripts: support reproducible builds via SOURCE_DATE_EPOCH Set SOURCE_DATE_EPOCH to make the installer, portable, MinGit and tar archives byte-identical across repeated builds on the same SDK snapshot. A shared pin-mtimes.sh helper pins the mtime of every packaged file and directory to the epoch, and the 7z/ZIP paths disable access/creation-time storage, so the archive bytes do not vary with the build time. This is a no-op unless SOURCE_DATE_EPOCH is set, which keeps local builds unchanged. Signed-off-by: PtJade Ceramic <185668489+PtJade-Ceramic@users.noreply.github.com> --- archive/release.sh | 9 ++++++ installer/release.sh | 30 +++++++++++++++++++ mingit/release.sh | 11 ++++++- pin-mtimes.sh | 70 ++++++++++++++++++++++++++++++++++++++++++++ portable/release.sh | 11 ++++++- 5 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 pin-mtimes.sh diff --git a/archive/release.sh b/archive/release.sh index 64bc10911e..e76becab17 100755 --- a/archive/release.sh +++ b/archive/release.sh @@ -127,6 +127,15 @@ type tar || pacman -Sy --noconfirm tar || die "Could not install tar" +# ---- Reproducible: pin file mtimes to $SOURCE_DATE_EPOCH (if set) ---- +# tar archives embed file timestamps; pinning mtimes makes repeated builds of +# the same version byte-identical. Skipped when SOURCE_DATE_EPOCH is unset. +if test -n "$SOURCE_DATE_EPOCH" +then + # shellcheck disable=SC2086 + "$SCRIPT_PATH/../pin-mtimes.sh" --root="$SCRIPT_PATH/root" $LIST +fi + echo "Creating .tar.bz2 archive" && if ! tar -c -j -f "$TARGET" --directory=/ --exclude=etc/post-install/* $LIST --directory=$SCRIPT_PATH/root bin dev etc tmp $MSYSTEM_LOWER && test $? = 1 then diff --git a/installer/release.sh b/installer/release.sh index 6f5cfdde20..41a1823def 100755 --- a/installer/release.sh +++ b/installer/release.sh @@ -361,6 +361,36 @@ signtool= test -z "$(git config alias.signtool)" || signtool="//Ssigntool=\"git signtool \\\$f\" //DSIGNTOOL" +# ---- Reproducible: pin the mtime of every file to be packaged ---- +# Inno Setup writes file timestamps into the installer; any mtime difference +# leads to different installer bytes. SOURCE_DATE_EPOCH is expected to be set +# by the build environment (e.g. CI); skipped for local builds without it. +# Sources are listed in file-list.iss and install.iss, including the +# generated files (ReleaseNotes.html, package-versions.txt, ...). +if test -n "$SOURCE_DATE_EPOCH" +then + files= + rel_pwd="${PWD#/}" + for iss in file-list.iss install.iss + do + while IFS= read -r s + do + case "$s" in + \{#SourcePath\}*) + # resolve {#SourcePath} against the installer directory + s="${s#\{#SourcePath\}}" + s="${s#\\}"; s="${s#/}" + s="$rel_pwd/${s//\\//}" + ;; + *) s="${s//\\//}" ;; + esac + test -e "/$s" && files="$files $s" + done < <(perl -ne 'if (/^Source: (?:"([^"]+)"|([^;]+));/) { print(defined $1 ? $1 : $2, "\n") }' "$iss") + done + # shellcheck disable=SC2086 + "$PWD/../pin-mtimes.sh" $files +fi + echo "Launching Inno Setup compiler ..." && eval ./InnoSetup/ISCC.exe "$signtool" install.iss >install.log || die "Could not make installer" diff --git a/mingit/release.sh b/mingit/release.sh index 37319aa10f..2534b7edae 100755 --- a/mingit/release.sh +++ b/mingit/release.sh @@ -177,6 +177,15 @@ esac test ! -f "$TARGET" || rm "$TARGET" || die "Could not remove $TARGET" +# ---- Reproducible: pin file mtimes to $SOURCE_DATE_EPOCH (if set) ---- +# ZIP archives embed file timestamps; pinning mtimes makes repeated builds of +# the same version byte-identical. Skipped when SOURCE_DATE_EPOCH is unset. +if test -n "$SOURCE_DATE_EPOCH" +then + # shellcheck disable=SC2086 + "$SCRIPT_PATH/../pin-mtimes.sh" --root="$SCRIPT_PATH/root" $LIST +fi + echo "Creating .zip archive" && -(cd / && 7z a -mx9 "$TARGET" $LIST "$SCRIPT_PATH"/root/*) && +(cd / && 7z a -mx9 -mta- -mtc- "$TARGET" $LIST "$SCRIPT_PATH"/root/*) && echo "Success! You will find the new MinGit at \"$TARGET\"." diff --git a/pin-mtimes.sh b/pin-mtimes.sh new file mode 100644 index 0000000000..f210f6cd13 --- /dev/null +++ b/pin-mtimes.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# +# pin-mtimes.sh - pin file mtimes for reproducible builds +# +# Usage: pin-mtimes.sh [--root=