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
177 changes: 177 additions & 0 deletions .github/workflows/build-iterfzf.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on: https://github.com/dahlia/iterfzf/blob/1.9.0.67.0/.github/workflows/release.yaml
# and https://github.com/dahlia/iterfzf/blob/1.9.0.67.0/.github/workflows/test.yaml
name: Build iterfzf wheels (riscv64)

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

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

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

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

build_wheel:
needs: [setup]
if: needs.setup.outputs.versions != '[]'
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
name: Build iterfzf ${{ matrix.version }} py3-none-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 30

env:
ITERFZF_VERSION: ${{ matrix.version }}

steps:
- name: Checkout iterfzf ${{ matrix.version }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: dahlia/iterfzf
ref: ${{ env.ITERFZF_VERSION }}
persist-credentials: false

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

- name: Apply patches
run: git apply -v python-wheels/patches/iterfzf/${{ env.ITERFZF_VERSION }}/*.patch

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

- name: Install build
run: uv pip install build

# GITHUB_TOKEN lifts the anonymous rate limit on the release lookup
# build_dist.py makes to resolve the fzf asset, as upstream's own jobs do.
- name: Build wheel
env:
GITHUB_TOKEN: ${{ github.token }}
run: GOOS=linux GOARCH=riscv64 python -m build --wheel .

- name: Verify the wheel ships the riscv64 fzf binary
run: |
python - dist/*.whl <<'EOF'
import sys, zipfile
with zipfile.ZipFile(sys.argv[1]) as zf:
names = zf.namelist()
print("\n".join(names))
assert sys.argv[1].endswith("-py3-none-manylinux_2_39_riscv64.whl"), sys.argv[1]
assert "iterfzf/fzf" in names, names
assert "iterfzf/fzf.exe" not in names, names
licenses = sorted(n.rsplit("/", 1)[-1] for n in names if ".dist-info/licenses/" in n)
assert licenses == ["LICENSE"], licenses
header = zf.read("iterfzf/fzf")[:20]
assert header[:4] == b"\x7fELF", header
assert header[18] == 0xF3, header
EOF

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: iterfzf-${{ env.ITERFZF_VERSION }}-py3-none-manylinux_riscv64
path: dist/*.whl
if-no-files-found: error

test_wheel:
name: Test iterfzf ${{ matrix.version }} on Python ${{ matrix.python-version }}
needs: [setup, build_wheel]
if: needs.setup.outputs.versions != '[]'
runs-on: ubuntu-24.04-riscv
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
version: ${{ fromJSON(needs.setup.outputs.versions) }}
python-version: ['3.12', '3.13', '3.14', '3.14t']

env:
ITERFZF_VERSION: ${{ matrix.version }}

steps:
- name: Download wheel
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: iterfzf-${{ env.ITERFZF_VERSION }}-py3-none-manylinux_riscv64

- name: Install Python
uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1
with:
python-version: ${{ matrix.python-version }}
activate-environment: true
enable-cache: false

- name: Install the wheel
run: |
uv pip install --reinstall --no-index --find-links . iterfzf
uv pip install pytest

# tox.ini's first two commands; the other two assert that iterfzf([])
# returns None, which raises AttributeError at this tag on every platform.
- name: Run upstream's wheel checks
run: |
python -c "import sys; sys.path.remove(''); from iterfzf import BUNDLED_EXECUTABLE as e; assert e"
python -c "import sys; sys.path.remove(''); from iterfzf import BUNDLED_EXECUTABLE as e; import os; assert os.execl(e, e, '--version') == 0"

# The suite resolves fzf from PATH, so it runs the wheel's own binary.
# The three deselected cases open the full-screen picker and need an
# interactive terminal, which is why upstream's CI runs tox and not this.
- name: Run upstream's tests
run: |
PATH="$(python -c 'import iterfzf, os; print(os.path.dirname(iterfzf.__file__))'):$PATH" \
python -m pytest --pyargs iterfzf.test_iterfzf -v \
-k 'not test_no_query and not test_supports_color_kwarg and not test_select_one_ambiguous'

publish:
name: Publish iterfzf ${{ matrix.version }}
needs: [setup, build_wheel, test_wheel]
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: iterfzf-${{ matrix.version }}-py3-none-manylinux_riscv64
6 changes: 6 additions & 0 deletions docs/packages/iterfzf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package-name: iterfzf
source-code: https://github.com/dahlia/iterfzf
license: GPL-3.0-or-later
versions:
- version: 1.9.0.67.0
patched: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Mon, 21 Sep 2026 14:05:00 +0000
Subject: [PATCH] build_dist: add riscv64 to the platform tables

Upstream-Status: To upstream [not yet submitted; python-wheels does not open issues/PRs on third-party repos]

build_dist.py bundles the fzf binary published by junegunn/fzf and names the
wheel from two parallel tables. Neither has a riscv64 row, so the build stops
before it downloads anything:

KeyError: ('linux', 'riscv64') # GOOS/GOARCH given
RuntimeError: unsupported platform: ('linux', 'riscv64') # native build

fzf 0.67.0, the version this release bundles, is the first to publish
fzf-0.67.0-linux_riscv64.tar.gz, so only the tables are missing.
goos_goarch_platform_tag_map names the wheel;
manylinux_2_39 is the oldest manylinux profile that exists for riscv64 (glibc
2.39, Rocky 10). platform_machine_goos_goarch_map is the native-detection half
that `pip install iterfzf` from the sdist goes through on a riscv64 host; the
two tables are documented as sharing their key order, so both get the row.

Signed-off-by: Ludovic Henry <git@ludovic.dev>
---
build_dist.py | 2 ++
1 file changed, 2 insertions(+)

diff --git a/build_dist.py b/build_dist.py
index 6e5f1ae..dda139c 100644
--- a/build_dist.py
+++ b/build_dist.py
@@ -206,6 +206,7 @@ goos_goarch_platform_tag_map = {
("linux", "armv6"): "manylinux_1_2_armv6l",
("linux", "armv7"): "manylinux_1_2_armv7l",
("linux", "ppc64le"): "manylinux_2_17_ppc64le.manylinux2014_ppc64le",
+ ("linux", "riscv64"): "manylinux_2_39_riscv64",
("linux", "s390x"): "manylinux_2_17_s390x.manylinux2014_s390x",
("windows", "amd64"): "win_amd64",
("windows", "arm64"): "win_arm64",
@@ -227,6 +228,7 @@ platform_machine_goos_goarch_map = {
("linux", "armv6l"): ("linux", "armv6"),
("linux", "armv7l"): ("linux", "armv7"),
("linux", "ppc64le"): ("linux", "ppc64le"),
+ ("linux", "riscv64"): ("linux", "riscv64"),
("linux", "s390x"): ("linux", "s390x"),
("win32", "AMD64"): ("windows", "amd64"),
("win32", "aarch64"): ("windows", "arm64"),
Loading