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
92 changes: 92 additions & 0 deletions .github/workflows/build-dumb-init.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# SPDX-FileCopyrightText: 2026 The RISE Project
# SPDX-License-Identifier: MIT
---
# This workflow is based on: https://github.com/Yelp/dumb-init/blob/v1.2.5/Makefile python-dists-% target
name: Build dumb-init wheels (riscv64)

on:
workflow_dispatch:
inputs:
version:
description: 'dumb-init version to build (PyPI version, e.g. 1.2.5.post1)'
required: true
default: '1.2.5.post1'
pull_request:
paths:
- '.github/workflows/build-dumb-init.yml'
- 'patches/dumb-init/**'

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

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

env:
# `inputs.version` is empty on pull_request events; default to 1.2.5.post1 there.
DUMB_INIT_VERSION: ${{ inputs.version || '1.2.5.post1' }}
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64

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

build_wheel:
needs: [setup]
name: Build dumb-init ${{ inputs.version || '1.2.5.post1' }} py2.py3-none-manylinux_riscv64
runs-on: ubuntu-24.04-riscv
timeout-minutes: 30

steps:
# The v1.2.5 tag's setup.py has no .post1 suffix; 0002-*.patch adds it to
# match the sdist Yelp actually uploaded to PyPI as 1.2.5.post1.
- name: Determine upstream git tag
run: echo "DUMB_INIT_TAG=v${DUMB_INIT_VERSION%.post*}" >> "$GITHUB_ENV"

- name: Checkout dumb-init ${{ env.DUMB_INIT_TAG }}
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: Yelp/dumb-init
ref: ${{ env.DUMB_INIT_TAG }}
persist-credentials: false

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

- name: Patch dumb-init source
run: git apply python-wheels/patches/dumb-init/${{ env.DUMB_INIT_VERSION }}/*.patch

- name: Build wheel
uses: pypa/cibuildwheel@1828c10ab37f080699c7b81cea34097c684a7074 # v4.2.0
with:
output-dir: wheelhouse/
# setup.py's own bdist_wheel override forces the py2.py3-none tag, so one build serves every interpreter.
only: cp312-manylinux_riscv64
env:
CIBW_MANYLINUX_RISCV64_IMAGE: ${{ env.MANYLINUX_RISCV64_IMAGE }}
# pytest-timeout<2.0.0 (upstream's own pin) imports distutils.version.LooseVersion,
# which cp312+ dropped entirely (PEP 632); a modern pytest-timeout has no such
# dependency, so let pip pick the latest instead of upstream's stale Python-2-era cap.
CIBW_TEST_REQUIRES: pytest pytest-timeout
CIBW_TEST_SOURCES: tests testing VERSION pytest.ini
CIBW_TEST_COMMAND: python -m pytest tests -vv

- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: dumb-init-${{ env.DUMB_INIT_VERSION }}-py2.py3-none-manylinux_riscv64
path: wheelhouse/*.whl
if-no-files-found: error

publish:
name: Publish dumb-init ${{ inputs.version || '1.2.5.post1' }}
needs: [setup, build_wheel]
permissions:
contents: write
pull-requests: write
uses: $/.github/workflows/_publish-wheel.yml
with:
artifact-pattern: dumb-init-${{ inputs.version || '1.2.5.post1' }}-*-manylinux_riscv64
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Ludovic Henry <git@ludovic.dev>
Date: Sun, 6 Sep 2026 00:00:00 +0200
Subject: [PATCH] testing: eliminate usage of pylib

v1.2.5's testing/__init__.py imports `py._path.local.LocalPath` from the
standalone py package, which recent pytest releases no longer pull in
as a dependency, so `pip install pytest` alone leaves `import testing`
failing with ModuleNotFoundError: No module named 'py'. Backports
upstream's later fixes, replacing it with the os/os.path calls already
imported by the module and tolerating the "0" process state GitHub's
own QEMU runners can report.

Upstream-Status: Backport [https://github.com/Yelp/dumb-init/commit/2c39101849abb835e9f368e3cf5c9570362a9589]
---
testing/__init__.py | 25 +++++++++++++++++--------
1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/testing/__init__.py b/testing/__init__.py
index 665df65..e860e09 100644
--- a/testing/__init__.py
+++ b/testing/__init__.py
@@ -8,9 +8,6 @@ from contextlib import contextmanager
from subprocess import PIPE
from subprocess import Popen

-from py._path.local import LocalPath
-
-
# these signals cause dumb-init to suspend itself
SUSPEND_SIGNALS = frozenset([
signal.SIGTSTP,
@@ -49,14 +46,24 @@ def print_signals(args=()):
def child_pids(pid):
"""Return a list of direct child PIDs for the given PID."""
children = set()
- for p in LocalPath('/proc').listdir():
+ for p in os.listdir('/proc'):
try:
- stat = open(p.join('stat').strpath).read()
- m = re.match(r'^\d+ \(.+?\) [a-zA-Z] (\d+) ', stat)
+ with open(os.path.join('/proc', p, 'stat')) as f:
+ stat = f.read()
+ m = re.match(
+ r'^\d+ \(.+?\) '
+ # This field, state, is normally a single letter, but can be
+ # "0" if there are some unusual security settings that prevent
+ # reading the process state (happens under GitHub Actions with
+ # QEMU for some reason).
+ '[0a-zA-Z] '
+ r'(\d+) ',
+ stat,
+ )
assert m, stat
ppid = int(m.group(1))
if ppid == pid:
- children.add(int(p.basename))
+ children.add(int(p))
except OSError:
# Happens when the process exits after listing it, or between
# opening stat and reading it.
@@ -76,12 +83,13 @@ def pid_tree(pid):

def is_alive(pid):
"""Return whether a process is running with the given PID."""
- return LocalPath('/proc').join(str(pid)).isdir()
+ return os.path.isdir(os.path.join('/proc', str(pid)))


def process_state(pid):
"""Return a process' state, such as "stopped" or "running"."""
- status = LocalPath('/proc').join(str(pid), 'status').read()
+ with open(os.path.join('/proc', str(pid), 'status')) as f:
+ status = f.read()
m = re.search(r'^State:\s+[A-Z] \(([a-z]+)\)$', status, re.MULTILINE)
return m.group(1)

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: Sun, 6 Sep 2026 00:00:00 +0200
Subject: [PATCH] setup.py: version 1.2.5.post1, drop the dev-only testing/
package

The v1.2.5 tag's setup.py has no `packages=` argument and computes
`version` from the bare VERSION file, but the actual dumb-init-1.2.5.post1
sdist Yelp uploaded to PyPI carries a setup.py with `version=... + ".post1"`
and an explicit `packages=[]` -- a metadata fix applied to the release
artifact and never pushed back to this tag (there is no newer tag on
GitHub). Without this, `pip download dumb-init==1.2.5.post1` and a build
from this checkout produce different version strings, and the checkout's
build also ships the tests/-only `testing` helper package inside the
wheel (visible: `dumb_init-1.2.5.data/purelib/testing/`), which the real
PyPI wheel excludes.

Upstream-Status: Inappropriate [Yelp's own PyPI release process applied this to the uploaded sdist but never committed or tagged it in git; there is no upstream ref to submit against]
---
setup.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/setup.py b/setup.py
index 0ec2f18..dd9e59b 100644
--- a/setup.py
+++ b/setup.py
@@ -121,10 +121,11 @@ class build_cexe(Command):
setup(
name='dumb-init',
description='Simple wrapper script which proxies signals to a child',
- version=open('VERSION').read().strip(),
+ version=open('VERSION').read().strip() + ".post1",
author='Yelp',
url='https://github.com/Yelp/dumb-init/',
platforms='linux',
+ packages=[],
c_executables=[Extension('dumb-init', ['dumb-init.c'])],
cmdclass={
'bdist_wheel': bdist_wheel,
--
2.43.0