#!/usr/bin/env bash # Expose each participant's own Arduino files INTO the apess-onboard app container # so the agent can read, correct, and complete their implementation. # # WHY THIS EXISTS # The App Lab container only bind-mounts the app's own directory # (/home/arduino/ArduinoApps/apess-onboard -> /app). A student's real work lives # elsewhere and is invisible to the agent: # ~/sketches//.ino App Lab "sketch editor" projects (primary) # ~/ArduinoApps// full App Lab apps # ~/Arduino/libraries/ installed libraries # App Lab has NO volumes field in app.yaml and generates the compose itself, so # we can't declare these there. Instead we bind the user paths UNDERNEATH the app # dir (which /app already maps). The catch: the /app bind is `rprivate`, so a # submount added AFTER the container starts does NOT propagate in — the binds must # exist BEFORE the app container is created. Hence a root oneshot ordered # Before=arduino-app-cli.service (see apess-user-workspace.service). # # RESULT INSIDE THE CONTAINER # /app/workspace/sketches/ <- ~/sketches (rw) # /app/workspace/apps// <- ~/ArduinoApps/ (rw, minus ourselves) # /app/workspace/libraries/ <- ~/Arduino/libraries (ro, reference) # # Idempotent — safe to re-run. Requires root (mount(2) is privileged). set -euo pipefail USER_HOME=${USER_HOME:-/home/arduino} APP_DIR=${APP_DIR:-$USER_HOME/ArduinoApps/apess-onboard} WS="$APP_DIR/workspace" SELF=$(basename "$APP_DIR") if [ "$(id -u)" -ne 0 ]; then echo "must run as root (mount is privileged) — try: sudo $0" >&2 exit 1 fi bind() { # src dst [ro] local src=$1 dst=$2 ro=${3:-} if [ ! -d "$src" ]; then echo "skip (no source dir): $src"; return 0; fi mkdir -p "$dst" if mountpoint -q "$dst"; then echo "already mounted: $dst"; return 0; fi mount --bind "$src" "$dst" [ "$ro" = ro ] && mount -o remount,ro,bind "$dst" echo "mounted: $src -> $dst${ro:+ (ro)}" } mkdir -p "$WS" "$WS/apps" chown "$(stat -c '%u:%g' "$USER_HOME")" "$WS" "$WS/apps" 2>/dev/null || true bind "$USER_HOME/sketches" "$WS/sketches" bind "$USER_HOME/Arduino/libraries" "$WS/libraries" ro # Each OTHER App Lab app — skip ourselves so we don't recursively self-mount. if [ -d "$USER_HOME/ArduinoApps" ]; then for d in "$USER_HOME/ArduinoApps"/*/; do [ -d "$d" ] || continue name=$(basename "$d") [ "$name" = "$SELF" ] && continue bind "$d" "$WS/apps/$name" done fi echo "workspace ready: $WS" echo "note: a NEW sibling app created after boot needs a re-run + app restart to appear" echo " (rprivate /app); new *sketches* in ~/sketches appear live, no restart needed."