128 lines
7.5 KiB
Bash
Executable File
128 lines
7.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# check-make-shells — assert that apps/backend/Makefile's run/dev/start-debug
|
|
# and deadcode targets expand to the correct per-shell command line, without
|
|
# running them.
|
|
#
|
|
# The Makefile dispatches on two independent axes:
|
|
# * EXE suffix — keyed on $(OS): any Windows build (native cmd/PowerShell
|
|
# OR Git Bash) produces kandev.exe.
|
|
# * shell syntax — keyed on $(OS)$(MSYSTEM): only native cmd/PowerShell uses
|
|
# `set VAR=VAL&` + backslash path + no exec; Unix and Git
|
|
# Bash/MSYS use POSIX `VAR=val exec`.
|
|
# Git Bash is the trap — it sets OS=Windows_NT yet runs recipes through sh, so
|
|
# it must take the POSIX branch while keeping the .exe suffix. Conflating the
|
|
# two axes (the pre-fix bug) made Git Bash emit `set VAR=VAL&` into bash, where
|
|
# the env var is never exported.
|
|
#
|
|
# Each shell is simulated deterministically with make's OS=/MSYSTEM=
|
|
# command-line overrides, so one host checks the dispatch for all three shells
|
|
# without having to run on each. The harness itself is bash (grep, sed), so it
|
|
# needs a POSIX shell — it runs in the Linux CI job and under Git Bash/WSL
|
|
# locally, not from native cmd.exe/PowerShell. Covers the Make-target dispatch
|
|
# that the backend Go CI jobs don't exercise.
|
|
|
|
set -euo pipefail
|
|
|
|
backend_dir="$(cd "$(dirname "$0")/../apps/backend" && pwd)"
|
|
|
|
status=0
|
|
|
|
# expect <label> <OS> <MSYSTEM> <target> <expected recipe tail>
|
|
expect() {
|
|
local label=$1 os=$2 msys=$3 target=$4 want=$5 marker=${6:-__backend} title_prefix=${7:-} got
|
|
# The OS=/MSYSTEM= overrides only steer which branch the Makefile picks;
|
|
# $(shell ...) still runs under this harness's POSIX shell, and it expands
|
|
# even under `make -n`. So neutralise the build-stamp probes rather than let
|
|
# the windows-native case run them: NULL_REDIR=NUL would have sh create a
|
|
# junk ./NUL, and BUILD_TIME would spawn PowerShell per case. Blanking
|
|
# NULL_REDIR (rather than passing /dev/null) also dodges Git Bash rewriting
|
|
# a /dev/null argument to `nul` on its way to native make. None of this
|
|
# affects the run/dev/start-debug recipes under assertion.
|
|
if [ -n "$title_prefix" ]; then
|
|
got=$(KANDEV_WEB_TITLE_PREFIX="$title_prefix" make -C "$backend_dir" OS="$os" MSYSTEM="$msys" NULL_REDIR= BUILD_TIME=simulated -n "$target" 2>/dev/null \
|
|
| grep -F "$marker" \
|
|
| sed 's/^[[:space:]]*//; s/[[:space:]]*$//; s/[[:space:]]\{1,\}/ /g' \
|
|
|| true)
|
|
else
|
|
got=$(env -u KANDEV_WEB_TITLE_PREFIX make -C "$backend_dir" OS="$os" MSYSTEM="$msys" NULL_REDIR= BUILD_TIME=simulated -n "$target" 2>/dev/null \
|
|
| grep -F "$marker" \
|
|
| sed 's/^[[:space:]]*//; s/[[:space:]]*$//; s/[[:space:]]\{1,\}/ /g' \
|
|
|| true)
|
|
fi
|
|
if [ "$got" = "$want" ]; then
|
|
printf 'ok %-16s %-12s %s\n' "$label" "$target" "$got"
|
|
else
|
|
printf 'FAIL %-16s %-12s\n want: %s\n got: %s\n' \
|
|
"$label" "$target" "$want" "$got"
|
|
status=1
|
|
fi
|
|
}
|
|
|
|
# Unix — no .exe, POSIX env-prefix + exec.
|
|
expect unix '' '' run './bin/kandev __backend'
|
|
expect unix '' '' dev 'KANDEV_DEBUG_DEV_MODE=true exec ./bin/kandev __backend'
|
|
expect unix '' '' start-debug "KANDEV_DEBUG_PPROF_ENABLED=true KANDEV_LOG_LEVEL=debug KANDEV_WEB_TITLE_PREFIX='Debug' exec ./bin/kandev __backend"
|
|
expect unix '' '' start-debug "KANDEV_DEBUG_PPROF_ENABLED=true KANDEV_LOG_LEVEL=debug KANDEV_WEB_TITLE_PREFIX='Preview' exec ./bin/kandev __backend" __backend Preview
|
|
expect unix '' '' start-debug "KANDEV_DEBUG_PPROF_ENABLED=true KANDEV_LOG_LEVEL=debug KANDEV_WEB_TITLE_PREFIX='QA Debug' exec ./bin/kandev __backend" __backend "QA Debug"
|
|
|
|
# Native Windows (cmd/PowerShell) — .exe, `set VAR=VAL&`, backslash path, no exec.
|
|
expect windows-native Windows_NT '' run '"bin\kandev.exe" __backend'
|
|
expect windows-native Windows_NT '' dev 'set KANDEV_DEBUG_DEV_MODE=true& "bin\kandev.exe" __backend'
|
|
expect windows-native Windows_NT '' start-debug 'set KANDEV_DEBUG_PPROF_ENABLED=true& set KANDEV_LOG_LEVEL=debug& set "KANDEV_WEB_TITLE_PREFIX=Debug"& "bin\kandev.exe" __backend'
|
|
expect windows-native Windows_NT '' start-debug 'set KANDEV_DEBUG_PPROF_ENABLED=true& set KANDEV_LOG_LEVEL=debug& set "KANDEV_WEB_TITLE_PREFIX=Preview"& "bin\kandev.exe" __backend' __backend Preview
|
|
expect windows-native Windows_NT '' start-debug 'set KANDEV_DEBUG_PPROF_ENABLED=true& set KANDEV_LOG_LEVEL=debug& set "KANDEV_WEB_TITLE_PREFIX=QA Debug"& "bin\kandev.exe" __backend' __backend "QA Debug"
|
|
|
|
# Git Bash/MSYS — .exe suffix but POSIX syntax (recipes run through sh).
|
|
expect git-bash Windows_NT MINGW64 run './bin/kandev.exe __backend'
|
|
expect git-bash Windows_NT MINGW64 dev 'KANDEV_DEBUG_DEV_MODE=true exec ./bin/kandev.exe __backend'
|
|
expect git-bash Windows_NT MINGW64 start-debug "KANDEV_DEBUG_PPROF_ENABLED=true KANDEV_LOG_LEVEL=debug KANDEV_WEB_TITLE_PREFIX='Debug' exec ./bin/kandev.exe __backend"
|
|
expect git-bash Windows_NT MINGW64 start-debug "KANDEV_DEBUG_PPROF_ENABLED=true KANDEV_LOG_LEVEL=debug KANDEV_WEB_TITLE_PREFIX='Preview' exec ./bin/kandev.exe __backend" __backend Preview
|
|
expect git-bash Windows_NT MINGW64 start-debug "KANDEV_DEBUG_PPROF_ENABLED=true KANDEV_LOG_LEVEL=debug KANDEV_WEB_TITLE_PREFIX='QA Debug' exec ./bin/kandev.exe __backend" __backend "QA Debug"
|
|
|
|
# deadcode — the analyzer is invoked through the same shell-specific env-prefix
|
|
# mechanism, but its command has no __backend marker, so match its module path.
|
|
expect unix '' '' deadcode \
|
|
'GOTOOLCHAIN=go1.26.0 go run golang.org/x/tools/cmd/deadcode@v0.48.0 -tags fts5 ./...' \
|
|
'golang.org/x/tools/cmd/deadcode'
|
|
expect windows-native Windows_NT '' deadcode \
|
|
'set GOTOOLCHAIN=go1.26.0& go run golang.org/x/tools/cmd/deadcode@v0.48.0 -tags fts5 ./...' \
|
|
'golang.org/x/tools/cmd/deadcode'
|
|
expect git-bash Windows_NT MINGW64 deadcode \
|
|
'GOTOOLCHAIN=go1.26.0 go run golang.org/x/tools/cmd/deadcode@v0.48.0 -tags fts5 ./...' \
|
|
'golang.org/x/tools/cmd/deadcode'
|
|
|
|
# Static guard: no literal /dev/null inside $(shell ...).
|
|
#
|
|
# Unlike a recipe, which only ever runs on a platform its target supports,
|
|
# $(shell ...) expands at parse time on EVERY invocation, through whatever shell
|
|
# make picked. Under native cmd there is no /dev/null: cmd resolves the
|
|
# redirection first, fails on the missing \dev directory, and hands the value to
|
|
# the fallback — so the probe silently returns its default on Windows while
|
|
# every POSIX host looks fine. Use $(NULL_REDIR), which carries the right token
|
|
# per shell. This runs on the Linux CI, where the Windows branch is otherwise
|
|
# never exercised.
|
|
# Fail closed: grep exits 1 for "no matches" but >1 for a real scan error, and
|
|
# swallowing the difference would let an unreadable or moved Makefile report ok.
|
|
grep_status=0
|
|
# `#` starts a comment anywhere in a Makefile line, so the match must not span
|
|
# one: [^#]* keeps a prose mention like `FOO = bar # $(shell x 2>/dev/null)`
|
|
# from failing CI, and cannot reach past a whole-line comment either. It matches
|
|
# empty so a bare `$(shell ...)` in column 0 still counts.
|
|
devnull_hits=$(grep -nE '^[[:space:]]*[^#]*\$\(shell[^#]*/dev/null' \
|
|
"$backend_dir/../../Makefile" "$backend_dir/Makefile") || grep_status=$?
|
|
if [ "$grep_status" -gt 1 ]; then
|
|
printf 'FAIL %-16s unable to scan Makefiles (grep exit %s)\n' "static" "$grep_status"
|
|
status=1
|
|
elif [ -n "$devnull_hits" ]; then
|
|
printf 'FAIL %-16s literal /dev/null inside $(shell ...) — use $(NULL_REDIR)\n' "static"
|
|
printf ' %s\n' "$devnull_hits"
|
|
status=1
|
|
else
|
|
printf 'ok %-16s %s\n' "static" 'no literal /dev/null inside $(shell ...)'
|
|
fi
|
|
|
|
if [ "$status" -eq 0 ]; then
|
|
echo "All Makefile shell-dispatch checks passed (3 shells x 4 targets, plus static guard)."
|
|
fi
|
|
exit "$status"
|