From 2a385df69f9d2033d3bde3fd25befe0173a065c0 Mon Sep 17 00:00:00 2001 From: Arnav Wadhwa Date: Tue, 1 Sep 2026 17:00:46 -0700 Subject: [PATCH] chore: remove redundant comments --- .github/CODEOWNERS | 1 - .github/workflows/build-image.yml | 12 ++------- .github/workflows/validate.yml | 22 +++------------ build-image.sh | 26 +++--------------- customize.sh | 36 +++---------------------- files/dpea-eth0.nmconnection | 4 +-- hardware-smoke-test.sh | 9 +------ imager-launchers/dpea-pi-imager.bat | 2 -- imager-launchers/dpea-pi-imager.command | 2 -- packages.txt | 24 +---------------- 10 files changed, 16 insertions(+), 122 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c11313f..74653c5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,2 +1 @@ -# The MechatronicsAdmin team owns everything: PRs require their review. * @dpengineering/mechatronicsadmin diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index 914c394..80de8e5 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -1,9 +1,3 @@ -# Build + publish the DPEA Pi image. -# Rebuilds when an image-affecting file changes on main, and on demand. -# Customizes the stock Raspberry Pi OS image (see build-image.sh) on a native -# arm64 runner, so the chroot's arm64 binaries run natively. Requires the 5358 -# avahi .deb published by the avahi_0.8 repo's CI. - name: build-dpea-pi-image on: @@ -43,9 +37,7 @@ jobs: . .build/image-meta.env TAG="dpea-pi-$(date +%Y%m%d-%H%M)" IMG_URL="/${GITHUB_REPOSITORY}/releases/download/${TAG}/${IMG_FILE}" - # os-list.json = a Raspberry Pi Imager repo with one entry. init_format - # enables the Customisation panel; the constant asset name means - # .../releases/latest/download/os-list.json is a stable URL for Imager. + # init_format enables Imager's Customisation panel. jq -n \ --arg url "$IMG_URL" \ --arg date "$(date +%Y-%m-%d)" \ @@ -67,7 +59,7 @@ jobs: echo "IMG_FILE=$IMG_FILE" >> "$GITHUB_ENV" - name: Publish latest Release - if: github.event_name != 'pull_request' # publish on push + manual dispatch + if: github.event_name != 'pull_request' env: GH_TOKEN: ${{ github.token }} run: | diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index b3a8a1a..4a4c427 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -1,7 +1,3 @@ -# PR validation: make sure a change would still produce a working image before it -# merges to main. Much cheaper than a full build: it runs the customization in a -# container, not a full loop-mounted image. - name: validate on: @@ -18,7 +14,7 @@ jobs: shellcheck -S error build-image.sh customize.sh hardware-smoke-test.sh customize-in-container: - runs-on: ubuntu-24.04-arm # native arm64 container + runs-on: ubuntu-24.04-arm steps: - uses: actions/checkout@v4 - name: Run customize.sh in an arm64 Trixie container and assert @@ -32,37 +28,25 @@ jobs: install -d -m 700 /etc/NetworkManager/system-connections install -m 600 /src/files/dpea-eth0.nmconnection \ /etc/NetworkManager/system-connections/dpea-eth0.nmconnection - # Simulate the real RPi OS Desktop base, which already ships stock avahi. - # A bare Trixie container does NOT, so without this the avahi-dpea - # file-overwrite conflict (a missing Replaces:) stays hidden here and only - # surfaces on the real image build. Installing stock avahi first makes CI - # reproduce that conflict, which is the whole point of this gate. + # Reproduce replacement conflicts with the stock avahi package. apt-get install -y avahi-daemon libnss-mdns - # The real base image also ships an RPi-MODIFIED avahi-daemon.conf, so - # replacing it triggers an interactive dpkg conffile prompt that aborts a - # non-interactive install. Dirty the conffile here so CI reproduces that - # too, not just the file-overwrite conflict. + # Reproduce the conffile prompt caused by Raspberry Pi OS's modified config. echo '# dpea-ci: simulate a base-image modified conffile' >> /etc/avahi/avahi-daemon.conf bash /src/customize.sh echo "===== assertions =====" fail=0 command -v uv >/dev/null && echo "OK uv $(uv --version)" || { echo "FAIL uv"; fail=1; } dpkg -s avahi-dpea >/dev/null 2>&1 && echo "OK avahi-dpea installed" || { echo "FAIL avahi-dpea"; fail=1; } - # It must actually take OVER the stock daemon binary, not just install - # alongside it. Replaces: transfers file ownership to avahi-dpea. dpkg -S /usr/sbin/avahi-daemon 2>/dev/null | grep -q '^avahi-dpea:' \ && echo "OK /usr/sbin/avahi-daemon owned by avahi-dpea" \ || { echo "FAIL avahi-daemon binary not replaced by avahi-dpea"; fail=1; } for line in "dtparam=i2c_arm=on" "enable_uart=1" "dtoverlay=disable-bt"; do grep -qx "$line" /boot/firmware/config.txt && echo "OK config: $line" || { echo "FAIL config: $line"; fail=1; } done - # SPI must NOT be enabled: it would claim GPIO7 (SPI0 CE1), a DPi computer input. grep -qx "dtparam=spi=on" /boot/firmware/config.txt && { echo "FAIL config: spi should be off"; fail=1; } || echo "OK config: spi not enabled" - # serial login console masked so the DPi RS485 bus owns /dev/serial0. test -L /etc/systemd/system/serial-getty@ttyAMA0.service && echo "OK serial getty masked" || { echo "FAIL serial getty not masked"; fail=1; } test -f /etc/NetworkManager/system-connections/dpea-eth0.nmconnection \ && echo "OK eth0 profile present" || { echo "FAIL eth0 profile"; fail=1; } - # best-effort: mDNS binds 5358 (a container may not let the daemon start; verify on hardware) (service dbus start >/dev/null 2>&1 || true; avahi-daemon -D >/dev/null 2>&1 || true; sleep 2) if ss -lun 2>/dev/null | grep -q ":5358"; then echo "OK avahi listening on 5358" else echo "WARN could not confirm 5358 in container (verify on hardware)"; fi diff --git a/build-image.sh b/build-image.sh index 0fe3314..80a0440 100755 --- a/build-image.sh +++ b/build-image.sh @@ -1,25 +1,12 @@ #!/usr/bin/env bash -# Build the DPEA Raspberry Pi OS image by customizing the stock Raspberry Pi OS -# arm64 image: download it, grow it, loop-mount it, run customize.sh in a chroot, -# then recompress. -# -# Invoked by the build-image GitHub Actions workflow (.github/workflows/build-image.yml), -# which runs on a native arm64 runner, so the chroot's arm64 binaries run natively. -# Must run as root (loop-mount + chroot). -# -# Tools: xz-utils parted e2fsprogs curl -# -# PREREQUISITE: the 5358 avahi .deb must be published (avahi_0.8 CI). The chroot -# step hard-fails without it. set -euo pipefail HERE="$(cd "$(dirname "$0")" && pwd)" WORK="${WORK:-$HERE/.build}" -# Stock Raspberry Pi OS (arm64, desktop). PIN a dated release for reproducibility; -# check https://downloads.raspberrypi.com/raspios_arm64/images/ for the current one. +# Keep this dated URL pinned so builds are reproducible. BASE_URL="${BASE_URL:-https://downloads.raspberrypi.com/raspios_arm64/images/raspios_arm64-2026-06-19/2026-06-18-raspios-trixie-arm64.img.xz}" -GROW_MB="${GROW_MB:-2048}" # headroom for our added packages +GROW_MB="${GROW_MB:-2048}" OUT_IMG="$WORK/dpea-pi-$(date +%Y%m%d).img" [ "$(id -u)" -eq 0 ] || { echo "run as root (loop-mount + chroot)" >&2; exit 1; } @@ -30,9 +17,8 @@ base_xz="$(basename "$BASE_URL")"; base_img="${base_xz%.xz}" [ -f "$base_img" ] || xz -dk "$base_xz" cp -f "$base_img" "$OUT_IMG" -# --- grow the image file + root partition (p2) --- truncate -s "+${GROW_MB}M" "$OUT_IMG" -LOOP="$(losetup -fP --show "$OUT_IMG")" # exposes ${LOOP}p1 (boot) + ${LOOP}p2 (root) +LOOP="$(losetup -fP --show "$OUT_IMG")" cleanup() { set +e for d in run sys proc dev/pts dev; do umount "$WORK/mnt/$d" 2>/dev/null; done @@ -45,14 +31,12 @@ parted -s "$LOOP" resizepart 2 100% e2fsck -fy "${LOOP}p2" || true resize2fs "${LOOP}p2" -# --- mount root + boot + pseudo-filesystems --- MNT="$WORK/mnt"; mkdir -p "$MNT" mount "${LOOP}p2" "$MNT" mount "${LOOP}p1" "$MNT/boot/firmware" for d in dev dev/pts proc sys run; do mount --bind "/$d" "$MNT/$d"; done cp /etc/resolv.conf "$MNT/etc/resolv.conf" -# --- drop our files in and run the customization --- install -m 644 "$HERE/packages.txt" "$MNT/tmp/packages.txt" install -d -m 700 "$MNT/etc/NetworkManager/system-connections" install -m 600 "$HERE/files/dpea-eth0.nmconnection" \ @@ -61,11 +45,9 @@ install -m 755 "$HERE/customize.sh" "$MNT/tmp/customize.sh" chroot "$MNT" /bin/bash /tmp/customize.sh rm -f "$MNT/tmp/customize.sh" -# --- unmount (via trap) + compress --- cleanup; trap - EXIT -# Record metadata for the Raspberry Pi Imager OS list (os-list.json, built by CI): -# the sha256 + size are of the UNCOMPRESSED image, which Imager verifies. +# Raspberry Pi Imager verifies the uncompressed image size and checksum. EXTRACT_SIZE="$(stat -c%s "$OUT_IMG")" EXTRACT_SHA256="$(sha256sum "$OUT_IMG" | awk '{print $1}')" xz -T0 -f "$OUT_IMG" diff --git a/customize.sh b/customize.sh index 8c5496b..852e5fe 100755 --- a/customize.sh +++ b/customize.sh @@ -1,24 +1,14 @@ #!/bin/bash -# DPEA image customizations. Runs INSIDE the mounted image chroot (see build-image.sh), -# and inside the CI validation container (see .github/workflows/validate.yml). -# Expects /tmp/packages.txt already copied in, and the NetworkManager profile -# already placed at /etc/NetworkManager/system-connections/dpea-eth0.nmconnection. - -# Both callers invoke this as `bash customize.sh`, which ignores the shebang's -# flags, so set the strict flags in the body or a failed step is silently skipped. set -euo pipefail export DEBIAN_FRONTEND=noninteractive -# --- shared non-Python system packages --- apt-get update # shellcheck disable=SC2046 apt-get install -y --no-install-recommends \ $(sed -e 's/#.*//' -e '/^[[:space:]]*$/d' /tmp/packages.txt) -# --- hardware interfaces (edit config.txt directly) --- # SPI is deliberately NOT enabled: the DPi computer board uses GPIO7 (SPI0 CE1) -# as a digital input (_IN_3_PIN), so an enabled SPI overlay claims that pin and -# the board's GPIO.setup fails with "GPIO busy". +# as a digital input, and the SPI overlay would claim it. CONFIG=/boot/firmware/config.txt [ -f "$CONFIG" ] || CONFIG=/boot/config.txt grep -q '^dtparam=i2c_arm=on' "$CONFIG" || echo 'dtparam=i2c_arm=on' >> "$CONFIG" @@ -26,40 +16,24 @@ grep -q '^enable_uart=1' "$CONFIG" || echo 'enable_uart=1' >> "$CO grep -q '^dtoverlay=disable-bt' "$CONFIG" || echo 'dtoverlay=disable-bt' >> "$CONFIG" grep -q '^i2c-dev' /etc/modules || echo 'i2c-dev' >> /etc/modules -# --- serial login console OFF (the UART hardware stays on via enable_uart above) --- -# Raspberry Pi OS runs a getty on the serial console by default; it holds -# /dev/serial0 open and fights the DPi RS485 bus (serial.Serial on /dev/serial0), -# giving "device reports readiness to read but returned no data (multiple access -# on port?)". Disable it two ways: drop the console= token from cmdline.txt, and -# mask the serial getty. enable_uart=1 above keeps the UART itself available. +# The default serial getty competes with the DPi RS485 bus for /dev/serial0. CMDLINE=/boot/firmware/cmdline.txt [ -f "$CMDLINE" ] || CMDLINE=/boot/cmdline.txt [ -f "$CMDLINE" ] && sed -i -E 's/ ?console=(serial0|ttyAMA0|ttyS0),[0-9]+//g' "$CMDLINE" install -d /etc/systemd/system ln -sf /dev/null /etc/systemd/system/serial-getty@ttyAMA0.service -# --- patched avahi (mDNS on 5358) from the prebuilt arm64 .deb (avahi_0.8 CI) --- AVAHI_DEB_URL="${AVAHI_DEB_URL:-https://github.com/dpengineering/avahi_0.8/releases/latest/download/avahi-dpea_0.8_arm64.deb}" if curl -fLsS "$AVAHI_DEB_URL" -o /tmp/avahi.deb; then - # The .deb Replaces stock avahi and ships /etc/avahi/avahi-daemon.conf as a - # conffile. The base image's copy is RPi-modified, so dpkg would raise an - # interactive conffile prompt and abort with "end of file on stdin" in this - # non-interactive chroot. --force-confold keeps the base config (our 5358 patch - # is in the binary/lib, not the conf), --force-confdef handles the rest. + # Keep Raspberry Pi OS's modified config to avoid an interactive dpkg prompt. apt-get install -y \ -o Dpkg::Options::=--force-confdef \ -o Dpkg::Options::=--force-confold \ /tmp/avahi.deb - # The stock RPi OS Desktop base already ships avahi, so the .deb must overwrite - # its files (it declares Replaces: for them). A dpkg file-overwrite conflict can - # leave the package uninstalled while apt still exits 0, so assert it is actually - # present instead of trusting the exit code. + # A dpkg file conflict can leave the package absent even when apt exits 0. dpkg -s avahi-dpea >/dev/null 2>&1 \ || { echo "ERROR: avahi-dpea did not install (dpkg file conflict / missing Replaces:?)" >&2; exit 1; } - # Refresh the linker cache so the patched libavahi-core (mDNS on 5358) it just - # dropped in is the one the daemon loads, not the stock lib it overwrote. ldconfig - # Hold both so an apt upgrade cannot restore the stock 5353 build over ours. apt-mark hold avahi-daemon avahi-dpea >/dev/null 2>&1 || true rm -f /tmp/avahi.deb else @@ -67,10 +41,8 @@ else exit 1 fi -# --- uv, system-wide --- curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh -# --- lock down the baked NetworkManager profile --- chown root:root /etc/NetworkManager/system-connections/dpea-eth0.nmconnection chmod 600 /etc/NetworkManager/system-connections/dpea-eth0.nmconnection diff --git a/files/dpea-eth0.nmconnection b/files/dpea-eth0.nmconnection index e79259e..faf28c4 100644 --- a/files/dpea-eth0.nmconnection +++ b/files/dpea-eth0.nmconnection @@ -5,9 +5,7 @@ interface-name=eth0 autoconnect=true [ipv4] -# DHCP for internet when plugged into a real network, PLUS an always-on static -# for a direct laptop-to-Pi cable (set the laptop's ethernet to 172.17.21.1). -# No gateway on the static, so it never competes for the default route. +# The gateway-free static address supports direct connections without replacing DHCP's route. method=auto address1=172.17.21.2/22 may-fail=true diff --git a/hardware-smoke-test.sh b/hardware-smoke-test.sh index a50c9e2..046b059 100755 --- a/hardware-smoke-test.sh +++ b/hardware-smoke-test.sh @@ -1,9 +1,4 @@ #!/usr/bin/env bash -# Smoke-test a flashed DPEA Pi. Run ON the Pi after its first boot: -# sudo ./hardware-smoke-test.sh -# Exits non-zero if any check fails. Covers the things the CI container cannot: -# real device nodes, the serial mapping, live mDNS port, and the eth0 address. - set -u pass=0; fail=0; skipped=0 chk(){ if eval "$2" >/dev/null 2>&1; then echo "PASS $1"; pass=$((pass+1)); else echo "FAIL $1"; fail=$((fail+1)); fi; } @@ -16,9 +11,7 @@ chk "/dev/serial0 -> ttyAMA0" "[ \"\$(readlink -f /dev/serial0)\" = /dev/tty chk "serial login console off" "! systemctl is-active --quiet serial-getty@ttyAMA0.service" chk "avahi listening on 5358" "ss -lun | grep -q ':5358'" chk "avahi NOT on 5353" "! ss -lun | grep -q ':5353'" -# The eth0 static (172.17.21.2) only activates when the link has carrier. Running -# this over wifi with no ethernet cable is not an image defect, so SKIP rather than -# FAIL when eth0 has no carrier; plug a cable (or the direct laptop link) and re-run. +# The static address cannot activate without an Ethernet carrier. if [ "$(cat /sys/class/net/eth0/carrier 2>/dev/null || echo 0)" = 1 ]; then chk "eth0 holds 172.17.21.2" "ip -4 addr show eth0 | grep -q '172.17.21.2'" else diff --git a/imager-launchers/dpea-pi-imager.bat b/imager-launchers/dpea-pi-imager.bat index 2857134..303866e 100644 --- a/imager-launchers/dpea-pi-imager.bat +++ b/imager-launchers/dpea-pi-imager.bat @@ -1,4 +1,2 @@ @echo off -rem Windows: double-click to launch Raspberry Pi Imager preloaded with the DPEA -rem image list, so "DPEA Pi" appears with the Customisation panel enabled. start "" "%ProgramFiles%\Raspberry Pi Imager\rpi-imager.exe" --repo https://github.com/dpengineering/DPEA-RaspberryPiImage/releases/latest/download/os-list.json diff --git a/imager-launchers/dpea-pi-imager.command b/imager-launchers/dpea-pi-imager.command index 78d072f..e92c69f 100755 --- a/imager-launchers/dpea-pi-imager.command +++ b/imager-launchers/dpea-pi-imager.command @@ -1,5 +1,3 @@ #!/bin/bash -# macOS: double-click to launch Raspberry Pi Imager preloaded with the DPEA image -# list, so "DPEA Pi" appears in the OS list with the Customisation panel enabled. exec "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/Applications/Raspberry Pi Imager.app/Contents/MacOS/rpi-imager" \ --repo https://github.com/dpengineering/DPEA-RaspberryPiImage/releases/latest/download/os-list.json diff --git a/packages.txt b/packages.txt index c09f401..859b810 100644 --- a/packages.txt +++ b/packages.txt @@ -1,34 +1,14 @@ -# DPEA Raspberry Pi image: shared apt packages (single source of truth) -# ---------------------------------------------------------------------- -# NON-Python OS packages ONLY. Every Python library (kivy, pidev, dpeaDPi, -# RPi.GPIO, spidev, smbus2, adafruit-*) is a per-repo uv dependency declared in -# that repo's pyproject.toml. apt python3-* LIBRARY packages do NOT populate a uv -# venv, so they never belong here. The lone exception is build tooling: python3-dev -# ships the CPython headers used to COMPILE a C extension (e.g. lgpio) into a venv, -# it is not itself a venv library. -# -# Read during the image build (build-image.sh copies it in, customize.sh installs -# it). Lines starting with # and blank lines are ignored. Keep this list -# documented in README.md. - -# --- core --- git curl ca-certificates -# --- I2C bus tooling (SlushEngine + DPi boards; SPI is left off, see customize.sh) --- i2c-tools -# --- rpi-lgpio build toolchain (DPi boards) --- -# dpeaDPi imports RPi.GPIO, provided on modern Pi OS / Python 3.13 by rpi-lgpio, -# whose lgpio dep has no aarch64 cp313 wheel and so compiles from source at -# `uv sync` time. swig + python3-dev build the C extension, liblgpio-dev links it -# (and pulls the runtime liblgpio shared lib). See the python3-dev note up top. +# lgpio has no aarch64 Python 3.13 wheel, so uv builds it from source. swig python3-dev liblgpio-dev -# --- kivy runtime: SDL2 + multitouch + GL (the kivy wheel links these at runtime) --- libsdl2-2.0-0 libsdl2-image-2.0-0 libsdl2-mixer-2.0-0 @@ -36,6 +16,4 @@ libsdl2-ttf-2.0-0 libmtdev1 libgl1-mesa-dri -# --- mDNS / .local name resolution (client-side NSS glue; the patched 5358 -# avahi daemon itself is installed separately from a prebuilt .deb) --- libnss-mdns