#!/usr/bin/env bash set -euo pipefail action="${1:?action is required}" root="${STEM_REPO:-${CARD_ROOT:-$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)}}" profile="${STEM_PROFILE:-native-amd64}" target="${STEM_TARGET:-native}" selector="${STEM_TASK:-task1}" card_id="$(sed -n 's/^card: cpp\///p' "$root/lesson-flow.yaml" | head -n1)" resolve_task() { local value="${1,,}" if [[ "$value" =~ ^(task|t)?[-_]?0*([1-3])($|[-_].*) ]]; then printf 'task%02d\n' "${BASH_REMATCH[2]}"; return; fi [[ "$value" =~ ^task0[1-3]$ ]] && { printf '%s\n' "$value"; return; } printf 'Unknown task selector: %s\n' "$1" >&2; exit 2 } task="$(resolve_task "$selector")" artifact_dir="$root/.stem/artifacts/$profile/$target/$task" binary="$artifact_dir/program" mkdir -p "$artifact_dir" compile_task() { local selected="$1" output="$2" mapfile -t sources < <(find "$root/src/$selected" -maxdepth 1 -type f -name '*.cpp' | sort) [[ ${#sources[@]} -gt 0 ]] || { printf 'No C++ sources for %s\n' "$selected" >&2; exit 2; } "${CXX:-g++}" -std=c++20 -Wall -Wextra -Wpedantic -Werror -O0 -g3 -fno-omit-frame-pointer -I"$root/src/$selected" "${sources[@]}" -o "$output" } verify_task() { local selected="$1" output="$2" actual="$artifact_dir/actual.txt" compile_task "$selected" "$output" "$output" >"$actual" diff -u "$root/tests/expected/$selected.txt" "$actual" } case "$profile:$target:$action" in native-amd64:native:build) for item in task01 task02 task03; do current="$root/.stem/artifacts/$profile/$target/$item" mkdir -p "$current" compile_task "$item" "$current/program" done printf 'BUILD %s standard=c++20 tasks=3\n' "$card_id" ;; native-amd64:native:test|native-amd64:native:run) verify_task "$task" "$binary" printf 'PASS %s %s standard=c++20\n' "$card_id" "$task" ;; native-amd64:native:debug) verify_task "$task" "$binary" trace="$artifact_dir/debug.log" if command -v gdb >/dev/null 2>&1; then gdb -q -batch -ex 'set pagination off' -ex 'set debuginfod enabled off' -ex 'break main' -ex run -ex 'info source' -ex 'info args' -ex continue "$binary" >"$trace" 2>&1 else { printf 'gdb unavailable; binary evidence follows\n'; "${NM:-nm}" -C "$binary" | head -n 80; "$binary"; } >"$trace" 2>&1 fi cat "$trace" [[ -s "$trace" ]] printf 'TRACE %s %s log=%s\n' "$card_id" "$task" "$trace" ;; *) printf 'Unsupported profile/target/action: %s/%s/%s\n' "$profile" "$target" "$action" >&2; exit 2 ;; esac