Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions .github/workflows/build-pyicu-wheels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on: https://github.com/Init7/pyicu/blob/v2.15.2/.github/workflows/build.yml
name: Build pyicu-wheels wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'Version glob to (re)build; empty builds every version of docs/packages/pyicu-wheels.yaml not released yet'
required: false
default: ''
pull_request:
branches: [main]
paths:
- '.github/workflows/build-pyicu-wheels.yml'
- 'docs/packages/pyicu-wheels.yaml'
- 'patches/pyicu-wheels/**'
push:
branches: [main]
paths:
- '.github/workflows/build-pyicu-wheels.yml'
- 'docs/packages/pyicu-wheels.yaml'
- 'patches/pyicu-wheels/**'

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

permissions:
contents: read # to fetch code (actions/checkout)

env:
UV_EXTRA_INDEX_URL: https://pypi.riseproject.dev/simple/
UV_INDEX_STRATEGY: unsafe-best-match
UV_ONLY_BINARY: ':all:'
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

jobs:
setup:
uses: $/.github/workflows/_setup.yml
with:
package: pyicu-wheels
version: ${{ inputs.version }}

linux:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
name: Build pyicu-wheels ${{ matrix.version }} ${{ matrix.python }}-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 240
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
python: ["cp312", "cp313", "cp314", "cp314t"]

env:
PYICU_WHEELS_VERSION: ${{ matrix.version }}
# A container-local ICU prefix; upstream's /host/tmp/.build only exists to feed its actions/cache.
_LIBICU_DIR: "/tmp/.build"

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: Init7/pyicu
ref: v${{ env.PYICU_WHEELS_VERSION }}
persist-credentials: false

- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: python-wheels
persist-credentials: false

- name: Apply riscv64 patches
run: git apply -v python-wheels/patches/pyicu-wheels/${{ env.PYICU_WHEELS_VERSION }}/*.patch

- uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
python-version: '3.12'
activate-environment: true
enable-cache: false

- name: Install Hatch
run: uv pip install --upgrade hatch

- name: Export PYICU_VERSION and LIBICU_VERSION
run: |
python - >> "$GITHUB_ENV" <<'EOF'
import tomllib
env = tomllib.load(open("pyproject.toml", "rb"))["tool"]["hatch"]["envs"]["default"]["env-vars"]
for key in ("PYICU_VERSION", "LIBICU_VERSION"):
print(f"{key}={env[key]}")
EOF

- name: Fetch pyicu source
run: hatch run pyicu:clone

- name: Copy src and tests
run: |
hatch run pyicu:src
hatch run pyicu:tests

- 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_ENVIRONMENT: MAKEFLAGS="-j$(nproc)"

- name: Check the wheel bundles ICU and its licences
run: |
python - wheelhouse/*.whl <<'EOF'
import sys, zipfile
for whl in sys.argv[1:]:
names = zipfile.ZipFile(whl).namelist()
assert any(n.startswith("icu/_icu_") and n.endswith(".so") for n in names), (whl, names)
assert any(n.startswith("pyicu_wheels.libs/libicudata") for n in names), (whl, names)
for lic in ("LICENSE.txt", "licenses/icu.txt", "licenses/pyicu.txt"):
assert any(n.endswith(".dist-info/licenses/" + lic) for n in names), (whl, lic, names)
print(whl, "OK")
EOF

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: pyicu-wheels-${{ env.PYICU_WHEELS_VERSION }}-${{ matrix.python }}-manylinux_riscv64
path: wheelhouse/*.whl
if-no-files-found: error

publish:
name: Publish pyicu-wheels ${{ matrix.version }}
needs: [setup, linux]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
secrets:
app-private-key: ${{ secrets.RISEPROJECT_APP_PRIVATE_KEY }}
with:
artifact-pattern: pyicu-wheels-${{ matrix.version }}-*-manylinux_riscv64
6 changes: 6 additions & 0 deletions docs/packages/pyicu-wheels.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package-name: pyicu-wheels
source-code: https://github.com/Init7/pyicu
license: Apache-2.0
versions:
- version: 2.15.2
patched: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 28 Sep 2026 00:00:00 +0200
Subject: [PATCH] before-build-linux: accept Rocky Linux

scripts/before-build-linux.sh dispatches on /etc/os-release's ID and
exits 1 on any distribution it does not list. manylinux_2_28 is
AlmaLinux 8, but manylinux_2_39 (the only manylinux image published for
riscv64) is Rocky Linux 10, whose ID is "rocky", so the script aborts
before ICU is built. Rocky takes exactly the AlmaLinux path: dnf for
wget, then ld.so.conf + ldconfig for the ICU prefix.

Upstream-Status: To upstream [not submitted from this automated port run; needs a pull request against Init7/pyicu]
---
scripts/before-build-linux.sh | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scripts/before-build-linux.sh b/scripts/before-build-linux.sh
index 8d05caa..57f054f 100755
--- a/scripts/before-build-linux.sh
+++ b/scripts/before-build-linux.sh
@@ -22,7 +22,7 @@ case "${ID}" in
yum install -y wget
;;

- almalinux)
+ almalinux|rocky)
dnf -y install wget
;;

@@ -45,7 +45,7 @@ fi

# NOTE: configure library search paths
case "${ID}" in
- almalinux|centos)
+ almalinux|centos|rocky)
echo "${_LIBICU_DIR}/lib" >> /etc/ld.so.conf
ldconfig
;;
--
2.43.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 28 Sep 2026 00:00:00 +0200
Subject: [PATCH] pyproject: ship the ICU and PyICU licences in the wheel

The wheel bundles PyICU's extension (MIT) and, via auditwheel,
libicudata/libicuuc/libicui18n (Unicode-3.0 plus the third-party notices
in ICU's LICENSE). Both notices already sit in licenses/, but hatchling
only picks up the root LICENSE.txt by default, so the released wheels
carry the Apache-2.0 text alone. Listing licenses/*.txt in PEP 639
license-files puts them in dist-info/licenses/ with no other change.

Upstream's own 2.15.2 wheels on PyPI carry the same gap on every
platform.

Upstream-Status: To upstream [not submitted from this automated port run; needs a pull request against Init7/pyicu]
---
pyproject.toml | 1 +
1 file changed, 1 insertion(+)

diff --git a/pyproject.toml b/pyproject.toml
index 2ee507f..7c12f33 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -9,6 +9,7 @@ description = 'Wheels for PyICU'
readme = "README.md"
requires-python = ">=3.10"
license = "Apache-2.0"
+license-files = ["LICENSE.txt", "licenses/*.txt"]
keywords = ["icu", "i18n", "wheel"]
classifiers = [
"Development Status :: 4 - Beta",
--
2.43.0
Loading