Skip to content

Commit f74e5a6

Browse files
dnicolodirgommers
authored andcommitted
BUG: fix mtime of sdist archive members
Set the mtime of all archive members to the mtime set by meson dist, also for files that may have been locally modified. Use the current time for the PKG-INFO file. Drop support for the $SOURCE_DATE_EPOCH environment variable when creating the sdist. This environment variable is for meant to be used as a work-around for build tools that produce non-reproducible binary packages. It does not have a standardized meaning for tools producing source distributions. See https://reproducible-builds.org/docs/source-date-epoch/ Fixes #450.
1 parent 92a0e8d commit f74e5a6

File tree

3 files changed

+29
-18
lines changed

3 files changed

+29
-18
lines changed

mesonpy/__init__.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import tarfile
3232
import tempfile
3333
import textwrap
34+
import time
3435
import typing
3536
import warnings
3637

@@ -928,7 +929,7 @@ def sdist(self, directory: Path) -> pathlib.Path:
928929
meson_dist_path = pathlib.Path(self._build_dir, 'meson-dist', f'{meson_dist_name}.tar.gz')
929930
sdist = pathlib.Path(directory, f'{dist_name}.tar.gz')
930931

931-
with tarfile.open(meson_dist_path, 'r:gz') as meson_dist, mesonpy._util.create_targz(sdist) as (tar, mtime):
932+
with tarfile.open(meson_dist_path, 'r:gz') as meson_dist, mesonpy._util.create_targz(sdist) as tar:
932933
for member in meson_dist.getmembers():
933934
# calculate the file path in the source directory
934935
assert member.name, member.name
@@ -955,6 +956,7 @@ def sdist(self, directory: Path) -> pathlib.Path:
955956

956957
info = tarfile.TarInfo(member.name)
957958
file_stat = os.stat(path)
959+
info.mtime = member.mtime
958960
info.size = file_stat.st_size
959961
info.mode = int(oct(file_stat.st_mode)[-3:], 8)
960962

@@ -970,8 +972,7 @@ def sdist(self, directory: Path) -> pathlib.Path:
970972

971973
# add PKG-INFO to dist file to make it a sdist
972974
pkginfo_info = tarfile.TarInfo(f'{dist_name}/PKG-INFO')
973-
if mtime:
974-
pkginfo_info.mtime = mtime
975+
pkginfo_info.mtime = time.time() # type: ignore[assignment]
975976
pkginfo_info.size = len(self.metadata)
976977
tar.addfile(pkginfo_info, fileobj=io.BytesIO(self.metadata))
977978

mesonpy/_util.py

+2-9
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@
1818

1919

2020
if typing.TYPE_CHECKING: # pragma: no cover
21-
from typing import Optional, Tuple
22-
2321
from mesonpy._compat import Iterable, Iterator, Path
2422

2523

@@ -48,18 +46,13 @@ def add_ld_path(paths: Iterable[str]) -> Iterator[None]:
4846

4947

5048
@contextlib.contextmanager
51-
def create_targz(path: Path) -> Iterator[Tuple[tarfile.TarFile, Optional[int]]]:
49+
def create_targz(path: Path) -> Iterator[tarfile.TarFile]:
5250
"""Opens a .tar.gz file in the file system for edition.."""
5351

54-
# reproducibility
55-
source_date_epoch = os.environ.get('SOURCE_DATE_EPOCH')
56-
mtime = int(source_date_epoch) if source_date_epoch else None
57-
5852
os.makedirs(os.path.dirname(path), exist_ok=True)
5953
file = typing.cast(IO[bytes], gzip.GzipFile(
6054
path,
6155
mode='wb',
62-
mtime=mtime,
6356
))
6457
tar = tarfile.TarFile(
6558
mode='w',
@@ -68,7 +61,7 @@ def create_targz(path: Path) -> Iterator[Tuple[tarfile.TarFile, Optional[int]]]:
6861
)
6962

7063
with contextlib.closing(file), tar:
71-
yield tar, mtime
64+
yield tar
7265

7366

7467
class CLICounter:

tests/test_sdist.py

+23-6
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717

1818
def test_contents(sdist_library):
1919
with tarfile.open(sdist_library, 'r:gz') as sdist:
20-
names = set(sdist.getnames())
20+
names = {member.name for member in sdist.getmembers()}
21+
mtimes = {member.mtime for member in sdist.getmembers()}
2122

2223
assert names == {
2324
'library-1.0.0/example.c',
@@ -28,10 +29,14 @@ def test_contents(sdist_library):
2829
'library-1.0.0/PKG-INFO',
2930
}
3031

32+
# All the archive members have a valid mtime.
33+
assert 0 not in mtimes
34+
3135

3236
def test_contents_subdirs(sdist_subdirs):
3337
with tarfile.open(sdist_subdirs, 'r:gz') as sdist:
34-
names = set(sdist.getnames())
38+
names = {member.name for member in sdist.getmembers()}
39+
mtimes = {member.mtime for member in sdist.getmembers()}
3540

3641
assert names == {
3742
'subdirs-1.0.0/PKG-INFO',
@@ -43,6 +48,9 @@ def test_contents_subdirs(sdist_subdirs):
4348
'subdirs-1.0.0/subdirs/b/c.py',
4449
}
4550

51+
# All the archive members have a valid mtime.
52+
assert 0 not in mtimes
53+
4654

4755
def test_contents_unstaged(package_pure, tmp_path):
4856
new_data = textwrap.dedent('''
@@ -65,7 +73,8 @@ def bar():
6573
os.unlink('crap')
6674

6775
with tarfile.open(tmp_path / sdist_path, 'r:gz') as sdist:
68-
names = set(sdist.getnames())
76+
names = {member.name for member in sdist.getmembers()}
77+
mtimes = {member.mtime for member in sdist.getmembers()}
6978
read_data = sdist.extractfile('pure-1.0.0/pure.py').read().replace(b'\r\n', b'\n')
7079

7180
assert names == {
@@ -76,6 +85,9 @@ def bar():
7685
}
7786
assert read_data == new_data.encode()
7887

88+
# All the archive members have a valid mtime.
89+
assert 0 not in mtimes
90+
7991

8092
@pytest.mark.skipif(sys.platform in {'win32', 'cygwin'}, reason='Platform does not support executable bit')
8193
def test_executable_bit(sdist_executable_bit):
@@ -94,7 +106,11 @@ def test_executable_bit(sdist_executable_bit):
94106

95107

96108
def test_generated_files(sdist_generated_files):
97-
expected = {
109+
with tarfile.open(sdist_generated_files, 'r:gz') as sdist:
110+
names = {member.name for member in sdist.getmembers()}
111+
mtimes = {member.mtime for member in sdist.getmembers()}
112+
113+
assert names == {
98114
'executable_bit-1.0.0/PKG-INFO',
99115
'executable_bit-1.0.0/example-script.py',
100116
'executable_bit-1.0.0/example.c',
@@ -104,5 +120,6 @@ def test_generated_files(sdist_generated_files):
104120
'executable_bit-1.0.0/_version_meson.py',
105121
'executable_bit-1.0.0/generate_version.py',
106122
}
107-
with tarfile.open(sdist_generated_files, 'r:gz') as sdist:
108-
assert {tar.name for tar in sdist.getmembers()} == expected
123+
124+
# All the archive members have a valid mtime.
125+
assert 0 not in mtimes

0 commit comments

Comments
 (0)