Skip to content
Merged
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
288 changes: 288 additions & 0 deletions .github/workflows/build-sdbus.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# Based on the CI/wheel-build steps of
# https://github.com/python-sdbus/python-sdbus/blob/0.14.3/.github/workflows/ci.yml
# Upstream's own release process statically links a from-source libsystemd for
# manylinux1-era portability; manylinux_2_39_riscv64 already ships systemd-devel,
# so this links libsystemd dynamically instead, like build-cysystemd.yml.
name: Build sdbus wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'sdbus version to build (git tag, e.g. 0.14.3)'
required: true
default: '0.14.3'
pull_request:
paths:
- '.github/workflows/build-sdbus.yml'

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

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

env:
SDBUS_VERSION: ${{ inputs.version || '0.14.3' }}
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64
# setup.py only sets Extension(py_limited_api=...); the bdist_wheel floor
# tag comes from us via --py-limited-api, so we pick our own (RISE's min).
ABI3_FLOOR: cp312

jobs:
setup:
uses: $/.github/workflows/_setup.yml

build_abi3:
needs: [setup]
name: Build sdbus ${{ inputs.version || '0.14.3' }} cp312-abi3-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 60
steps:
- name: Checkout sdbus ${{ env.SDBUS_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: python-sdbus/python-sdbus
ref: ${{ env.SDBUS_VERSION }}
persist-credentials: false

- name: Stage the licence-collection script
run: |
cat > collect-licenses.sh <<'COLLECT_EOF'
#!/bin/bash
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
#
# Stage, at the project root, the licence of every shared library
# auditwheel vendors out of the build image alongside libsystemd.
# setuptools' default LICENSE* glob copies them into the wheel.
set -euo pipefail

project="${1:?usage: collect-licenses.sh <project-dir>}"

# ldd is transitive, so libsystemd alone covers its whole closure;
# ldd does not list the root itself, so resolve that too.
mapfile -t libs < <(
{
ldd /usr/lib64/libsystemd.so.0 | tr ' ' '\n' | grep '^/'
readlink -f /usr/lib64/libsystemd.so.0
} | sort -u
)

# `rpm -qf` reports unowned files on stdout, so keep only bare package names.
# glibc and the gcc runtime are on auditwheel's manylinux allowlist and
# are never vendored into the wheel.
mapfile -t pkgs < <(
rpm -qf --qf '%{NAME}\n' "${libs[@]}" 2>/dev/null |
grep -E '^[A-Za-z0-9._+-]+$' | sort -u |
grep -vE '^(glibc|libgcc|libstdc\+\+|gcc)$'
)

for pkg in "${pkgs[@]}"; do
mapfile -t files < <(rpm -q --licensefiles "$pkg" 2>/dev/null || true)

# Some subpackages leave the licence to a sibling of the same source RPM.
if [ -z "${files[0]:-}" ]; then
srpm=$(rpm -q --qf '%{SOURCERPM}\n' "$pkg")
mapfile -t files < <(
rpm -qa --qf '%{SOURCERPM} %{NAME}\n' |
awk -v s="$srpm" '$1 == s { print $2 }' |
xargs -r rpm -q --licensefiles 2>/dev/null | sort -u
)
fi

# Others mark it %doc rather than %license, and the image installs no docs.
if [ -z "${files[0]:-}" ]; then
dnf -y --disablerepo=extras reinstall --setopt=tsflags= "$pkg" >/dev/null
mapfile -t files < <(rpm -qd "$pkg" | grep -iE '/(LICEN[CS]E|COPYING|NOTICE)')
fi

for f in "${files[@]}"; do
[ -f "$f" ] || continue
cp "$f" "$project/LICENSE.${pkg}.$(basename "$f")"
done
compgen -G "$project/LICENSE.$pkg.*" >/dev/null ||
{ echo "no licence file found for $pkg" >&2; exit 1; }
done

ls -1 "$project"/LICENSE.* | sed "s|$project/||"
COLLECT_EOF

- name: Build wheels
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
with:
output-dir: wheelhouse/
env:
CIBW_ARCHS: riscv64
CIBW_BUILD: >-
cp312-manylinux_riscv64 cp313-manylinux_riscv64
cp314-manylinux_riscv64
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
CIBW_BEFORE_ALL_LINUX: >-
dnf install -y systemd-devel dbus-daemon &&
bash {project}/collect-licenses.sh {project}
CIBW_ENVIRONMENT: PYTHON_SDBUS_USE_LIMITED_API=1
# setup.py only calls Extension(py_limited_api=True); it never sets
# the bdist_wheel option itself (gotcha 34 does not apply here), so
# the abi3 tag has to be injected via config-settings (gotcha 11).
CIBW_CONFIG_SETTINGS: --build-option=--py-limited-api=${{ env.ABI3_FLOOR }}
# Matches build-pygame.yml's fix for the same "D-Bus library appears
# to be incorrectly set up" error: the image ships no machine-id.
CIBW_BEFORE_TEST: |
mkdir -p /var/lib/dbus
if [ ! -f /var/lib/dbus/machine-id ]; then
dbus-uuidgen > /var/lib/dbus/machine-id
fi
CIBW_TEST_REQUIRES: jinja2
# {package}/test is a package (has __init__.py) with relative
# imports, so it must be discovered as a subpackage of {package},
# not passed as the start directory itself (gotcha: bare
# `--start-directory {package}/test` makes __package__ = "").
CIBW_TEST_COMMAND: cd {package} && python3 -m unittest discover --verbose

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sdbus-${{ env.SDBUS_VERSION }}-cp312-abi3-manylinux_riscv64
path: wheelhouse/*.whl
if-no-files-found: error

build_freethreaded:
needs: [setup]
name: Build sdbus ${{ inputs.version || '0.14.3' }} cp314t-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 60
steps:
- name: Checkout sdbus ${{ env.SDBUS_VERSION }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: python-sdbus/python-sdbus
ref: ${{ env.SDBUS_VERSION }}
persist-credentials: false

- name: Stage the licence-collection script
run: |
cat > collect-licenses.sh <<'COLLECT_EOF'
#!/bin/bash
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
#
# Stage, at the project root, the licence of every shared library
# auditwheel vendors out of the build image alongside libsystemd.
# setuptools' default LICENSE* glob copies them into the wheel.
set -euo pipefail

project="${1:?usage: collect-licenses.sh <project-dir>}"

# ldd is transitive, so libsystemd alone covers its whole closure;
# ldd does not list the root itself, so resolve that too.
mapfile -t libs < <(
{
ldd /usr/lib64/libsystemd.so.0 | tr ' ' '\n' | grep '^/'
readlink -f /usr/lib64/libsystemd.so.0
} | sort -u
)

# `rpm -qf` reports unowned files on stdout, so keep only bare package names.
# glibc and the gcc runtime are on auditwheel's manylinux allowlist and
# are never vendored into the wheel.
mapfile -t pkgs < <(
rpm -qf --qf '%{NAME}\n' "${libs[@]}" 2>/dev/null |
grep -E '^[A-Za-z0-9._+-]+$' | sort -u |
grep -vE '^(glibc|libgcc|libstdc\+\+|gcc)$'
)

for pkg in "${pkgs[@]}"; do
mapfile -t files < <(rpm -q --licensefiles "$pkg" 2>/dev/null || true)

# Some subpackages leave the licence to a sibling of the same source RPM.
if [ -z "${files[0]:-}" ]; then
srpm=$(rpm -q --qf '%{SOURCERPM}\n' "$pkg")
mapfile -t files < <(
rpm -qa --qf '%{SOURCERPM} %{NAME}\n' |
awk -v s="$srpm" '$1 == s { print $2 }' |
xargs -r rpm -q --licensefiles 2>/dev/null | sort -u
)
fi

# Others mark it %doc rather than %license, and the image installs no docs.
if [ -z "${files[0]:-}" ]; then
dnf -y --disablerepo=extras reinstall --setopt=tsflags= "$pkg" >/dev/null
mapfile -t files < <(rpm -qd "$pkg" | grep -iE '/(LICEN[CS]E|COPYING|NOTICE)')
fi

for f in "${files[@]}"; do
[ -f "$f" ] || continue
cp "$f" "$project/LICENSE.${pkg}.$(basename "$f")"
done
compgen -G "$project/LICENSE.$pkg.*" >/dev/null ||
{ echo "no licence file found for $pkg" >&2; exit 1; }
done

ls -1 "$project"/LICENSE.* | sed "s|$project/||"
COLLECT_EOF

- name: Build wheels
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
with:
output-dir: wheelhouse/
env:
CIBW_ARCHS: riscv64
CIBW_BUILD: cp314t-manylinux_riscv64
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
CIBW_BEFORE_ALL_LINUX: >-
dnf install -y systemd-devel dbus-daemon &&
bash {project}/collect-licenses.sh {project}
CIBW_BEFORE_TEST: |
mkdir -p /var/lib/dbus
if [ ! -f /var/lib/dbus/machine-id ]; then
dbus-uuidgen > /var/lib/dbus/machine-id
fi
CIBW_TEST_REQUIRES: jinja2
CIBW_TEST_COMMAND: cd {package} && python3 -m unittest discover --verbose

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sdbus-${{ env.SDBUS_VERSION }}-cp314t-manylinux_riscv64
path: wheelhouse/*.whl
if-no-files-found: error

gpl_sources:
needs: [setup]
name: Collect GPL sources for sdbus ${{ inputs.version || '0.14.3' }}
runs-on: ubuntu-24.04-riscv

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

# libcap/systemd-libs are the copyleft (GPL/LGPL) libraries auditwheel
# vendors out of the build image alongside libsystemd.
- uses: ./actions/collect-gpl-sources
with:
image: ${{ env.MANYLINUX_RISCV64_IMAGE }}
packages: gcc libcap systemd-libs
output: gpl-sources.tar

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: sdbus-${{ env.SDBUS_VERSION }}-gpl-sources
path: gpl-sources.tar
if-no-files-found: error

publish:
name: Publish sdbus ${{ inputs.version || '0.14.3' }}
needs: [setup, build_abi3, build_freethreaded, gpl_sources]
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
with:
artifact-pattern: sdbus-${{ inputs.version || '0.14.3' }}-*-manylinux_riscv64
gpl-sources-artifact: sdbus-${{ inputs.version || '0.14.3' }}-gpl-sources
gpl-sources-description: gcc and the copyleft libraries bundled in the wheel