gh-91279: ZipFile.writestr now respect SOURCE_DATE_EPOCH (#124435)

This commit is contained in:
Wulian 2025-01-21 02:12:29 +08:00 committed by GitHub
parent dda02eb7be
commit 5d57959d7d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 44 additions and 2 deletions

View file

@ -730,6 +730,12 @@ zipinfo
(Contributed by Bénédikt Tran in :gh:`123424`.)
* :meth:`zipfile.ZipFile.writestr` now respect ``SOURCE_DATE_EPOCH`` that
distributions can set centrally and have build tools consume this in order
to produce reproducible output.
(Contributed by Jiahao Li in :gh:`91279`.)
.. Add improved modules above alphabetically, not here at the end.
Optimizations

View file

@ -20,7 +20,7 @@ from tempfile import TemporaryFile
from random import randint, random, randbytes
from test import archiver_tests
from test.support import script_helper
from test.support import script_helper, os_helper
from test.support import (
findfile, requires_zlib, requires_bz2, requires_lzma,
captured_stdout, captured_stderr, requires_subprocess,
@ -1784,6 +1784,35 @@ class OtherTests(unittest.TestCase):
zinfo.flag_bits |= zipfile._MASK_USE_DATA_DESCRIPTOR # Include an extended local header.
orig_zip.writestr(zinfo, data)
def test_write_with_source_date_epoch(self):
with os_helper.EnvironmentVarGuard() as env:
# Set the SOURCE_DATE_EPOCH environment variable to a specific timestamp
env['SOURCE_DATE_EPOCH'] = "1735715999"
with zipfile.ZipFile(TESTFN, "w") as zf:
zf.writestr("test_source_date_epoch.txt", "Testing SOURCE_DATE_EPOCH")
with zipfile.ZipFile(TESTFN, "r") as zf:
zip_info = zf.getinfo("test_source_date_epoch.txt")
get_time = time.localtime(int(os.environ['SOURCE_DATE_EPOCH']))[:6]
# Compare each element of the date_time tuple
# Allow for a 1-second difference
for z_time, g_time in zip(zip_info.date_time, get_time):
self.assertAlmostEqual(z_time, g_time, delta=1)
def test_write_without_source_date_epoch(self):
if 'SOURCE_DATE_EPOCH' in os.environ:
del os.environ['SOURCE_DATE_EPOCH']
with zipfile.ZipFile(TESTFN, "w") as zf:
zf.writestr("test_no_source_date_epoch.txt", "Testing without SOURCE_DATE_EPOCH")
with zipfile.ZipFile(TESTFN, "r") as zf:
zip_info = zf.getinfo("test_no_source_date_epoch.txt")
current_time = time.localtime()[:6]
for z_time, c_time in zip(zip_info.date_time, current_time):
self.assertAlmostEqual(z_time, c_time, delta=1)
def test_close(self):
"""Check that the zipfile is closed after the 'with' block."""
with zipfile.ZipFile(TESTFN2, "w") as zipfp:

View file

@ -614,7 +614,11 @@ class ZipInfo:
Return self.
"""
self.date_time = time.localtime(time.time())[:6]
# gh-91279: Set the SOURCE_DATE_EPOCH to a specific timestamp
epoch = os.environ.get('SOURCE_DATE_EPOCH')
get_time = int(epoch) if epoch else time.time()
self.date_time = time.localtime(get_time)[:6]
self.compress_type = archive.compression
self.compress_level = archive.compresslevel
if self.filename.endswith('/'): # pragma: no cover

View file

@ -0,0 +1,3 @@
:meth:`zipfile.ZipFile.writestr` now respect ``SOURCE_DATE_EPOCH`` that
distributions can set centrally and have build tools consume this in order
to produce reproducible output.