Skip to content

Commit 7f91f2e

Browse files
authored
Merge branch 'main' into github-actions/add-doc-for-bottleneck
2 parents 8ed1801 + 7eeee3c commit 7f91f2e

103 files changed

Lines changed: 4947 additions & 1 deletion

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
# SPDX-FileCopyrightText: 2026 The RISE Project
2+
# SPDX-License-Identifier: MIT
3+
#
4+
# This workflow is based on:
5+
# https://github.com/google/array_record/blob/main/.github/workflows/build_and_publish_template.yml
6+
# and https://github.com/google/array_record/blob/main/oss/build_whl.sh
7+
---
8+
name: Build array-record wheels (riscv64)
9+
10+
on:
11+
workflow_dispatch:
12+
inputs:
13+
version:
14+
description: 'array_record version to build'
15+
required: true
16+
default: '0.8.3'
17+
pull_request:
18+
paths:
19+
- '.github/workflows/build-array-record.yml'
20+
21+
run-name: build-array-record - ${{ inputs.version || '0.8.3' }}
22+
23+
concurrency:
24+
group: ${{ github.workflow }}-${{ inputs.version || '0.8.3' }}-${{ github.head_ref || github.run_id }}
25+
cancel-in-progress: true
26+
27+
permissions:
28+
contents: read
29+
30+
env:
31+
ARRAY_RECORD_VERSION: ${{ inputs.version || '0.8.3' }}
32+
MANYLINUX_RISCV64_IMAGE: quay.io/pypa/manylinux_2_39_riscv64
33+
# Upstream pins 7.2.1, fetched from the bazel releases, which publish no
34+
# riscv64 binary; 7.5.0 is the version this repo bootstraps from source.
35+
BAZEL_VERSION: '7.5.0'
36+
# versions bazel 7.5.0's MODULE.bazel pins; both need a riscv64 fix below
37+
RULES_PYTHON_VERSION: '0.33.2'
38+
RULES_JAVA_VERSION: '7.6.5'
39+
40+
jobs:
41+
bazel:
42+
name: Bootstrap bazel (riscv64)
43+
runs-on: ubuntu-24.04-riscv
44+
timeout-minutes: 720
45+
46+
steps:
47+
- name: Restore bazel binary
48+
id: cache
49+
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
50+
with:
51+
path: bazel-bin
52+
key: bazel-${{ env.BAZEL_VERSION }}-manylinux_riscv64
53+
54+
- name: Bootstrap bazel ${{ env.BAZEL_VERSION }}
55+
if: steps.cache.outputs.cache-hit != 'true'
56+
run: |
57+
mkdir -p bazel-bin
58+
docker run --rm -i --network=host \
59+
-v "${GITHUB_WORKSPACE}:/work" \
60+
-w /work \
61+
-e BAZEL_VERSION="${BAZEL_VERSION}" \
62+
-e RULES_PYTHON_VERSION="${RULES_PYTHON_VERSION}" \
63+
-e RULES_JAVA_VERSION="${RULES_JAVA_VERSION}" \
64+
"${MANYLINUX_RISCV64_IMAGE}" \
65+
bash <<'SCRIPT'
66+
set -eux
67+
68+
dnf install -y --disablerepo=extras --setopt=install_weak_deps=False java-21-openjdk-devel zip unzip
69+
JAVA_HOME="$(dirname "$(dirname "$(readlink -f "$(command -v javac)")")")"
70+
export JAVA_HOME
71+
72+
# rules_python 0.33.2's PLATFORMS has no riscv64 entry, aborting the bootstrap
73+
# (bazelbuild/bazel#23018). Any linux entry is a safe stand-in: the toolchain it names
74+
# is never selected on a riscv64 host. Fixed in bazel 8.2.0; the 7.x backport is open.
75+
mkdir -p /tmp/rules_python
76+
curl -fsSLo /tmp/rules_python.tar.gz "https://github.com/bazel-contrib/rules_python/releases/download/${PROJECT_RULES_PYTHON_VERSION}/rules_python-${PROJECT_RULES_PYTHON_VERSION}.tar.gz"
77+
tar -xzf /tmp/rules_python.tar.gz -C /tmp/rules_python --strip-components=1
78+
sed -i 's|fail("No platform declared for host OS {} on arch {}".format(os_name, arch))|return "x86_64-unknown-linux-gnu"|' \
79+
/tmp/rules_python/python/private/toolchains_repo.bzl
80+
81+
# rules_java 7.x maps riscv64 to a stray-colon include path, so a JNI library
82+
# can't find jni_md.h. Fixed in rules_java 8.x, never backported.
83+
mkdir -p /tmp/rules_java
84+
curl -fsSLo /tmp/rules_java.tar.gz "https://github.com/bazelbuild/rules_java/releases/download/${RULES_JAVA_VERSION}/rules_java-${RULES_JAVA_VERSION}.tar.gz"
85+
tar -xzf /tmp/rules_java.tar.gz -C /tmp/rules_java
86+
sed -i 's|\[":include/linux"\]|["include/linux"]|g' /tmp/rules_java/toolchains/BUILD
87+
88+
mkdir -p /tmp/bazel-src
89+
cd /tmp/bazel-src
90+
curl -fsSLo dist.zip "https://github.com/bazelbuild/bazel/releases/download/${BAZEL_VERSION}/bazel-${BAZEL_VERSION}-dist.zip"
91+
unzip -q dist.zip
92+
93+
EXTRA_BAZEL_ARGS="--tool_java_runtime_version=local_jdk \
94+
--override_module=rules_python=/tmp/rules_python \
95+
--override_module=rules_java=/tmp/rules_java" \
96+
bash ./compile.sh
97+
install -m 0755 output/bazel /work/bazel-bin/bazel
98+
SCRIPT
99+
100+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
101+
with:
102+
name: bazel-${{ env.BAZEL_VERSION }}-riscv64
103+
path: bazel-bin/bazel
104+
if-no-files-found: error
105+
106+
build_wheels:
107+
name: Build array-record ${{ inputs.version || '0.8.3' }} ${{ matrix.tag }}-manylinux_riscv64
108+
runs-on: ubuntu-24.04-riscv
109+
timeout-minutes: 720
110+
needs: [bazel]
111+
112+
strategy:
113+
fail-fast: false
114+
matrix:
115+
# Upstream supports 3.11-3.14 and publishes no free-threaded wheel.
116+
include:
117+
- {tag: cp312, python: '3.12'}
118+
- {tag: cp313, python: '3.13'}
119+
- {tag: cp314, python: '3.14'}
120+
121+
steps:
122+
- name: Checkout array_record ${{ inputs.version || '0.8.3' }}
123+
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
124+
with:
125+
repository: google/array_record
126+
ref: v${{ env.ARRAY_RECORD_VERSION }}
127+
path: array_record
128+
fetch-depth: 1
129+
persist-credentials: false
130+
131+
- name: Download bazel
132+
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
133+
with:
134+
name: bazel-${{ env.BAZEL_VERSION }}-riscv64
135+
path: bazel-bin
136+
137+
- name: Build wheel
138+
env:
139+
PYTHON_VERSION: ${{ matrix.python }}
140+
PROJECT_RULES_PYTHON_VERSION: '1.6.0'
141+
run: |
142+
mkdir -p wheelhouse
143+
set -o pipefail
144+
docker run --rm -i --network=host \
145+
-v "${GITHUB_WORKSPACE}:/work" \
146+
-w /work \
147+
-e PYTHON_VERSION \
148+
-e PROJECT_RULES_PYTHON_VERSION \
149+
"${MANYLINUX_RISCV64_IMAGE}" \
150+
bash <<'SCRIPT' 2>&1 | tee build.log
151+
set -eux
152+
153+
dnf install -y --disablerepo=extras --setopt=install_weak_deps=False java-21-openjdk-devel zip unzip rsync
154+
JAVA_HOME="$(dirname "$(dirname "$(readlink -f "$(command -v javac)")")")"
155+
export JAVA_HOME
156+
install -m 0755 /work/bazel-bin/bazel /usr/local/bin/bazel
157+
158+
PYTAG="cp${PYTHON_VERSION/./}"
159+
export PYTHON_BIN="/opt/python/${PYTAG}-${PYTAG}/bin/python"
160+
export PATH="/opt/python/${PYTAG}-${PYTAG}/bin:${PATH}"
161+
"${PYTHON_BIN}" -m pip install -q -U setuptools wheel auditwheel
162+
163+
# protobuf and rules_fuzzing declare pip hubs for CPython 3.8, which
164+
# python-build-standalone does not publish for riscv64, and rules_python
165+
# aborts on the missing interpreter even though nothing uses those hubs.
166+
mkdir -p /tmp/rules_python
167+
curl -fsSLo /tmp/rules_python.tar.gz \
168+
"https://github.com/bazel-contrib/rules_python/releases/download/${PROJECT_RULES_PYTHON_VERSION}/rules_python-${PROJECT_RULES_PYTHON_VERSION}.tar.gz"
169+
tar -xzf /tmp/rules_python.tar.gz -C /tmp/rules_python --strip-components=1
170+
python3 - <<'PATCH'
171+
path = "/tmp/rules_python/python/private/pypi/extension.bzl"
172+
source = open(path).read()
173+
old = " if python_name not in available_interpreters:\n fail(("
174+
new = (
175+
" if python_name not in available_interpreters:\n"
176+
" python_name = sorted(available_interpreters)[0]\n"
177+
" if False:\n"
178+
" fail(("
179+
)
180+
assert old in source
181+
open(path, "w").write(source.replace(old, new, 1))
182+
PATCH
183+
184+
cd /work/array_record
185+
186+
rm -f .bazelrc
187+
cat > .bazelrc <<'RC'
188+
build --incompatible_default_to_explicit_init_py
189+
build --enable_platform_specific_config
190+
build -c opt
191+
build --cxxopt=-std=c++17
192+
build --host_cxxopt=-std=c++17
193+
build --experimental_repo_remote_exec
194+
common --check_direct_dependencies=error
195+
build --cxxopt=-Wno-deprecated-declarations --host_cxxopt=-Wno-deprecated-declarations
196+
build --cxxopt=-Wno-parentheses --host_cxxopt=-Wno-parentheses
197+
build --cxxopt=-Wno-sign-compare --host_cxxopt=-Wno-sign-compare
198+
RC
199+
{
200+
echo "build --@rules_python//python/config_settings:python_version=${PYTHON_VERSION}"
201+
echo "test --@rules_python//python/config_settings:python_version=${PYTHON_VERSION}"
202+
echo "test --action_env PYTHON_VERSION=${PYTHON_VERSION}"
203+
echo "test --test_timeout=900"
204+
echo "build --override_module=rules_python=/tmp/rules_python"
205+
# A long build's default curses progress output is large enough that
206+
# GitHub drops the job log, taking the failure with it.
207+
echo "common --curses=no --show_progress_rate_limit=60"
208+
} >> .bazelrc
209+
210+
bazel build ... --action_env PYTHON_BIN_PATH="${PYTHON_BIN}"
211+
bazel test --verbose_failures --test_output=errors ... --action_env PYTHON_BIN_PATH="${PYTHON_BIN}"
212+
213+
STAGE="$(mktemp -d)"
214+
mkdir "${STAGE}/array_record"
215+
cp setup.py LICENSE "${STAGE}"
216+
rsync -avm -L --exclude="bazel-*/" . "${STAGE}/array_record"
217+
rsync -avm -L --include="*.so" --include="*_pb2.py" \
218+
--exclude="*.runfiles" --exclude="*_obj" --include="*/" --exclude="*" \
219+
bazel-bin/cpp "${STAGE}/array_record"
220+
rsync -avm -L --include="*.so" --include="*_pb2.py" \
221+
--exclude="*.runfiles" --exclude="*_obj" --include="*/" --exclude="*" \
222+
bazel-bin/python "${STAGE}/array_record"
223+
224+
# The extension statically links these; upstream ships none of their
225+
# licences, so collect them from the sources bazel built.
226+
OUTPUT_BASE="$(bazel info output_base)"
227+
for repo in abseil-cpp boringssl brotli crc32c curl google_cloud_cpp \
228+
highwayhash protobuf pybind11 riegeli snappy zlib zstd; do
229+
dir="$(find "${OUTPUT_BASE}/external" -mindepth 1 -maxdepth 1 -type d \
230+
\( -name "${repo}" -o -name "${repo}~" -o -name "*~${repo}" \) | head -1)"
231+
file="$(find "${dir}" -maxdepth 1 -type f -iname 'LICENSE*' | head -1)"
232+
[ -n "${file}" ] || file="$(find "${dir}" -maxdepth 1 -type f -iname 'COPYING*' | head -1)"
233+
cp "${file}" "${STAGE}/LICENSE.${repo}"
234+
done
235+
236+
cd "${STAGE}"
237+
"${PYTHON_BIN}" setup.py bdist_wheel --python-tag "py3${PYTHON_VERSION#*.}"
238+
auditwheel repair --plat manylinux_2_39_riscv64 -w /work/wheelhouse dist/*.whl
239+
SCRIPT
240+
241+
- name: Upload build log
242+
if: failure()
243+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
244+
with:
245+
name: array-record-${{ env.ARRAY_RECORD_VERSION }}-${{ matrix.tag }}-build-log
246+
path: build.log
247+
248+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
249+
with:
250+
name: array-record-${{ env.ARRAY_RECORD_VERSION }}-${{ matrix.tag }}-manylinux_riscv64
251+
path: wheelhouse/*.whl
252+
if-no-files-found: error
253+
254+
- name: Test wheel
255+
env:
256+
PYTHON_VERSION: ${{ matrix.python }}
257+
run: |
258+
docker run --rm -i --network=host \
259+
-v "${GITHUB_WORKSPACE}:/work" \
260+
-e PYTHON_VERSION \
261+
"${MANYLINUX_RISCV64_IMAGE}" \
262+
bash <<'SCRIPT'
263+
set -eux
264+
265+
PYTAG="cp${PYTHON_VERSION/./}"
266+
PYTHON_BIN="/opt/python/${PYTAG}-${PYTAG}/bin/python"
267+
"${PYTHON_BIN}" -m pip install /work/wheelhouse/*.whl
268+
269+
# /work holds the checkout, whose root would shadow the installed wheel.
270+
cd /tmp
271+
"${PYTHON_BIN}" - <<'PY'
272+
import importlib.metadata
273+
import tempfile
274+
275+
import array_record
276+
from array_record.python import array_record_data_source # noqa: F401
277+
from array_record.python import array_record_module
278+
279+
assert array_record_module.__file__.endswith(".so"), array_record_module.__file__
280+
281+
path = tempfile.mkdtemp() + "/test.arecord"
282+
writer = array_record_module.ArrayRecordWriter(path)
283+
records = [b"abc", b"def", b"ghi"]
284+
for record in records:
285+
writer.write(record)
286+
writer.close()
287+
reader = array_record_module.ArrayRecordReader(path)
288+
assert reader.num_records() == len(records)
289+
assert [reader.read() for _ in records] == records
290+
reader.close()
291+
292+
licenses = {
293+
str(f).rsplit("/", 1)[1]
294+
for f in importlib.metadata.files("array_record")
295+
if ".dist-info/licenses/" in str(f)
296+
} - {""}
297+
expected = {"LICENSE"} | {
298+
"LICENSE." + name
299+
for name in [
300+
"abseil-cpp", "boringssl", "brotli", "crc32c", "curl",
301+
"google_cloud_cpp", "highwayhash", "protobuf", "pybind11",
302+
"riegeli", "snappy", "zlib", "zstd",
303+
]
304+
}
305+
assert licenses == expected, licenses
306+
PY
307+
SCRIPT
308+
309+
publish:
310+
name: Publish array-record ${{ inputs.version || '0.8.3' }} to GitLab
311+
needs: [build_wheels]
312+
runs-on: ubuntu-latest
313+
permissions:
314+
contents: write
315+
pull-requests: write
316+
317+
steps:
318+
- name: Publish wheels and open docs PR
319+
uses: riseproject-dev/python-wheels/actions/publish-wheels@main
320+
with:
321+
artifact-pattern: array-record-${{ env.ARRAY_RECORD_VERSION }}-*-manylinux_riscv64
322+
gitlab-username: ${{ vars.GITLAB_DEPLOY_USER }}
323+
gitlab-token: ${{ secrets.GITLAB_DEPLOY_TOKEN }}
324+
gitlab-project-id: ${{ vars.GITLAB_PROJECT_ID }}
325+
gh-token: ${{ secrets.GITHUB_TOKEN }}

0 commit comments

Comments
 (0)