Files
order_system/packaging/win7/make_waitress_wheel.py

61 lines
3.0 KiB
Python

"""Repackage official Waitress 3.0.2 metadata for the tested Python 3.8 build.
The HTTP server and security fixes are kept byte-for-byte. Only the CLI name
resolver gets a Python 3.8 fallback. The local version identifies the adaptation.
"""
import base64
import csv
import hashlib
import io
from pathlib import Path
import zipfile
UPSTREAM_SHA256 = 'c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e'
VERSION = '3.0.2+win7.1'
def repackage(source, destination):
source, destination = Path(source), Path(destination)
if hashlib.sha256(source.read_bytes()).hexdigest() != UPSTREAM_SHA256:
raise ValueError('Unexpected upstream Waitress wheel checksum')
old_info, new_info = 'waitress-3.0.2.dist-info', 'waitress-%s.dist-info' % VERSION
destination.mkdir(parents=True, exist_ok=True)
target = destination / ('waitress-%s-py3-none-any.whl' % VERSION)
records = []
with zipfile.ZipFile(source) as src, zipfile.ZipFile(target, 'w', zipfile.ZIP_DEFLATED) as out:
for name in src.namelist():
if name.endswith('/RECORD'):
continue
content = src.read(name)
new_name = name.replace(old_info, new_info)
if name == 'waitress/runner.py':
assert b'import pkgutil\n' in content and b'pkgutil.resolve_name(args[0])' in content
content = content.replace(b'import pkgutil\n',
b'try:\n from pkgutil import resolve_name\nexcept ImportError:\n from pkgutil_resolve_name import resolve_name\n')
content = content.replace(b'pkgutil.resolve_name(args[0])', b'resolve_name(args[0])')
if name == old_info + '/METADATA':
content = content.replace(b'Version: 3.0.2\n', ('Version: %s\n' % VERSION).encode())
content = content.replace(b'Requires-Python: >=3.9.0\n',
b'Requires-Python: >=3.8.0\nRequires-Dist: pkgutil-resolve-name==1.3.10; python_version < "3.9"\n')
assert b'Requires-Python: >=3.8.0\n' in content
out.writestr(new_name, content)
digest = base64.urlsafe_b64encode(hashlib.sha256(content).digest()).rstrip(b'=').decode()
records.append((new_name, 'sha256=' + digest, str(len(content))))
records.append((new_info + '/RECORD', '', ''))
record = io.StringIO(newline='')
csv.writer(record, lineterminator='\n').writerows(records)
out.writestr(new_info + '/RECORD', record.getvalue())
with zipfile.ZipFile(source) as src, zipfile.ZipFile(target) as dest:
assert all(src.read(name) == dest.read(name) for name in src.namelist()
if name.startswith('waitress/') and name != 'waitress/runner.py')
return target
if __name__ == '__main__':
import argparse
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('source', type=Path)
parser.add_argument('destination', type=Path)
args = parser.parse_args()
print(repackage(args.source, args.destination))