joeylib2/scripts/lib/joeyEnv.sh
2026-09-28 21:03:46 -05:00

125 lines
4 KiB
Bash

# Sourced by the scripts in scripts/ (and tools/) so every one of them finds
# toolchains the same way: from the environment ./install.sh generates. A script calls joeyNeed for each tool it uses, and gets a clear
# "install this" message (exit 2, which the gate runners treat as SKIP)
# instead of failing halfway through with a missing binary.
JOEY_REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
if [ -f "$JOEY_REPO/toolchains/env.sh" ]; then
# shellcheck source=/dev/null
source "$JOEY_REPO/toolchains/env.sh"
fi
# joeyNeed VAR INSTALL-TARGET -- exit 2 unless VAR names an existing path.
joeyNeed() {
local var="$1"
local target="$2"
if [ -z "${!var:-}" ] || [ ! -e "${!var}" ]; then
echo "$(basename "$0"): $var is not available; run: ./install.sh install $target" >&2
exit 2
fi
}
# joeyNeedFile PATH INSTALL-TARGET -- exit 2 unless PATH exists.
joeyNeedFile() {
if [ ! -e "$1" ]; then
echo "$(basename "$0"): $1 is missing; run: ./install.sh install $2" >&2
exit 2
fi
}
# DOSBox Staging must never read or write the user's own DOSBox setup, even
# ~/.config/dosbox (it creates that tree even with --noprimaryconf). Launch
# it as
# XDG_CONFIG_HOME="$work/xdg" "$DOSBOX" "${JOEY_DOSBOX_ISOLATE[@]}" ...
JOEY_DOSBOX_ISOLATE=(--noprimaryconf --nolocalconf)
# joeyExampleProgram NAME PORT -- the built program for an example name. A
# program that ships in its own folder with its DATA (Space Taxi on every
# port but the IIgs) is found inside that folder. When nothing is built yet
# it prints the flat path, so the caller's "not built" message names it.
joeyExampleProgram() {
local name="$1"
local bin="$JOEY_REPO/build/$2/bin"
local up="${name^^}"
local ext=""
local candidate
[ "$up" = "SPACETAXI" ] && up=STAXI
case "$2" in
iigs)
printf '%s\n' "$bin/$up"
return 0
;;
amiga)
# Mixed-case names, and Space Taxi is called Taxi there.
up="${name,,}"
case "$up" in
staxi|spacetaxi) up=taxi ;;
esac
up="${up^}"
;;
atarist) ext=".PRG" ;;
dos) ext=".EXE" ;;
x68000) ext=".X" ;;
*)
echo "$(basename "$0"): unknown port '$2' (iigs, amiga, atarist, dos or x68000)" >&2
return 2
;;
esac
for candidate in "$bin/$up/$up$ext" "$bin/$up$ext"; do
if [ -f "$candidate" ]; then
printf '%s\n' "$candidate"
return 0
fi
done
printf '%s\n' "$bin/$up$ext"
}
# joeyFindWindow DISPLAY PID -- print the X window owned by process PID.
# More robust than matching titles, which differ between emulator builds.
joeyFindWindow() {
local win
for win in $(DISPLAY="$1" xdotool search --name -- "." 2>/dev/null); do
if [ "$(DISPLAY="$1" xdotool getwindowpid "$win" 2>/dev/null)" = "$2" ]; then
printf '%s\n' "$win"
return 0
fi
done
return 1
}
# joeyAlive PID -- PID is running. A zombie (exited, not yet reaped) is not,
# although `kill -0` still succeeds on it.
joeyAlive() {
local stat
stat="$(ps -o stat= -p "$1" 2>/dev/null)" || return 1
[[ "$stat" != Z* ]]
}
# joeyStop PID... -- stop emulator processes and make sure they are gone.
# Hatari, MAME and DOSBox Staging ignore or are slow to act on SIGTERM; a
# plain `kill` left them running (and burning CPU) after their script had
# finished, so escalate to SIGKILL. Only ever pass PIDs this script started.
joeyStop() {
local pid
local tick
for pid in "$@"; do
[ -n "$pid" ] || continue
kill "$pid" 2>/dev/null || continue
for tick in 1 2 3 4 5 6 7 8 9 10; do
joeyAlive "$pid" || break
sleep 0.2
done
kill -9 "$pid" 2>/dev/null || true
# Reap it when it is this shell's child (a no-op otherwise), so no
# zombie outlives the script where nothing else would reap it.
wait "$pid" 2>/dev/null || true
done
}