[
  {
    "path": ".github/workflows/cd.yml",
    "content": "name: CD\n\non:\n  workflow_dispatch:\n    inputs:\n      version:\n        description: \"The version to build Zig wheels for, use 'latest' for latest release, 'master' for nightly builds\"\n        required: true\n        default: \"latest\"\n      suffix:\n        description: >\n          Suffix to append to the version in the wheel filename, i.e., for dev versions and version specifiers\n        required: false\n        default: \"\"\n      platforms:\n        description: >\n          Comma-separated list of specific platforms to build wheels for, or use 'all' to build for all supported platforms\n        required: false\n        default: \"all\"\n      push_to_pypi:\n        description: >\n          Whether to push the built wheels to PyPI. Can be 'true' or 'false', defaults to 'false'.\n        required: true\n        default: \"false\"\n\npermissions: {}\n\njobs:\n  build_wheels:\n    name: Build wheels\n    runs-on: ubuntu-latest\n    permissions:\n      contents: read\n    steps:\n      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0\n        with:\n          persist-credentials: false\n      - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0\n        with:\n          python-version: \"3.x\"\n\n      - uses: astral-sh/setup-uv@557e51de59eb14aaaba2ed9621916900a91d50c6 # v6.6.1\n\n      - name: Build wheels for all requested platforms\n        shell: bash\n        env:\n          GITHUB_EVENT_INPUTS_PLATFORMS: ${{ github.event.inputs.platforms }}\n          GITHUB_EVENT_INPUTS_VERSION: ${{ github.event.inputs.version }}\n          GITHUB_EVENT_INPUTS_SUFFIX: ${{ github.event.inputs.suffix }}\n        run: |\n          platforms=${GITHUB_EVENT_INPUTS_PLATFORMS}\n          IFS=',' read -r -a platform_array <<< \"$platforms\"\n          for platform in \"${platform_array[@]}\"; do\n            cmd=\"uv run make_wheels.py --outdir dist/ --version ${GITHUB_EVENT_INPUTS_VERSION} --platform $platform\"\n            if [ -n \"${GITHUB_EVENT_INPUTS_SUFFIX}\" ]; then\n              cmd=\"$cmd --suffix ${GITHUB_EVENT_INPUTS_SUFFIX}\"\n            fi\n            eval \"$cmd\"\n          done\n\n      - name: Upload wheel artifacts\n        uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2\n        with:\n          name: zig_wheels\n          path: dist/*.whl\n          if-no-files-found: error\n\n  deploy_wheels:\n    name: Deploy wheels\n    needs: [build_wheels]\n    if: >-\n      github.event.inputs.push_to_pypi == 'true' &&\n      github.repository == 'ziglang/zig-pypi'\n    environment: pypi\n    runs-on: ubuntu-latest\n    permissions:\n      id-token: write # for OIDC trusted publishing\n      attestations: write # for the GitHub Actions Attestations feature\n      contents: read\n    steps:\n      - name: Download all wheel artifacts\n        uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0\n        with:\n          path: dist/\n          merge-multiple: true\n\n      - name: Sanity check wheel artifacts\n        run: ls -R dist/\n\n      - name: Generate artifact attestations\n        uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0\n        with:\n          subject-path: dist/*\n\n      # This will publish the list of wheels inputted to the action to PyPI (set to\n      # off, by default).\n      # The workflow may be triggered multiple times with the `push_to_pypi` input\n      # set to 'true' to publish the wheels for any configurable version (non-dev).\n      - name: Publish wheels to PyPI\n        uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0\n        with:\n          packages-dir: dist/\n\n  inspect_wheels:\n    name: Inspect wheels\n    needs: [build_wheels]\n    runs-on: ubuntu-latest\n    steps:\n      - name: Download all built wheel artifacts\n        uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0\n        with:\n          path: dist/\n          merge-multiple: true\n\n      - name: Inspect wheel artifacts\n        shell: bash\n        run: |\n          echo -e '## A list of built wheels and their SHA-256 checksums \\n' >> $GITHUB_STEP_SUMMARY\n          echo -e '```\\n' >> $GITHUB_STEP_SUMMARY\n          for wheel in dist/*.whl; do\n            shasum --algorithm 256 \"$wheel\" >> $GITHUB_STEP_SUMMARY\n          done\n          echo -e '```\\n' >> $GITHUB_STEP_SUMMARY\n"
  },
  {
    "path": ".gitignore",
    "content": "# Python\n__pycache__/\n*.egg-info\n/dist\n*.whl\n\n# pdm\n/.pdm-plugins\n/.pdm-python\n/.venv\n/pdm.lock\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "The MIT License (Expat)\n\nCopyright (c) 2021, whitequark <whitequark@whitequark.org>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "Zig PyPI distribution\n=====================\n\nThis repository contains the script used to repackage the [releases][zigdl] of the [Zig programming language][zig] as [Python binary wheels][wheel]. This document is intended for maintainers; see the [package README][pkgreadme] for rationale and usage instructions.\n\nThe repackaged artifacts are published as the [ziglang PyPI package][pypi].\n\n[zig]: https://ziglang.org/\n[zigdl]: https://ziglang.org/download/\n[wheel]: https://github.com/pypa/wheel\n[pkgreadme]: README.pypi.md\n[pypi]: https://pypi.org/project/ziglang/\n\nPreparation\n-----------\n\nThe script requires Python 3.9 and later and a [PEP 723][pep723] compatible script\nrunner, such as [`pipx`][pipx], [`pdm`][pdm], [`hatch`][hatch], [`uv`][uv], or\nsimilar. Please refer to their documentation for installation instructions.\n\n[pep723]: https://peps.python.org/pep-0723/\n[pipx]: https://pipx.pypa.io/stable/examples/#pipx-run-examples\n[pdm]: https://pdm-project.org/en/latest/usage/scripts/#single-file-scripts\n[hatch]: https://hatch.pypa.io/latest/blog/2024/05/02/hatch-v1100/#python-script-runner/\n[uv]: https://docs.astral.sh/uv/#script-support/\n\nBuilding wheels\n---------------\n\nRun the repackaging script. Here's an example invocation with [`pdm`][pdm]:\n\n```shell\n$ pdm run make_wheels.py --help\nusage: make_wheels.py [-h] [--version VERSION] [--suffix SUFFIX] [--outdir OUTDIR]\n                                                  [--platform {x86_64-windows,x86_64-macos,aarch64-macos,i386-linux,x86-linux,x86_64-linux,aarch64-linux,armv7a-linux}]\n\nRepackage official Zig downloads as Python wheels\n\noptions:\n  -h, --help            show this help message and exit\n  --version VERSION     version to package, use `latest` for latest release, `master` for nightly build\n  --suffix SUFFIX       wheel version suffix\n  --outdir OUTDIR       target directory\n  --platform {x86_64-windows,x86_64-macos,aarch64-macos,i386-linux,x86-linux,x86_64-linux,aarch64-linux,armv7a-linux}\n                        platform to build for, can be repeated\n```\n\nThis command will download the Zig release archives for every supported platform and convert them to binary wheels, which are placed under `dist/`. The Zig version and platforms can be passed as arguments.\n\nThe process of converting release archives to binary wheels is deterministic, and the output of the script should be bit-for-bit identical regardless of the environment and platform it runs under. To this end, it prints the SHA256 hashes of inputs and outputs; the hashes of the inputs will match the ones on the [Zig downloads page][zigdl], and the hashes of the outputs will match the ones on the [PyPI downloads page][pypidl].\n\n[pypidl]: https://pypi.org/project/ziglang/#files\n\nUploading wheels to PyPI\n------------------------\n\nTrigger the publishing workflow from this repository manually (requires authorization)\nwith the necessary inputs as mentioned in the [workflow file](.github/workflows/cd.yml)\nor in the GitHub Actions UI. The wheels are checked with `twine` before they are uploaded.\n\nThe workflow will upload the wheels to PyPI to make them available for installation. It\nis possible to trigger it multiple times to upload wheels for different versions or\nplatforms.\n\nVerifying the provenance of wheels uploaded to PyPI\n---------------------------------------------------\n\nTo establish build provenance, the workflow generates attestations for the uploaded wheels\nusing the [GitHub Actions Attestations feature](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds)\nwhen it is run. Please navigate to the [Attestations interface](https://github.com/ziglang/zig-pypi/attestations)\nto view the attestations for the uploaded wheels.\n\nThe attestations may be verified via the [GitHub (`gh`) CLI](https://cli.github.com/manual/gh_attestation_verify)\nor via the [GitHub API](https://docs.github.com/en/rest/users/attestations).\n\nLicense\n-------\n\nThis script is distributed under the terms of the [MIT (Expat) license](LICENSE.txt).\n\nPlease refer to the [Zig license](https://ziglang.org/download/#license) for the terms\nof use of the Zig programming language itself, or look in the `.dist-info/licenses/`\ndirectory of the built wheels for individual licenses of the bundled components.\n"
  },
  {
    "path": "README.pypi.md",
    "content": "Zig PyPI distribution\n=====================\n\n[Zig][] is a general-purpose programming language and toolchain for maintaining robust, optimal, and reusable software. The [ziglang][pypi] Python package redistributes the Zig toolchain so that it can be used as a dependency of Python projects.\n\n[zig]: https://ziglang.org/\n[pypi]: https://pypi.org/project/ziglang/\n\nRationale\n---------\n\nAlthough Zig is useful in itself, the Zig toolchain includes a drop-in C and C++ compiler, [`zig cc`][zigcc], based on [clang][]. Unlike clang itself, `zig cc` is standalone: it does not require additional development files to be installed to target any of the platforms it supports. Through `zig cc`, Python code that generates C or C++ code can build it without any external dependencies.\n\n[clang]: https://clang.llvm.org/\n[zigcc]: https://andrewkelley.me/post/zig-cc-powerful-drop-in-replacement-gcc-clang.html\n\nUsage\n-----\n\nTo run the Zig toolchain from the command line, use:\n\n```shell\npython -m ziglang\n```\n\nTo run the Zig toolchain from a Python program, use `sys.executable` to locate the Python binary to invoke. For example:\n\n```python\nimport sys, subprocess\n\nsubprocess.call([sys.executable, \"-m\", \"ziglang\"])\n```\n\nBinary wrapper\n--------------\n\nThe [ziglang][pypi] Python package installs a binary wrapper for the Zig compiler under the name `python-zig`; the name is different to avoid conflicts with any system-wide or user-wide `zig` binaries that may be already installed.\n\n\nUsing with `uv`\n---------------\n\nThe Zig compiler distributed in this Python package can be launched by [uv](https://docs.astral.sh/uv) without installation:\n\n```shell\nuvx --from ziglang python-zig\n```\n\nLicense\n-------\n\nThe [Zig license](https://github.com/ziglang/zig#license).\n"
  },
  {
    "path": "make_wheels.py",
    "content": "# /// script\n# requires-python = \"~=3.9\"\n# dependencies = [\n#   \"wheel~=0.41.0\",\n# ]\n# ///\n\n# Additionally, install twine to upload the wheels to PyPI.\n\nimport argparse\nimport logging\nimport io\nimport os\nimport re\nimport json\nimport hashlib\nimport tarfile\nimport urllib.request\nfrom pathlib import Path, PurePath\nfrom email.policy import EmailPolicy\nfrom email.message import EmailMessage\nfrom wheel.wheelfile import WheelFile\nfrom zipfile import ZipFile, ZipInfo, ZIP_DEFLATED\n\n\nZIG_VERSION_INFO_URL = 'https://ziglang.org/download/index.json'\nZIG_PYTHON_PLATFORMS = {\n    'x86_64-windows': 'win_amd64',\n    'aarch64-windows': 'win_arm64',\n    'x86-windows':    'win32',\n    'x86_64-macos':   'macosx_12_0_x86_64',\n    'aarch64-macos':  'macosx_12_0_arm64',\n    'i386-linux':     'manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686',\n    # renamed i386 to x86 since v0.11.0, i386 was last supported in v0.10.1\n    'x86-linux':      'manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686',\n    'x86_64-linux':   'manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64',\n    'aarch64-linux':\n        'manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64',\n    'armv7a-linux':   'manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l',\n    # renamed armv7a to arm since v0.15.1, armv7a was last supported in v0.14.1\n    'arm-linux':      'manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l',\n    'powerpc64le-linux':  'manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le',\n    's390x-linux':     'manylinux_2_17_s390x.manylinux2014_s390x.musllinux_1_1_s390x',\n    'riscv64-linux':   'manylinux_2_31_riscv64.musllinux_1_1_riscv64',\n}\n\n_YELLOW = \"\\033[93m\"\n\n\nclass ReproducibleWheelFile(WheelFile):\n    def writestr(self, zinfo_or_arcname, data, *args, **kwargs):\n        if isinstance(zinfo_or_arcname, ZipInfo):\n            zinfo = zinfo_or_arcname\n        else:\n            assert isinstance(zinfo_or_arcname, str)\n            zinfo = ZipInfo(zinfo_or_arcname)\n            zinfo.file_size = len(data)\n            zinfo.external_attr = 0o0644 << 16\n            if zinfo_or_arcname.endswith(\".dist-info/RECORD\"):\n                zinfo.external_attr = 0o0664 << 16\n\n        zinfo.compress_type = ZIP_DEFLATED\n        zinfo.date_time = (1980,1,1,0,0,0)\n        zinfo.create_system = 3\n        super().writestr(zinfo, data, *args, **kwargs)\n\n\ndef make_message(headers, payload=None):\n    msg = EmailMessage(policy=EmailPolicy(max_line_length=0))\n    for name, value in headers:\n        if isinstance(value, list):\n            for value_part in value:\n                msg[name] = value_part\n        else:\n            msg[name] = value\n    if payload:\n        msg.set_payload(payload)\n    return msg\n\n\ndef write_wheel_file(filename, contents):\n    with ReproducibleWheelFile(filename, 'w') as wheel:\n        for member_info, member_source in contents.items():\n            wheel.writestr(member_info, bytes(member_source))\n    return filename\n\n\ndef write_wheel(out_dir, *, name, version, tag, metadata, description, contents):\n    wheel_name = f'{name}-{version}-{tag}.whl'\n    dist_info  = f'{name}-{version}.dist-info'\n    filtered_metadata = []\n    for header, value in metadata:\n        filtered_metadata.append((header, value))\n\n    # The WHEEL file must contain the compatibility tags in their expanded form.\n    # see https://packaging.python.org/en/latest/specifications/binary-distribution-format/#file-contents\n    # see https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/#compressed-tag-sets\n    pytag, abitag, platformtag = tag.split(\"-\")\n    expanded_tags = [\n        \"-\".join((x, y, z))\n        for z in platformtag.split(\".\")\n        for y in abitag.split(\".\")\n        for x in pytag.split(\".\")\n    ]\n\n    return write_wheel_file(os.path.join(out_dir, wheel_name), {\n        **contents,\n        f'{dist_info}/entry_points.txt': make_message([],\n            '[console_scripts]\\npython-zig = ziglang.__main__:dummy'\n        ),\n        f'{dist_info}/METADATA': make_message([\n            ('Metadata-Version', '2.4'),\n            ('Name', name),\n            ('Version', version),\n            *filtered_metadata,\n        ], description),\n        f'{dist_info}/WHEEL': make_message([\n            ('Wheel-Version', '1.0'),\n            ('Generator', 'ziglang make_wheels.py'),\n            ('Root-Is-Purelib', 'false'),\n            ('Tag', expanded_tags),\n        ]),\n    })\n\n\ndef iter_archive_contents(archive):\n    magic = archive[:4]\n    if magic[:4] == b\"\\xfd7zX\":\n        with tarfile.open(mode=\"r|xz\", fileobj=io.BytesIO(archive)) as tar:\n            for entry in tar:\n                if entry.isreg():\n                    yield entry.name, entry.mode | (1 << 15), tar.extractfile(entry).read()\n    elif magic[:4] == b\"PK\\x03\\x04\":\n        with ZipFile(io.BytesIO(archive)) as zip_file:\n            for entry in zip_file.infolist():\n                if not entry.is_dir():\n                    yield entry.filename, entry.external_attr >> 16, zip_file.read(entry)\n    else:\n        raise RuntimeError(\"Unsupported archive format\")\n\n\ndef write_ziglang_wheel(out_dir, *, version, platform, archive):\n    contents = {}\n    contents['ziglang/__init__.py'] = b''\n\n    license_files = {}\n    found_license_files = set()\n    potential_extra_licenses = set()\n\n    # A bunch of standard license file patterns. If a file matches any of\n    # these, we need to add them to required_license_paths and metadata.\n    license_patterns = [\n        r'COPYING.*',\n        r'COPYRIGHT.*',\n        r'COPYLEFT.*',\n        r'LICEN[CS]E.*',\n        r'LICEN[CS]E-.*',\n        r'LICEN[CS]E\\..*',\n        r'PATENTS.*',\n        r'NOTICE.*',\n        r'LEGAL.*',\n        r'AUTHORS.*',\n        r'RIGHT*',\n        r'PERMISSION*',\n        r'THIRD[-_]PARTY[-_]LICENSES?.*',\n        r'EULA*',\n        r'MIT*',\n        r'GPL*',\n        r'AGPL*',\n        r'LGPL*',\n        r'APACHE*',\n    ]\n    license_regex = re.compile('|'.join(f'^{pattern}$' for pattern in license_patterns), re.IGNORECASE)\n\n    # These file paths MUST remain in sync with the paths in the official\n    # Zig tarballs and with the ones defined below in the metadata. The\n    # script will raise an error if any of these files are not found in\n    # the archive.\n    required_license_paths = [\n        'LICENSE',\n        'lib/libc/glibc/LICENSES',\n        'lib/libc/mingw/COPYING',\n        'lib/libc/musl/COPYRIGHT',\n        'lib/libc/wasi/LICENSE',\n        'lib/libc/wasi/LICENSE-APACHE',\n        'lib/libc/wasi/LICENSE-APACHE-LLVM',\n        'lib/libc/wasi/LICENSE-MIT',\n        'lib/libc/wasi/libc-bottom-half/cloudlibc/LICENSE',\n        'lib/libc/wasi/libc-top-half/musl/COPYRIGHT',\n        'lib/libcxx/LICENSE.TXT',\n        'lib/libcxxabi/LICENSE.TXT',\n        'lib/libunwind/LICENSE.TXT',\n\t    'lib/libc/freebsd/COPYRIGHT',\n        'lib/libc/wasi/fts/musl-fts/COPYING',\n    ]\n    excluded_license_paths = [\n        # not a license text; contains macros that generate license strings\n        'lib/libc/include/generic-freebsd/sys/copyright.h',\n    ]\n\n    for entry_name, entry_mode, entry_data in iter_archive_contents(archive):\n        entry_name = '/'.join(entry_name.split('/')[1:])\n        if not entry_name:\n            continue\n        if entry_name.startswith('doc/') or entry_name in excluded_license_paths:\n            continue\n\n        # Check for additional license-like files\n        potential_license_filename = PurePath(entry_name).name\n        if license_regex.match(potential_license_filename):\n            potential_extra_licenses.add(entry_name)\n\n        zip_info = ZipInfo(f'ziglang/{entry_name}')\n        zip_info.external_attr = (entry_mode & 0xFFFF) << 16\n        contents[zip_info] = entry_data\n\n        if entry_name in required_license_paths:\n            license_files[entry_name] = entry_data\n            found_license_files.add(entry_name)\n\n        if entry_name.startswith('zig'):\n            contents['ziglang/__main__.py'] = f'''\\\nimport os, sys\nargv = [os.path.join(os.path.dirname(__file__), \"{entry_name}\"), *sys.argv[1:]]\nif os.name == 'posix':\n    os.execv(argv[0], argv)\nelse:\n    import subprocess; sys.exit(subprocess.call(argv))\n\ndef dummy(): \"\"\"Dummy function for an entrypoint. Zig is executed as a side effect of the import.\"\"\"\n'''.encode('ascii')\n\n    # 1. Check for missing required licenses paths\n    missing_licenses = set(required_license_paths) - found_license_files\n    if missing_licenses:\n        error_message = (\n            f\"{_YELLOW}The following required license files were not found in the Zig archive: {', '.join(sorted(missing_licenses))} \"\n            f\"\\nThis may indicate a change in Zig's license file structure or an error in the listing of license files and/or paths.{_YELLOW}\"\n        )\n        raise RuntimeError(error_message)\n\n    # 2. Check for potentially missing license files\n    extra_licenses = potential_extra_licenses - set(required_license_paths)\n    if extra_licenses:\n        error_message = (\n            f\"{_YELLOW}Found additional potential license files in the Zig archive but not included in the metadata: {', '.join(sorted(extra_licenses))} \"\n            f\"\\nPlease consider adding these to the license paths if they should be included.{_YELLOW}\"\n        )\n        raise RuntimeError(error_message)\n\n    with open('README.pypi.md') as f:\n        description = f.read()\n\n    dist_info = f'ziglang-{version}.dist-info'\n    for license_path, license_data in license_files.items():\n        contents[f'{dist_info}/licenses/ziglang/{license_path}'] = license_data\n\n    return write_wheel(out_dir,\n        name='ziglang',\n        version=version,\n        tag=f'py3-none-{platform}',\n        metadata=[\n            ('Summary', 'Zig is a general-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.'),\n            ('Description-Content-Type', 'text/markdown'),\n            # The license expression and the file paths MUST remain in sync\n            # with the paths in the official Zig tarballs and with the ones\n            # defined above in the contents. The difference is that these\n            # are prefixed with \"ziglang/\" to match the paths in the wheel\n            # for metadata compliance.\n            ('License-Expression', 'MIT'),\n            ('License-File', 'ziglang/LICENSE'),\n            ('License-File', 'ziglang/lib/libc/glibc/LICENSES'),\n            ('License-File', 'ziglang/lib/libc/mingw/COPYING'),\n            ('License-File', 'ziglang/lib/libc/musl/COPYRIGHT'),\n            ('License-File', 'ziglang/lib/libc/wasi/LICENSE'),\n            ('License-File', 'ziglang/lib/libc/wasi/LICENSE-APACHE'),\n            ('License-File', 'ziglang/lib/libc/wasi/LICENSE-APACHE-LLVM'),\n            ('License-File', 'ziglang/lib/libc/wasi/LICENSE-MIT'),\n            ('License-File', 'ziglang/lib/libc/wasi/libc-bottom-half/cloudlibc/LICENSE'),\n            ('License-File', 'ziglang/lib/libc/wasi/libc-top-half/musl/COPYRIGHT'),\n            ('License-File', 'ziglang/lib/libcxx/LICENSE.TXT'),\n            ('License-File', 'ziglang/lib/libcxxabi/LICENSE.TXT'),\n            ('License-File', 'ziglang/lib/libunwind/LICENSE.TXT'),\n            ('License-File', 'ziglang/lib/libc/freebsd/COPYRIGHT'),\n            ('Classifier', 'Development Status :: 4 - Beta'),\n            ('Classifier', 'Intended Audience :: Developers'),\n            ('Classifier', 'Topic :: Software Development :: Compilers'),\n            ('Classifier', 'Topic :: Software Development :: Code Generators'),\n            ('Classifier', 'Topic :: Software Development :: Build Tools'),\n            ('Classifier', 'Programming Language :: Zig'),\n            ('Project-URL', 'Homepage, https://ziglang.org'),\n            ('Project-URL', 'Source Code, https://github.com/ziglang/zig-pypi'),\n            ('Project-URL', 'Bug Tracker, https://github.com/ziglang/zig-pypi/issues'),\n            ('Requires-Python', '~=3.5'),\n        ],\n        description=description,\n        contents=contents,\n    )\n\n\ndef fetch_zig_version_info():\n    with urllib.request.urlopen(ZIG_VERSION_INFO_URL) as request:\n        return json.loads(request.read())\n\n\ndef fetch_and_write_ziglang_wheels(\n    outdir='dist/', zig_version='master', wheel_version_suffix='', platforms=tuple()\n):\n    Path(outdir).mkdir(exist_ok=True)\n    if not platforms:\n        platforms = list(ZIG_PYTHON_PLATFORMS)\n    zig_versions_info = fetch_zig_version_info()\n\n    if zig_version == 'latest':\n        zig_version = [version for version in zig_versions_info if version != 'master'][0]\n\n    try:\n        zig_version_info = zig_versions_info[zig_version]\n    except KeyError:\n        print(f\"Invalid version, valid values: {list(zig_versions_info)}\")\n        raise\n\n    effective_zig_version = zig_version_info.get('version', zig_version)\n\n    for zig_platform in platforms:\n        python_platform = ZIG_PYTHON_PLATFORMS[zig_platform]\n        if zig_platform not in zig_version_info:\n            print(f\"{zig_platform} not present for \"\n                  f\"version {zig_version} / {effective_zig_version}\")\n            continue\n        zig_download = zig_version_info[zig_platform]\n        zig_url = zig_download['tarball']\n        expected_hash = zig_download['shasum']\n\n        with urllib.request.urlopen(zig_url) as request:\n            zig_archive = request.read()\n            zig_archive_hash = hashlib.sha256(zig_archive).hexdigest()\n            if zig_archive_hash != expected_hash:\n                raise Exception(\n                    f\"SHA256 hash mismatch for {zig_download}! expected shasum {expected_hash}\")\n            print(f'{hashlib.sha256(zig_archive).hexdigest()} {zig_url}')\n\n        wheel_version = effective_zig_version.split('+')[0].replace('-', '.')\n        wheel_path = write_ziglang_wheel(outdir,\n            version=wheel_version + wheel_version_suffix,\n            platform=python_platform,\n            archive=zig_archive)\n        with open(wheel_path, 'rb') as wheel:\n            print(f'  {hashlib.sha256(wheel.read()).hexdigest()} {wheel_path}')\n\n\ndef get_argparser():\n    supported_platforms = ', '.join(sorted(ZIG_PYTHON_PLATFORMS.keys()))\n    description = (f\"Repackage official Zig downloads as Python wheels.\\n\\n\"\n                   f\"Supported platforms: {supported_platforms}\")\n\n    parser = argparse.ArgumentParser(prog=__file__, description=description,\n                                   formatter_class=argparse.RawDescriptionHelpFormatter)\n    parser.add_argument('--version', default='latest',\n                        help=\"version to package, use `latest` for latest release, `master` for nightly build\")\n    parser.add_argument('--suffix', default='', help=\"wheel version suffix\")\n    parser.add_argument('--outdir', default='dist/', help=\"target directory\")\n    parser.add_argument('--platform', action='append', default=[],\n                        help=\"platform to build for, use 'all' to build for all supported platforms, can be repeated\")\n    return parser\n\n\ndef main():\n    args = get_argparser().parse_args()\n    logging.getLogger(\"wheel\").setLevel(logging.WARNING)\n\n    platforms = args.platform\n    if 'all' in platforms:\n        platforms = list(ZIG_PYTHON_PLATFORMS.keys())\n\n\n    fetch_and_write_ziglang_wheels(outdir=args.outdir, zig_version=args.version,\n                                   wheel_version_suffix=args.suffix, platforms=platforms)\n\n\nif __name__ == '__main__':\n    main()\n"
  }
]