fix: correct OOT catalog branches and add binding hash fixup

- Fix branch names for 5 modules discovered during install attempts:
  ieee802_11, ieee802_15_4, adsb (maint-3.10), iridium, nrsc5 (master)
- Remove packet_radio (repo gone/private)
- Add build_deps for modules that need them (castxml, autotools, Qt5)
- Add fix_binding_hashes.py helper script to Dockerfile builds to
  prevent castxml regen failures from stale pybind11 header hashes
- Use tar build context in Docker builds to support COPY instruction
- Note inspector as incompatible with GR 3.10 (API changes)

Successfully built: ieee802_11, ieee802_15_4, adsb, iridium, nrsc5
This commit is contained in:
Ryan Malloy 2026-01-31 15:04:50 -07:00
parent 521c306173
commit 2956ceab0f
3 changed files with 75 additions and 17 deletions

View File

@ -4,6 +4,7 @@ import io
import json
import logging
import subprocess
import tarfile
from datetime import datetime, timezone
from pathlib import Path
from typing import Any
@ -25,8 +26,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \\
# Clone and build
WORKDIR /build
COPY fix_binding_hashes.py /tmp/fix_binding_hashes.py
RUN git clone --depth 1 --branch {branch} {git_url} && \\
cd {repo_dir} && mkdir build && cd build && \\
cd {repo_dir} && \\
python3 /tmp/fix_binding_hashes.py . && \\
mkdir build && cd build && \\
cmake -DCMAKE_INSTALL_PREFIX=/usr {cmake_args}.. && \\
make -j$(nproc) && make install && \\
ldconfig && \\
@ -38,6 +42,44 @@ WORKDIR /flowgraphs
ENV PYTHONPATH="/usr/lib/python3.11/site-packages:${{PYTHONPATH}}"
"""
# Standalone script injected into OOT Docker builds to fix stale
# pybind11 binding hashes that would otherwise trigger castxml regen.
FIX_BINDING_HASHES_SCRIPT = """\
#!/usr/bin/env python3
\"\"\"Fix stale BINDTOOL_HEADER_FILE_HASH in pybind11 binding files.
GNU Radio's GR_PYBIND_MAKE_OOT cmake macro compares MD5 hashes of C++
headers against values stored in the binding .cc files. When they
differ it tries to regenerate via castxml, which often fails in minimal
Docker images. This script updates the hashes to match the actual
headers so cmake skips the regeneration step.
\"\"\"
import hashlib, pathlib, re, sys
root = pathlib.Path(sys.argv[1]) if len(sys.argv) > 1 else pathlib.Path(".")
bindings = root / "python" / "bindings"
if not bindings.is_dir():
sys.exit(0)
for cc in sorted(bindings.glob("*_python.cc")):
text = cc.read_text()
m = re.search(r"BINDTOOL_HEADER_FILE\\((\\S+)\\)", text)
if not m:
continue
header = next(root.joinpath("include").rglob(m.group(1)), None)
if not header:
continue
actual = hashlib.md5(header.read_bytes()).hexdigest()
new_text = re.sub(
r"BINDTOOL_HEADER_FILE_HASH\\([a-f0-9]+\\)",
f"BINDTOOL_HEADER_FILE_HASH({actual})",
text,
)
if new_text != text:
cc.write_text(new_text)
print(f"Fixed binding hash: {cc.name}")
"""
class OOTInstallerMiddleware:
"""Builds OOT modules into Docker images from git repos.
@ -235,13 +277,30 @@ class OOTInstallerMiddleware:
except Exception:
return False
@staticmethod
def _build_context(dockerfile: str) -> io.BytesIO:
"""Create a tar archive build context with Dockerfile and helper scripts."""
buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode="w") as tar:
for name, content in [
("Dockerfile", dockerfile),
("fix_binding_hashes.py", FIX_BINDING_HASHES_SCRIPT),
]:
data = content.encode("utf-8")
info = tarfile.TarInfo(name=name)
info.size = len(data)
tar.addfile(info, io.BytesIO(data))
buf.seek(0)
return buf
def _docker_build(self, dockerfile: str, tag: str) -> list[str]:
"""Build a Docker image from a Dockerfile string. Returns log lines."""
f = io.BytesIO(dockerfile.encode("utf-8"))
context = self._build_context(dockerfile)
log_lines: list[str] = []
try:
_image, build_log = self._client.images.build(
fileobj=f,
fileobj=context,
custom_context=True,
tag=tag,
rm=True,
forcerm=True,

View File

@ -230,7 +230,8 @@ CATALOG: dict[str, OOTModuleEntry] = {
description="IEEE 802.11a/g/p OFDM transceiver",
category="WiFi",
git_url="https://github.com/bastibl/gr-ieee802-11",
branch="main",
branch="maint-3.10",
build_deps=["castxml"],
homepage="https://github.com/bastibl/gr-ieee802-11",
),
_entry(
@ -238,7 +239,8 @@ CATALOG: dict[str, OOTModuleEntry] = {
description="IEEE 802.15.4 (Zigbee) O-QPSK transceiver",
category="IoT",
git_url="https://github.com/bastibl/gr-ieee802-15-4",
branch="main",
branch="maint-3.10",
build_deps=["castxml"],
homepage="https://github.com/bastibl/gr-ieee802-15-4",
),
_entry(
@ -246,7 +248,7 @@ CATALOG: dict[str, OOTModuleEntry] = {
description="ADS-B (1090 MHz) aircraft transponder decoder",
category="Aviation",
git_url="https://github.com/mhostetter/gr-adsb",
branch="main",
branch="maint-3.10",
homepage="https://github.com/mhostetter/gr-adsb",
),
_entry(
@ -254,7 +256,7 @@ CATALOG: dict[str, OOTModuleEntry] = {
description="Iridium satellite burst detector and demodulator",
category="Satellite",
git_url="https://github.com/muccc/gr-iridium",
branch="main",
branch="master",
homepage="https://github.com/muccc/gr-iridium",
),
_entry(
@ -263,24 +265,19 @@ CATALOG: dict[str, OOTModuleEntry] = {
category="Analysis",
git_url="https://github.com/gnuradio/gr-inspector",
branch="master",
build_deps=["qtbase5-dev", "libqwt-qt5-dev"],
homepage="https://github.com/gnuradio/gr-inspector",
gr_versions="3.9 (master branch has API compat issues with 3.10)",
),
_entry(
name="nrsc5",
description="HD Radio (NRSC-5) digital broadcast decoder",
category="Broadcast",
git_url="https://github.com/argilo/gr-nrsc5",
branch="main",
branch="master",
build_deps=["autoconf", "automake", "libtool"],
homepage="https://github.com/argilo/gr-nrsc5",
),
_entry(
name="packet_radio",
description="Amateur packet radio (AFSK, AX.25) modem",
category="Amateur",
git_url="https://github.com/duggabe/gr-packet-radio",
branch="main",
homepage="https://github.com/duggabe/gr-packet-radio",
),
]
}

View File

@ -94,7 +94,9 @@ class TestDockerfileGeneration:
assert "FROM gnuradio-runtime:latest" in dockerfile
assert "git clone --depth 1 --branch master" in dockerfile
assert "https://github.com/tapparelj/gr-lora_sdr.git" in dockerfile
assert "cd gr-lora_sdr && mkdir build" in dockerfile
assert "cd gr-lora_sdr" in dockerfile
assert "fix_binding_hashes.py" in dockerfile
assert "mkdir build" in dockerfile
assert "cmake -DCMAKE_INSTALL_PREFIX=/usr" in dockerfile
assert "make -j$(nproc)" in dockerfile
assert "ldconfig" in dockerfile