From 0d01cba955d98d59102fcea4fa487665ecc17967 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Mon, 5 Aug 2024 20:53:15 -0400 Subject: [PATCH 1/3] Store entries in zip file in a deterministic order. In order to make the output zip file reproducible (independent of the underlying filesystem's directory traversal order), sort each list of subdirectories and each list of files before adding them to the zip file. (Note that we want to sort the dirs list in place, causing os.walk to traverse the subdirectories in order.) --- src/auditwheel/tools.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/auditwheel/tools.py b/src/auditwheel/tools.py index 63b32802..6431abed 100644 --- a/src/auditwheel/tools.py +++ b/src/auditwheel/tools.py @@ -75,6 +75,8 @@ def dir2zip(in_dir: str, zip_fname: str, date_time: datetime | None = None) -> N compression = zipfile.ZIP_DEFLATED with zipfile.ZipFile(zip_fname, "w", compression=compression) as z: for root, dirs, files in os.walk(in_dir): + dirs.sort() + files.sort() for dir in dirs: dname = os.path.join(root, dir) out_dname = os.path.relpath(dname, in_dir) + "/" From a393a176eb77c8d437d1ffd35820988b2d2dac5a Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Mon, 5 Aug 2024 20:55:20 -0400 Subject: [PATCH 2/3] Store entries in RECORD in a deterministic order. In order to make the output zip file reproducible (independent of the underlying filesystem's directory traversal order), sort each list of subdirectories and each list of files while we are generating the RECORD file. (Note that we want to sort the dirs list in place, causing os.walk to traverse the subdirectories in order.) --- src/auditwheel/wheeltools.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/auditwheel/wheeltools.py b/src/auditwheel/wheeltools.py index b9f85b31..4e3a737e 100644 --- a/src/auditwheel/wheeltools.py +++ b/src/auditwheel/wheeltools.py @@ -71,6 +71,8 @@ def rewrite_record(bdist_dir: str) -> None: def walk() -> Generator[str, None, None]: for dir, dirs, files in os.walk(bdist_dir): + dirs.sort() + files.sort() for f in files: yield pjoin(dir, f) From 1600fdf449e405c322cd9191c06f6f7122145d60 Mon Sep 17 00:00:00 2001 From: Benjamin Moody Date: Mon, 16 Sep 2024 16:48:05 -0400 Subject: [PATCH 3/3] Store .dist-info entries at the end of the zip file. If the wheel metadata files are physically located at the end of the zip file, this allows other tools to modify the metadata without rewriting the entire archive. --- src/auditwheel/tools.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/auditwheel/tools.py b/src/auditwheel/tools.py index 6431abed..1fd215ab 100644 --- a/src/auditwheel/tools.py +++ b/src/auditwheel/tools.py @@ -77,6 +77,11 @@ def dir2zip(in_dir: str, zip_fname: str, date_time: datetime | None = None) -> N for root, dirs, files in os.walk(in_dir): dirs.sort() files.sort() + if root == in_dir: + # Place the contents of *.dist-info at the end of + # the archive, as recommended by PEP 427. + dirs.sort(key=lambda p: p.endswith(".dist-info")) + for dir in dirs: dname = os.path.join(root, dir) out_dname = os.path.relpath(dname, in_dir) + "/"