Skip to content

Commit 59ebae0

Browse files
committed
Support a SOURCE_DATE_EPOCH prior to 1980
1 parent 4ebce0e commit 59ebae0

File tree

2 files changed

+13
-4
lines changed

2 files changed

+13
-4
lines changed

backend/src/hatchling/builders/wheel.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ def __init__(self, project_id: str, *, reproducible: bool) -> None:
8787
def get_reproducible_time_tuple() -> TIME_TUPLE:
8888
from datetime import datetime, timezone
8989

90-
d = datetime.fromtimestamp(get_reproducible_timestamp(), timezone.utc)
90+
# `zipfile.ZipInfo` does not support timestamps before 1980
91+
min_ts = datetime(1980, 1, 1, tzinfo=timezone.utc).timestamp()
92+
d = datetime.fromtimestamp(max(get_reproducible_timestamp(), min_ts), timezone.utc)
9193
return d.year, d.month, d.day, d.hour, d.minute, d.second
9294

9395
def add_file(self, included_file: IncludedFile) -> tuple[str, str, str]:

tests/backend/builders/test_wheel.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,14 @@ def test_default_auto_detection(self, hatch, helpers, temp_dir, config_file):
786786
zip_info = zip_archive.getinfo(f'{metadata_directory}/WHEEL')
787787
assert zip_info.date_time == (2020, 2, 2, 0, 0, 0)
788788

789-
def test_default_reproducible_timestamp(self, hatch, helpers, temp_dir, config_file):
789+
@pytest.mark.parametrize(
790+
('epoch', 'expected_date_time'),
791+
[
792+
('0', (1980, 1, 1, 0, 0, 0)),
793+
('1580601700', (2020, 2, 2, 0, 1, 40)),
794+
],
795+
)
796+
def test_default_reproducible_timestamp(self, hatch, helpers, temp_dir, config_file, epoch, expected_date_time):
790797
config_file.model.template.plugins['default']['src-layout'] = False
791798
config_file.save()
792799

@@ -812,7 +819,7 @@ def test_default_reproducible_timestamp(self, hatch, helpers, temp_dir, config_f
812819
build_path = project_path / 'dist'
813820
build_path.mkdir()
814821

815-
with project_path.as_cwd(env_vars={'SOURCE_DATE_EPOCH': '1580601700'}):
822+
with project_path.as_cwd(env_vars={'SOURCE_DATE_EPOCH': epoch}):
816823
artifacts = list(builder.build(directory=str(build_path)))
817824

818825
assert len(artifacts) == 1
@@ -837,7 +844,7 @@ def test_default_reproducible_timestamp(self, hatch, helpers, temp_dir, config_f
837844

838845
with zipfile.ZipFile(str(expected_artifact), 'r') as zip_archive:
839846
zip_info = zip_archive.getinfo(f'{metadata_directory}/WHEEL')
840-
assert zip_info.date_time == (2020, 2, 2, 0, 1, 40)
847+
assert zip_info.date_time == expected_date_time
841848

842849
def test_default_no_reproducible(self, hatch, helpers, temp_dir, config_file):
843850
config_file.model.template.plugins['default']['src-layout'] = False

0 commit comments

Comments
 (0)