mirror of
https://github.com/kuhyx/screen-locker.git
synced 2026-11-13 04:00:48 +01:00
116 lines
4.4 KiB
Bash
Executable File
116 lines
4.4 KiB
Bash
Executable File
#!/bin/bash
|
|
# Deploy screen-locker for real: update the live clone, reinstall, restart the
|
|
# long-running user units, prove they are healthy, then ship the workout app.
|
|
#
|
|
# Usage: bash scripts/deploy.sh [--health-only]
|
|
#
|
|
# Every path is anchored on the LIVE clone (~/src/screen-locker), never on this
|
|
# script's own directory: install.sh installs editable from wherever it sits,
|
|
# so running a worktree copy of it would point the services at scratch code.
|
|
#
|
|
# workout-locker.service is deliberately NOT restarted: it is the login-time
|
|
# gate and starting it can lock the display. Its timer is only re-enabled.
|
|
#
|
|
# Phone: phone_deploy.sh refuses com.kuhy.workout_app (exit 46) unless kuhy
|
|
# runs this himself with PHONE_PROTECT_ALLOW=com.kuhy.workout_app and the app
|
|
# closed. This script never sets that variable; it passes the caller's
|
|
# environment through and fails loudly when the guard refuses.
|
|
#
|
|
# Seams: SCREEN_LOCKER_LIVE (live clone), DEPLOY_WEB_PORT (health port).
|
|
# Exit: 0 healthy and installed everywhere | 1 any step or check failed.
|
|
|
|
set -euo pipefail
|
|
|
|
readonly LIVE="${SCREEN_LOCKER_LIVE:-$HOME/src/screen-locker}"
|
|
readonly PY="/usr/bin/python3"
|
|
readonly APP_DIR="stronglift_replacement/workout_app"
|
|
readonly PHONE_DEPLOY="$HOME/.claude/scripts/phone_deploy.sh"
|
|
readonly UNITS=(screen-locker-web.service workout-poke.service runnerup-watch.service)
|
|
|
|
die() { echo "deploy: FAIL: $*" >&2; exit 1; }
|
|
ok() { echo "deploy: ok: $*"; }
|
|
|
|
main_pid() { systemctl --user show -p MainPID --value "$1"; }
|
|
|
|
web_port() {
|
|
if [[ -n "${DEPLOY_WEB_PORT:-}" ]]; then
|
|
echo "$DEPLOY_WEB_PORT"
|
|
else
|
|
(cd /tmp && "$PY" -c 'from screen_locker._web_server import DEFAULT_PORT; print(DEFAULT_PORT)')
|
|
fi
|
|
}
|
|
|
|
# /api/health answers and reports enforcement armed; retried while the
|
|
# freshly restarted server binds its port.
|
|
check_web() {
|
|
local port body i
|
|
port="$(web_port)"
|
|
for i in $(seq 1 15); do
|
|
if body="$(curl -fsS --max-time 2 "http://127.0.0.1:$port/api/health" 2>/dev/null)"; then
|
|
jq -e '.armed == true' >/dev/null <<<"$body" \
|
|
|| die "web health on :$port says enforcement is NOT armed"
|
|
ok "web /api/health on :$port armed (try $i)"
|
|
return 0
|
|
fi
|
|
sleep 1
|
|
done
|
|
die "web /api/health on :$port did not answer within 15 s"
|
|
}
|
|
|
|
health() {
|
|
local unit
|
|
for unit in "${UNITS[@]}"; do
|
|
systemctl --user is-active --quiet "$unit" || die "$unit is not active"
|
|
ok "$unit active"
|
|
done
|
|
check_web
|
|
"$PY" "$LIVE/scripts/check_enforcement_armed.py" --quiet \
|
|
|| die "check_enforcement_armed.py: enforcement is not armed"
|
|
ok "enforcement armed"
|
|
"$PY" "$LIVE/scripts/poke_selftest.py" sandbox >/dev/null \
|
|
|| die "workout-poke sandbox self-test failed"
|
|
ok "workout-poke signed sandbox round trip"
|
|
local mod
|
|
mod="$(cd /tmp && "$PY" -c 'import screen_locker; print(screen_locker.__file__)')"
|
|
[[ "$mod" == "$LIVE"/* ]] || die "screen_locker imports from $mod, not $LIVE"
|
|
ok "screen_locker imports from the live clone"
|
|
}
|
|
|
|
desktop() {
|
|
local unit
|
|
declare -A before=()
|
|
git -C "$LIVE" pull --ff-only || die "git pull --ff-only in $LIVE (dirty or diverged?)"
|
|
[[ "$(git -C "$LIVE" rev-parse HEAD)" == "$(git -C "$LIVE" rev-parse '@{u}')" ]] \
|
|
|| die "$LIVE HEAD is not its upstream after the pull"
|
|
ok "live clone at $(git -C "$LIVE" rev-parse --short HEAD)"
|
|
bash "$LIVE/install.sh" || die "install.sh failed"
|
|
for unit in "${UNITS[@]}"; do before[$unit]="$(main_pid "$unit")"; done
|
|
systemctl --user restart "${UNITS[@]}" || die "restart of ${UNITS[*]} failed"
|
|
for unit in "${UNITS[@]}"; do
|
|
[[ "$(main_pid "$unit")" != "${before[$unit]}" ]] \
|
|
|| die "$unit kept PID ${before[$unit]}: restart did not take"
|
|
done
|
|
ok "restarted ${UNITS[*]}"
|
|
}
|
|
|
|
phone() {
|
|
local rc=0
|
|
bash "$PHONE_DEPLOY" "$LIVE/$APP_DIR" --release || rc=$?
|
|
case "$rc" in
|
|
0) ok "workout app release build installed on the phone" ;;
|
|
46) die "phone_deploy protect guard (exit 46) refused com.kuhy.workout_app;" \
|
|
"kuhy runs: PHONE_PROTECT_ALLOW=com.kuhy.workout_app bash $LIVE/scripts/deploy.sh" \
|
|
"with the workout app closed" ;;
|
|
*) die "phone_deploy.sh exited $rc (see its exit-code table)" ;;
|
|
esac
|
|
}
|
|
|
|
if [[ "${1:-}" == "--health-only" ]]; then
|
|
health
|
|
exit 0
|
|
fi
|
|
desktop
|
|
health
|
|
phone
|
|
ok "deployed"
|