add helper to rewrite timestamps in zip files to SOURCE_DATE_EPOCH

for reproducible builds, the timestams of zip members must not depend on
checkout date or file creation dates, the metadata should be clear of
those effects.

Only timestamps are rewritten since we want custom order/storage options
for open document files / our make rules should already have
deterministic order (or that determinism is just one additional $(sort…)
call away)

Change-Id: I49341cf3252d5ef5c092508c789fd188f21dc8df
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/207142
Reviewed-by: Christian Lohmaier <lohmaier+LibreOffice@googlemail.com>
Tested-by: Jenkins
This commit is contained in:
Christian Lohmaier
2026-07-14 15:14:42 +02:00
parent 3ee90bca13
commit 725b107b1d
11 changed files with 59 additions and 6 deletions
+6 -1
View File
@@ -7057,7 +7057,12 @@ if test "$_os" = "WINNT"; then
done
fi
fi
if test "$with_system_hsqldb" = "yes"; then
# required for solenv/bin/rewrite_zip_timestamps.pl/for reproducible builds
# and also needed for --with-system-hsqldb
if test -n "$WSL_ONLY_AS_HELPER"; then
perl_use_string_spp="$perl_use_string_spp ; use Archive::Zip"
else
perl_use_string="$perl_use_string ; use Archive::Zip"
fi
if test "$enable_openssl" = "yes" -a "$with_system_openssl" != "yes"; then
+1
View File
@@ -282,6 +282,7 @@ $(gb_CustomTarget_workdir)/extras/source/autocorr/acor_%.dat : \
$(autocorr_PYTHONCOMMAND) $(SRCDIR)/bin/check-autocorr.py DocumentList.xml && \
$(call gb_Helper_wsl_path,$(WSL) zip -q0X --filesync --must-match $@ mimetype) && \
$(call gb_Helper_wsl_path,$(WSL) zip -qrX --must-match $@ $(call extras_AUTOCORR_XMLFILES_LANG,$(call extras_AUTOCORR_SHORTLANG,$*))) \
$(call gb_Helper_make_zip_deterministic,$@) \
)
$(call gb_Trace_EndRange,autocorr/acor_$*.dat,ZIP)
+1
View File
@@ -3670,6 +3670,7 @@ $(gb_CustomTarget_workdir)/extras/source/autotext/share/%.bau : \
$(call gb_Helper_wsl_path,\
$(WSL) zip -q0X --filesync --must-match $@ mimetype && \
$(WSL) zip -qrX --must-match $@ $(call extras_AUTOTEXTSHARE_XMLFILES_RELATIVE,$*)) \
$(call gb_Helper_make_zip_deterministic,$@) \
)
$(call gb_Trace_EndRange,autotext/$*.bau,ZIP)
+1
View File
@@ -44,6 +44,7 @@ $(gb_CustomTarget_workdir)/extras/source/autotext/user/%.bau : \
$(call gb_Helper_wsl_path,\
$(WSL) zip -q0X --filesync --must-match $@ mimetype && \
$(WSL) zip -qrX --must-match $@ $(call extras_AUTOTEXTUSER_XMLFILES_RELATIVE,$*)) \
$(call gb_Helper_make_zip_deterministic,$@) \
)
$(call gb_Trace_EndRange,autotext/user/$*.bau,ZIP)
+2 -1
View File
@@ -17,7 +17,8 @@ $(call gb_Trace_StartRange,$(subst $(gb_CustomTarget_workdir)/extras/source/,,$@
cd $(dir $<) && \
$(call gb_Helper_wsl_path,\
$(WSL) zip -q0X --filesync --must-match $@ mimetype && \
$(WSL) zip -qrX --must-match $@ $(subst $(dir $<),,$^)) -x mimetype
$(WSL) zip -qrX --must-match $@ $(subst $(dir $<),,$^) -x mimetype) \
$(call gb_Helper_make_zip_deterministic,$@)
$(call gb_Trace_EndRange,$(subst $(gb_CustomTarget_workdir)/extras/source/,,$@),ZIP)
endef
+2 -1
View File
@@ -22,7 +22,8 @@ $(call gb_Trace_StartRange,$(subst $(gb_CustomTarget_workdir)/filter/source/docb
cd $(dir $<) && \
$(call gb_Helper_wsl_path,\
$(WSL) zip -q0X --filesync --must-match $@ mimetype && \
$(WSL) zip -qrX --must-match $@ $(subst $(dir $<),,$^)) -x mimetype
$(WSL) zip -qrX --must-match $@ $(subst $(dir $<),,$^) -x mimetype) \
$(call gb_Helper_make_zip_deterministic,$@)
$(call gb_Trace_EndRange,$(subst $(gb_CustomTarget_workdir)/filter/source/docbook/,,$@),ZIP)
endef
+2 -1
View File
@@ -62,7 +62,8 @@ $(packimages_DIR)/images_%.zip : \
-L $(packimages_DIR)/$*_links.txt \
-s $< -o $@ \
$(if $(findstring s,$(MAKEFLAGS)),> /dev/null) && \
rm -rf $${ILSTFILE})
rm -rf $${ILSTFILE} \
$(call gb_Helper_make_zip_deterministic,$@))
$(call gb_Trace_EndRange,$(subst $(WORKDIR)/,,$@),PRL)
# turn the #defines foo "resource.png" of hlst into the final ilst format
+37
View File
@@ -0,0 +1,37 @@
#!/usr/bin/env perl
# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t; fill-column: 100 -*-
#
# This file is part of the LibreOffice project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
use strict;
use warnings;
use utf8;
use Archive::Zip qw( :ERROR_CODES );
# minimalist script to rewrite the timestamps in a zip file to make them deterministic for
# reproducible builds. Other tools also reorder members and also potentially recompress, but we
# control order in our makefiles and want e.g. the mimetype file to be first member and also be
# uncompressed for OpenDocument files, so we just rewrite the timestamps here.
my $zip = Archive::Zip->new();
my $zip_file = shift @ARGV;
my $timestamp = shift @ARGV;
$zip->read($zip_file) == Archive::Zip::AZ_OK or die "Error reading file $zip_file ($!)\n";
# this will only rewrite standard metadata, files with extended attributes aren't covered
foreach my $member ( $zip->members() ) {
$member->setLastModFileDateTimeFromUnix($timestamp);
}
# overwrite saves to temp file first, then renames the original file and only then renames the temp
# file to the original name, should be atomic enough, esp. given that some recipies create zipfiles
# in multiple steps and are more prone to errors in case the build is killed midway.
$zip->overwrite() == Archive::Zip::AZ_OK or die "Error writing file $zip_file ($!)\n";
# vim: set noet sw=4 ts=4:
+4 -2
View File
@@ -109,7 +109,8 @@ $(call gb_Extension_get_target,%) : \
$(if $(and $(gb_Extension_TRANS_LANGS),$(DESCRIPTION)),cp $(foreach lang,$(gb_Extension_TRANS_LANGS),$(gb_Extension_workdir)/$*/description-$(lang).txt) $(call gb_Extension_get_rootdir,$*) &&) \
cd $(call gb_Extension_get_rootdir,$*) && \
cat $$RESPONSEFILE | $(call gb_Helper_wsl_path,$(WSL) $(gb_Extension_ZIPCOMMAND) -rX --filesync --must-match \
$(call gb_Extension_get_target,$*) --names-stdin)) && rm -f $$RESPONSEFILE
$(call gb_Extension_get_target,$*) --names-stdin)) && rm -f $$RESPONSEFILE \
$(call gb_Helper_make_zip_deterministic,$@)
$(call gb_Trace_EndRange,$*,OXT)
# set file list and location of manifest and description files
@@ -464,7 +465,8 @@ $(call gb_Extension_get_rootdir,$(1))/help/$(2).done : \
$$(HELPFILES) && \
(cd $(gb_Extension_workdir)/$(1)/help/$(2) && \
$$(call gb_Helper_wsl_path,$(WSL) $$(gb_Extension_ZIPCOMMAND) -r $$(basename $$@)/help.jar \
$$(HELPFILES))) && \
$$(HELPFILES))) \
$$(call gb_Helper_make_zip_deterministic,$$(basename $$@)/help.jar) && \
$$(gb_Extension_HELPINDEXERCOMMAND) -lang $(2) -mod help \
-dir $$(basename $$@) && \
rm -fr $$(basename $$@)/caption $$(basename $$@)/content && \
+2
View File
@@ -397,4 +397,6 @@ Libs: $(4)
$(5)
endef
gb_Helper_make_zip_deterministic = $(if $(SOURCE_DATE_EPOCH),&& $(if $(MSYSTEM),$(STRAWBERRY_PERL),$(PERL)) $(SRCDIR)/solenv/bin/rewrite_zip_timestamps.pl $(1) $(SOURCE_DATE_EPOCH))
# vim: set noet sw=4 ts=4:
+1
View File
@@ -54,6 +54,7 @@ $(call gb_Zip_get_target,%) :
$(call gb_Zip_get_target,$*)) && \
rm -f $${RESPONSEFILE} && \
touch $@\
$(call gb_Helper_make_zip_deterministic,$@) \
, cp $(SRCDIR)/solenv/gbuild/empty.zip $@)\
$(if $(INSTALL_NAME),&& cp $(call gb_Zip_get_target,$*) $(INSTALL_NAME)) \
)