diff --git a/.github/workflows/build-gevent.yml b/.github/workflows/build-gevent.yml new file mode 100644 index 000000000..e142b219b --- /dev/null +++ b/.github/workflows/build-gevent.yml @@ -0,0 +1,142 @@ +# SPDX-FileCopyrightText: 2026 The RISE Project +# SPDX-License-Identifier: MIT +--- +# This workflow is based on the `manylinux` job of +# https://github.com/gevent/gevent/blob/26.8.0/.github/workflows/ci.yml and the +# scripts/releases/make-manylinux script it runs. +name: Build gevent wheels (riscv64) + +on: + workflow_dispatch: + inputs: + version: + description: 'gevent version to build (git tag, e.g. 26.8.0)' + required: true + default: '26.8.0' + pull_request: + paths: + - '.github/workflows/build-gevent.yml' + +concurrency: + group: ${{ github.workflow }}-${{ inputs.version || '26.8.0' }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read # to fetch code (actions/checkout) + +env: + GEVENT_VERSION: ${{ inputs.version || '26.8.0' }} + MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 + +jobs: + build_wheels: + name: Build gevent ${{ inputs.version || '26.8.0' }} ${{ matrix.python }}-manylinux_riscv64 + runs-on: ubuntu-24.04-riscv + strategy: + fail-fast: false + matrix: + python: + # make-manylinux skips free-threaded builds: "The GIL is required". + - "cp312" + - "cp313" + - "cp314" + + steps: + - name: Checkout gevent ${{ env.GEVENT_VERSION }} + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + repository: gevent/gevent + ref: ${{ env.GEVENT_VERSION }} + persist-credentials: false + + - name: Checkout python-wheels + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + path: python-wheels + persist-credentials: false + + # The wheel statically compiles libev, libuv and c-ares but ships only gevent's + # own LICENSE. + - name: Patch gevent source + run: | + git apply python-wheels/patches/gevent/${{ env.GEVENT_VERSION }}/00*.patch + + - name: Build wheels + uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0 + with: + output-dir: wheelhouse/ + only: ${{ matrix.python }}-manylinux_riscv64 + env: + CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }} + CIBW_BEFORE_ALL_LINUX: yum -y install libffi-devel + # As in make-manylinux: NO_CYTHON_COMPILE keeps Cython, which has no riscv64 + # binary wheel, from compiling its own accelerators here; TRAVIS is how it tells + # setup.py it is on CI, which makes the c-ares extension required, not optional. + CIBW_ENVIRONMENT: >- + NO_CYTHON_COMPILE=true + CI=1 + TRAVIS=true + PIP_EXTRA_INDEX_URL=https://pypi.riseproject.dev/simple/ + CIBW_TEST_EXTRAS: test + # The monkey-patched stdlib tests live in src/greentest and are found by climbing + # to setup.py, so both have to be staged or the runner just warns and skips them + # (17 of 86 test commands). src/gevent stays out so the wheel is what is imported. + CIBW_TEST_SOURCES: setup.py src/greentest examples + # GEVENT_MANYLINUX is test-only: during the build it makes setup.py assume + # c-ares was already configured by a separate step, which we don't have. + CIBW_TEST_ENVIRONMENT: >- + GEVENT_MANYLINUX=1 + GEVENT_MANYLINUX_NAME=manylinux_2_39_riscv64 + GEVENT_LOOP=libev-cext + GEVENTTEST_USE_RESOURCES=-network + PYTHONHASHSEED=8675309 + CIBW_TEST_COMMAND: >- + python -c "import gevent; print(gevent, gevent.__version__)" && + python -c "import gevent.core; print('default loop', gevent.core.loop)" && + GEVENT_LOOP=libuv python -c "import gevent.core; print('libuv loop', gevent.core.loop)" && + GEVENT_LOOP=libev-cffi python -c "import gevent.core; print('libev-cffi loop', gevent.core.loop)" && + python -c "import gevent.ares; print('ares', gevent.ares)" && + python -c "import importlib.metadata as m; f=[str(p) for p in m.files('gevent')]; missing=[n for n in ('licenses/LICENSE','licenses/NOTICE','licenses/deps/c-ares/LICENSE.md','licenses/deps/libev/LICENSE','licenses/deps/libuv/LICENSE','licenses/deps/libuv/LICENSE-extra') if not any(s.endswith(n) for s in f)]; assert not missing, missing" && + python -m gevent.tests --second-chance + + - name: Check the compiled extensions made it into the wheel + run: | + python3 - wheelhouse/*.whl <<'EOF' + import sys, zipfile + # gevent.resolver.cares is declared optional unless setup.py detects it is + # running on CI from a checkout, so a failed build silently drops it. + expected = ( + 'gevent/libev/corecext', 'gevent/libev/_corecffi', + 'gevent/libuv/_corecffi', 'gevent/resolver/cares', + 'gevent/_gevent_cgreenlet', 'gevent/_gevent_cqueue', + ) + for whl in sys.argv[1:]: + sos = [n for n in zipfile.ZipFile(whl).namelist() if n.endswith('.so')] + missing = [e for e in expected if not any(n.startswith(e) for n in sos)] + assert not missing, (whl, missing, sos) + print(whl, len(sos), 'extension modules ok') + EOF + + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: gevent-${{ env.GEVENT_VERSION }}-${{ matrix.python }}-manylinux_riscv64 + path: wheelhouse/*.whl + if-no-files-found: error + + publish: + name: Publish gevent ${{ inputs.version || '26.8.0' }} to GitLab + needs: [build_wheels] + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + + steps: + - name: Publish wheels and open docs PR + uses: riseproject-dev/python-wheels/actions/publish-wheels@main + with: + artifact-pattern: gevent-${{ env.GEVENT_VERSION }}-*-manylinux_riscv64 + gitlab-username: ${{ vars.GITLAB_DEPLOY_USER }} + gitlab-token: ${{ secrets.GITLAB_DEPLOY_TOKEN }} + gitlab-project-id: ${{ vars.GITLAB_PROJECT_ID }} + gh-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/patches/gevent/26.8.0/0001-package-the-licences-of-the-embedded-libev-libuv-and.patch b/patches/gevent/26.8.0/0001-package-the-licences-of-the-embedded-libev-libuv-and.patch new file mode 100644 index 000000000..a110290b9 --- /dev/null +++ b/patches/gevent/26.8.0/0001-package-the-licences-of-the-embedded-libev-libuv-and.patch @@ -0,0 +1,77 @@ +From c85027ca757d661635d7c02f1b60e73eb9b19187 Mon Sep 17 00:00:00 2001 +From: Ludovic Henry +Date: Wed, 26 Aug 2026 13:24:02 +0200 +Subject: [PATCH] package the licences of the embedded libev, libuv and c-ares + +Upstream-Status: To upstream [not yet submitted; the same gap exists in every gevent wheel on PyPI, so this needs a maintainer discussion rather than a drive-by PR] + +The wheels statically compile the bundled deps/libev, deps/libuv and +deps/c-ares sources into gevent.libev.corecext, gevent.libev._corecffi, +gevent.libuv._corecffi and gevent.resolver.cares. libev is BSD 2-clause +(or GPL 2+), libuv and c-ares are MIT; all three require the copyright +notice to travel with binary redistributions, but setup.py names only +'LICENSE' in license_files, so the wheel ships gevent's own licence alone. + +The vendored c-ares tree carries no licence file at all -- the notice +appears only in the per-file headers -- so restore LICENSE.md from the +vendored release (c-ares 1.34.5). + +NOTICE is added for the same reason: it carries the PSF licence covering +the stdlib test files copied under gevent/tests and the guv copyright of +gevent/libuv/_corecffi_*.c, both of which do ship in the wheel. + +Signed-off-by: Ludovic Henry +--- + deps/c-ares/LICENSE.md | 24 ++++++++++++++++++++++++ + setup.py | 7 +++++++ + 2 files changed, 31 insertions(+) + create mode 100644 deps/c-ares/LICENSE.md + +diff --git a/deps/c-ares/LICENSE.md b/deps/c-ares/LICENSE.md +new file mode 100644 +index 0000000..910ddde +--- /dev/null ++++ b/deps/c-ares/LICENSE.md +@@ -0,0 +1,24 @@ ++MIT License ++ ++Copyright (c) 1998 Massachusetts Institute of Technology ++Copyright (c) 2007 - 2023 Daniel Stenberg with many contributors, see AUTHORS ++file. ++ ++Permission is hereby granted, free of charge, to any person obtaining a copy of ++this software and associated documentation files (the "Software"), to deal in ++the Software without restriction, including without limitation the rights to ++use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of ++the Software, and to permit persons to whom the Software is furnished to do so, ++subject to the following conditions: ++ ++The above copyright notice and this permission notice (including the next ++paragraph) shall be included in all copies or substantial portions of the ++Software. ++ ++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ++OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE ++SOFTWARE. +diff --git a/setup.py b/setup.py +index 878a360..22ef420 100755 +--- a/setup.py ++++ b/setup.py +@@ -349,6 +349,13 @@ def run_setup(ext_modules): + license='MIT', # pep 639, use SPDX license identifiers + license_files=[ + 'LICENSE', ++ 'NOTICE', ++ # Embedded and statically linked into the extension modules; their ++ # BSD/MIT terms require the copyright notice to ship with the binary. ++ 'deps/c-ares/LICENSE.md', ++ 'deps/libev/LICENSE', ++ 'deps/libuv/LICENSE', ++ 'deps/libuv/LICENSE-extra', + ], + project_urls={ + 'Bug Tracker': 'https://github.com/gevent/gevent/issues',