Last active
September 11, 2023 10:17
-
-
Save lifthrasiir/0da11dacf24e14cb32960b1b92dc4212 to your computer and use it in GitHub Desktop.
Custom Zig PyPI packaging script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This script builds a custom Zig distribution into a Python wheel. | |
# | |
# The "custom" distribution refers to any directory resulting from | |
# zig-bootstrap that doesn't make into public nightly or stable releases. | |
# The existing ziglang/zig-pypi doesn't work with such cases, hence | |
# this script. It still makes use of a large portion of make_wheels.py, | |
# so should be put into the same directory in order to function. | |
# | |
# This script is derived from make_wheels.py from zig-pypi (commit | |
# 5b30070bc), and thus distributed under the same license (MIT/Expat). | |
# | |
# Kang Seonghoon, 2023-09-11 | |
import sys | |
import os | |
import subprocess | |
import json | |
from zipfile import ZipInfo | |
try: | |
import libarchive | |
except ImportError as e: # this script works without libarchive | |
import types | |
sys.modules['libarchive'] = types.ModuleType('libarchive') | |
from make_wheels import write_wheel, ZIG_PYTHON_PLATFORMS | |
def write_ziglang_wheel_from_dir(out_dir, *, version, platform, built_dir): | |
built_dir = built_dir.rstrip(os.sep) | |
contents = {} | |
contents['ziglang/__init__.py'] = b'' | |
for base, dirs, files in os.walk(built_dir): | |
assert base.startswith(built_dir) | |
base_in_wheel = 'ziglang' + base[len(built_dir):].replace(os.sep, '/') | |
for name in files: | |
path = os.path.join(base, name) | |
path_in_wheel = f'{base_in_wheel}/{name}' | |
stat = os.stat(path) | |
zip_info = ZipInfo(path_in_wheel) | |
zip_info.external_attr = (stat.st_mode & 0xFFFF) << 16 | |
with open(path, 'rb') as f: | |
contents[zip_info] = f.read() | |
if path_in_wheel.startswith('ziglang/zig'): | |
contents['ziglang/__main__.py'] = f'''\ | |
import os, sys | |
argv = [os.path.join(os.path.dirname(__file__), "{name}"), *sys.argv[1:]] | |
if os.name == 'posix': | |
os.execv(argv[0], argv) | |
else: | |
import subprocess; sys.exit(subprocess.call(argv)) | |
'''.encode('ascii') | |
with open('README.pypi.md') as f: | |
description = f.read() | |
return write_wheel(out_dir, | |
name='ziglang', | |
version=version, | |
tag=f'py3-none-{platform}', | |
metadata={ | |
'Summary': 'Zig is a general-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.', | |
'Description-Content-Type': 'text/markdown', | |
'License': 'MIT', | |
'Classifier': [ | |
'License :: OSI Approved :: MIT License', | |
], | |
'Project-URL': [ | |
'Homepage, https://ziglang.org', | |
'Source Code, https://github.com/ziglang/zig-pypi', | |
'Bug Tracker, https://github.com/ziglang/zig-pypi/issues', | |
], | |
'Requires-Python': '~=3.5', | |
}, | |
description=description, | |
contents=contents, | |
) | |
def main(built_dir, out_dir='.'): | |
built_dir = os.path.realpath(built_dir) | |
env_json = subprocess.check_output([os.path.join(built_dir, 'zig'), 'env']) | |
env = json.loads(env_json) | |
# ensure that we are not packaging the usual development binary | |
for key in ('zig_exe', 'lib_dir', 'std_dir'): | |
if os.path.commonpath([built_dir, os.path.realpath(env[key])]) != built_dir: | |
raise RuntimeError(f'`zig env` returned {key}={env[key]!r}, which is outside of the built directory {built_dir!r}') | |
version = env['version'].replace('-dev', '.dev') | |
target, _, _ = env['target'].partition('.') | |
platform = ZIG_PYTHON_PLATFORMS[target] | |
write_ziglang_wheel_from_dir(out_dir, version=version, platform=platform, built_dir=built_dir) | |
if __name__ == '__main__': | |
if not (2 <= len(sys.argv) <= 3): | |
print(f'Usage: {sys.argv[0]} <directory to the built zig> [<directory to write a wheel (default `.`)>]', file=sys.stderr) | |
raise SystemExit(1) | |
else: | |
main(*sys.argv[1:]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment