61 lines
3.0 KiB
Python
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))
|