docs: Update projects #27
This file contains hidden or 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
| # SPDX-FileCopyrightText: 2026 The RISE Project | |
| # SPDX-License-Identifier: MIT | |
| --- | |
| # Upstream builds eccodeslib via a private tool (ecmwf-actions/reusable-workflows' | |
| # python-wrapper-wheel.yml + the "wheelmaker" image), not a public workflow, so this | |
| # replays ecmwf/eccodes's own python_wrapper/buildconfig CMAKE_PARAMS directly. The | |
| # built libeccodes.so is byte-identical across upstream's cp310..cp314 wheels (no | |
| # Python C-API use), so this builds one py3-none wheel instead of a per-interpreter | |
| # matrix. ENABLE_ECKIT_GEO is set to its CMake default (OFF; upstream forces it ON) | |
| # since eckit has no riscv64 build yet; this only drops the optional geo-iterator | |
| # backend, not core GRIB/BUFR support. | |
| name: Build eccodeslib wheels (riscv64) | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version glob to (re)build; empty builds every version of docs/packages/eccodeslib.yaml not released yet' | |
| required: false | |
| default: '' | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - '.github/workflows/build-eccodeslib.yml' | |
| - 'docs/packages/eccodeslib.yaml' | |
| push: | |
| branches: [main] | |
| paths: | |
| - '.github/workflows/build-eccodeslib.yml' | |
| - 'docs/packages/eccodeslib.yaml' | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read # to fetch code (actions/checkout) | |
| env: | |
| MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64 | |
| ECBUILD_VERSION: '3.15.2' | |
| OPENJPEG_VERSION: '2.5.2' | |
| LIBAEC_VERSION: '1.1.4' | |
| jobs: | |
| setup: | |
| uses: $/.github/workflows/_setup.yml | |
| with: | |
| package: eccodeslib | |
| version: ${{ inputs.version }} | |
| build_wheels: | |
| needs: [setup] | |
| if: needs.setup.outputs.versions != '[]' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| version: ${{ fromJSON(needs.setup.outputs.versions) }} | |
| name: Build eccodeslib ${{ matrix.version }} py3-none-manylinux_riscv64 | |
| runs-on: ubuntu-24.04-riscv | |
| timeout-minutes: 420 | |
| env: | |
| PACKAGE_VERSION: ${{ matrix.version }} | |
| steps: | |
| - name: Derive the eccodes git tag from the package version | |
| run: echo "ECCODES_VERSION=$(echo "$PACKAGE_VERSION" | sed -E 's/\.[0-9]+$//')" >> "$GITHUB_ENV" | |
| - name: Checkout eccodes ${{ env.ECCODES_VERSION }} | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| repository: ecmwf/eccodes | |
| ref: ${{ env.ECCODES_VERSION }} | |
| persist-credentials: false | |
| - name: Record the resolved commit | |
| run: echo "ECCODES_COMMIT=$(git rev-parse HEAD)" >> "$GITHUB_ENV" | |
| - name: Write the wheel packaging script | |
| run: | | |
| cat > build_wheel.py <<'PY' | |
| import hashlib | |
| import os | |
| import sys | |
| import zipfile | |
| from base64 import urlsafe_b64encode | |
| PKG = "eccodeslib" | |
| VERSION, PLATFORM_TAG, INSTALL_DIR, LICENSES_DIR, OUT_DIR = sys.argv[1:6] | |
| WHEEL_TAG = f"py3-none-{PLATFORM_TAG}" | |
| DIST_INFO = f"{PKG}-{VERSION}.dist-info" | |
| METADATA = f"""Metadata-Version: 2.4 | |
| Name: {PKG} | |
| Version: {VERSION} | |
| Summary: Compiled ecCodes C library (GRIB/BUFR decoding and encoding), no Python bindings | |
| Home-page: https://confluence.ecmwf.int/display/ECC/ecCodes+Home | |
| Project-URL: Source, https://github.com/ecmwf/eccodes | |
| License-Expression: Apache-2.0 | |
| """ | |
| WHEEL = f"""Wheel-Version: 1.0 | |
| Generator: python-wheels-riscv64-port | |
| Root-Is-Purelib: false | |
| Tag: {WHEEL_TAG} | |
| """ | |
| os.makedirs(OUT_DIR, exist_ok=True) | |
| wheel_path = os.path.join(OUT_DIR, f"{PKG}-{VERSION}-{WHEEL_TAG}.whl") | |
| records = [] | |
| def write_file(zf, arcname, path): | |
| with open(path, "rb") as f: | |
| data = f.read() | |
| info = zipfile.ZipInfo(arcname) | |
| info.external_attr = (os.stat(path).st_mode & 0xFFFF) << 16 | |
| zf.writestr(info, data, zipfile.ZIP_DEFLATED) | |
| digest = urlsafe_b64encode(hashlib.sha256(data).digest()).rstrip(b"=").decode() | |
| records.append(f"{arcname},sha256={digest},{len(data)}") | |
| def write_bytes(zf, arcname, data): | |
| zf.writestr(arcname, data) | |
| digest = urlsafe_b64encode(hashlib.sha256(data).digest()).rstrip(b"=").decode() | |
| records.append(f"{arcname},sha256={digest},{len(data)}") | |
| with zipfile.ZipFile(wheel_path, "w", zipfile.ZIP_DEFLATED) as zf: | |
| for root, _dirs, files in os.walk(INSTALL_DIR): | |
| for name in sorted(files): | |
| path = os.path.join(root, name) | |
| rel = os.path.relpath(path, INSTALL_DIR) | |
| write_file(zf, f"{PKG}/{rel}", path) | |
| for name in sorted(os.listdir(LICENSES_DIR)): | |
| write_file(zf, f"{DIST_INFO}/licenses/{name}", os.path.join(LICENSES_DIR, name)) | |
| write_bytes(zf, f"{DIST_INFO}/METADATA", METADATA.encode()) | |
| write_bytes(zf, f"{DIST_INFO}/WHEEL", WHEEL.encode()) | |
| write_bytes(zf, f"{DIST_INFO}/top_level.txt", f"{PKG}\n".encode()) | |
| record_name = f"{DIST_INFO}/RECORD" | |
| zf.writestr(record_name, "\n".join(records + [f"{record_name},,"]) + "\n") | |
| print(wheel_path) | |
| PY | |
| - name: Build eccodes and its vendored codecs, then package the wheel | |
| run: | | |
| docker run --rm \ | |
| -v "$(pwd)":/workspace \ | |
| --workdir /workspace \ | |
| -e PACKAGE_VERSION="$PACKAGE_VERSION" \ | |
| -e ECCODES_COMMIT="$ECCODES_COMMIT" \ | |
| -e ECBUILD_VERSION="$ECBUILD_VERSION" \ | |
| -e OPENJPEG_VERSION="$OPENJPEG_VERSION" \ | |
| -e LIBAEC_VERSION="$LIBAEC_VERSION" \ | |
| "$MANYLINUX_RISCV64_IMAGE" \ | |
| bash -c ' | |
| set -euo pipefail | |
| dnf -y -q install libpng-devel | |
| mkdir -p /tmp/deps /tmp/build /tmp/install/eccodeslib /tmp/licenses | |
| curl -fsSL "https://github.com/ecmwf/ecbuild/archive/refs/tags/$ECBUILD_VERSION.tar.gz" | tar xz -C /tmp/build | |
| cmake -S "/tmp/build/ecbuild-$ECBUILD_VERSION" -B /tmp/build/ecbuild-build -D CMAKE_INSTALL_PREFIX=/tmp/deps | |
| cmake --build /tmp/build/ecbuild-build -j "$(nproc)" | |
| cmake --install /tmp/build/ecbuild-build | |
| mkdir -p /tmp/build/libaec-src | |
| curl -fsSL "https://github.com/Deutsches-Klimarechenzentrum/libaec/releases/download/v$LIBAEC_VERSION/libaec-$LIBAEC_VERSION.tar.gz" | tar xz --strip-components=1 -C /tmp/build/libaec-src | |
| cmake -S /tmp/build/libaec-src -B /tmp/build/libaec-build \ | |
| -D CMAKE_BUILD_TYPE=Release -D CMAKE_INSTALL_PREFIX=/tmp/deps -D CMAKE_INSTALL_LIBDIR=lib \ | |
| -D BUILD_STATIC_LIBS=OFF -D BUILD_TESTING=OFF | |
| cmake --build /tmp/build/libaec-build -j "$(nproc)" | |
| cmake --install /tmp/build/libaec-build | |
| mkdir -p /tmp/build/openjpeg-src | |
| curl -fsSL "https://github.com/uclouvain/openjpeg/archive/refs/tags/v$OPENJPEG_VERSION.tar.gz" | tar xz --strip-components=1 -C /tmp/build/openjpeg-src | |
| cmake -S /tmp/build/openjpeg-src -B /tmp/build/openjpeg-build \ | |
| -D CMAKE_BUILD_TYPE=RelWithDebInfo -D CMAKE_INSTALL_PREFIX=/tmp/deps -D CMAKE_INSTALL_LIBDIR=lib \ | |
| -D BUILD_CODEC=OFF | |
| cmake --build /tmp/build/openjpeg-build -j "$(nproc)" | |
| cmake --install /tmp/build/openjpeg-build | |
| cmake -S . -B /tmp/build/eccodes-build \ | |
| -D CMAKE_BUILD_TYPE=RelWithDebInfo \ | |
| -D CMAKE_PREFIX_PATH=/tmp/deps \ | |
| -D CMAKE_INSTALL_PREFIX=/tmp/install/eccodeslib \ | |
| -D CMAKE_INSTALL_LIBDIR=lib64 \ | |
| -D Python3_EXECUTABLE=/opt/python/cp312-cp312/bin/python3 \ | |
| -D ENABLE_PNG=1 \ | |
| -D ENABLE_JPG=1 -D ENABLE_JPG_LIBJASPER=0 -D ENABLE_JPG_LIBOPENJPEG=1 -D OPENJPEG_DIR=/tmp/deps \ | |
| -D ENABLE_NETCDF=0 -D ENABLE_FORTRAN=0 \ | |
| -D ENABLE_EXAMPLES=0 -D ENABLE_BUILD_TOOLS=1 \ | |
| -D ENABLE_INSTALL_ECCODES_DEFINITIONS=0 -D ENABLE_INSTALL_ECCODES_SAMPLES=0 \ | |
| -D ENABLE_ECCODES_THREADS=1 -D ENABLE_MEMFS=1 -D ENABLE_ECKIT_GEO=0 \ | |
| -D ENABLE_AEC=1 | |
| cmake --build /tmp/build/eccodes-build -j "$(nproc)" | |
| cmake --install /tmp/build/eccodes-build | |
| cp /tmp/deps/lib/libopenjp2.so* /tmp/install/eccodeslib/lib64/ | |
| cp /tmp/deps/lib/libaec.so* /tmp/install/eccodeslib/lib64/ | |
| cp "$(find /usr/lib* -name "libpng16.so.16*" | head -1)" /tmp/install/eccodeslib/lib64/ | |
| cp LICENSE /tmp/licenses/eccodes.txt | |
| cp AUTHORS /tmp/licenses/ | |
| curl -fsSL "https://raw.githubusercontent.com/uclouvain/openjpeg/v$OPENJPEG_VERSION/LICENSE" -o /tmp/licenses/openjpeg.txt | |
| curl -fsSL "https://raw.githubusercontent.com/MathisRosenhauer/libaec/v$LIBAEC_VERSION/LICENSE.txt" -o /tmp/licenses/libaec.txt | |
| cp /usr/share/licenses/libpng/LICENSE /tmp/licenses/libpng.txt | |
| printf "__version__ = \"%s\"\n__commit_hash__ = \"%s\"\nfindlibs_dependencies = []\n" "$PACKAGE_VERSION" "$ECCODES_COMMIT" > /tmp/install/eccodeslib/__init__.py | |
| python3 build_wheel.py "$PACKAGE_VERSION" manylinux_2_39_riscv64 /tmp/install/eccodeslib /tmp/licenses wheelhouse | |
| ' | |
| - name: Check the wheel ships the extensions and the bundled licences | |
| run: | | |
| python3 - wheelhouse/*.whl <<'EOF' | |
| import sys, zipfile | |
| names = zipfile.ZipFile(sys.argv[1]).namelist() | |
| assert any(n.endswith("lib64/libeccodes.so") for n in names), names | |
| for licence in ("eccodes.txt", "openjpeg.txt", "libaec.txt", "libpng.txt"): | |
| assert any( | |
| n.endswith(f".dist-info/licenses/{licence}") for n in names | |
| ), (licence, names) | |
| EOF | |
| - name: Smoke-test the built library | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -y -qq --no-install-recommends python3-venv | |
| python3 -m venv .venv | |
| . .venv/bin/activate | |
| # gotcha 234: stock Ubuntu 24.04 apt pip (24.0) has zero manylinux_*_riscv64 | |
| # tags, so it rejects the riscv64 wheel outright without upgrading first. | |
| pip install -q --upgrade pip | |
| pip install -q findlibs wheelhouse/*.whl | |
| python3 -c " | |
| import findlibs | |
| lib = findlibs.load('eccodes') | |
| print(lib) | |
| " | |
| - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: eccodeslib-${{ matrix.version }}-py3-none-manylinux_riscv64 | |
| path: wheelhouse/*.whl | |
| if-no-files-found: error | |
| publish: | |
| name: Publish eccodeslib ${{ matrix.version }} | |
| needs: [setup, build_wheels] | |
| 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: eccodeslib-${{ matrix.version }}-*-manylinux_riscv64 |