LazyBoy2/Makefile

250 lines
6.2 KiB
Makefile
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Local process control for LazyBoy.
# make build cargo + production web UI (web/dist)
# make box Docker computer image (lazyboy-box:local)
# make start rebuild, then API :8787 + Vite :5173
# make restart stop, build, start
# make stop
.DEFAULT_GOAL := help
ROOT := $(abspath $(dir $(lastword $(MAKEFILE_LIST))))
RUNDIR := $(ROOT)/.run
BIN := $(ROOT)/target/debug/lazyboy
WEBDIR := $(ROOT)/web
HOST ?= 0.0.0.0
PORT_API ?= 8787
PORT_WEB ?= 5173
PID_SERVE := $(RUNDIR)/serve.pid
PID_WEB := $(RUNDIR)/web.pid
LOG_SERVE := $(RUNDIR)/serve.log
LOG_WEB := $(RUNDIR)/web.log
.PHONY: help build build-bin build-ui box start stop restart status logs prepare-ui start-serve start-web stop-serve stop-web
# Shared POSIX helpers. Sourced by each recipe.
define CTL
alive() {
pidfile="$$1"
[ -f "$$pidfile" ] || return 1
pid=$$(cat "$$pidfile")
[ -n "$$pid" ] && kill -0 "$$pid" 2>/dev/null
}
kill_tree() {
pid="$$1"
[ -n "$$pid" ] || return 0
for child in $$(pgrep -P "$$pid" 2>/dev/null); do
kill_tree "$$child"
done
kill -TERM "$$pid" 2>/dev/null || true
}
kill_tree_hard() {
pid="$$1"
[ -n "$$pid" ] || return 0
for child in $$(pgrep -P "$$pid" 2>/dev/null); do
kill_tree_hard "$$child"
done
kill -KILL "$$pid" 2>/dev/null || true
}
free_port() {
port="$$1"
extra=$$(lsof -nP -tiTCP:"$$port" -sTCP:LISTEN 2>/dev/null || true)
[ -n "$$extra" ] || return 0
echo "freeing :$$port ($$extra)"
kill -TERM $$extra 2>/dev/null || true
sleep 0.2
extra=$$(lsof -nP -tiTCP:"$$port" -sTCP:LISTEN 2>/dev/null || true)
[ -n "$$extra" ] && kill -KILL $$extra 2>/dev/null || true
}
stop_one() {
name="$$1"
pidfile="$$2"
port="$$3"
if alive "$$pidfile"; then
pid=$$(cat "$$pidfile")
echo "stopping $$name pid=$$pid"
kill_tree "$$pid"
n=0
while [ $$n -lt 15 ] && kill -0 "$$pid" 2>/dev/null; do
sleep 0.2
n=$$((n + 1))
done
kill_tree_hard "$$pid"
elif [ -f "$$pidfile" ]; then
echo "$$name not running (stale pidfile)"
else
echo "$$name not running"
fi
rm -f "$$pidfile"
free_port "$$port"
}
wait_alive() {
pidfile="$$1"
name="$$2"
log="$$3"
i=0
while [ $$i -lt 15 ]; do
if alive "$$pidfile"; then
return 0
fi
sleep 0.1
i=$$((i + 1))
done
echo "$$name exited immediately. Last log:"
tail -n 40 "$$log" 2>/dev/null || true
rm -f "$$pidfile"
return 1
}
wait_listen() {
pidfile="$$1"
port="$$2"
name="$$3"
log="$$4"
i=0
while [ $$i -lt 50 ]; do
if lsof -nP -iTCP:"$$port" -sTCP:LISTEN >/dev/null 2>&1; then
return 0
fi
if [ -f "$$pidfile" ]; then
pid=$$(cat "$$pidfile")
if [ -n "$$pid" ] && ! kill -0 "$$pid" 2>/dev/null; then
echo "$$name died before listening on :$$port. Last log:"
tail -n 40 "$$log" 2>/dev/null || true
rm -f "$$pidfile"
return 1
fi
fi
sleep 0.2
i=$$((i + 1))
done
echo "$$name did not listen on :$$port. Last log:"
tail -n 40 "$$log" 2>/dev/null || true
return 1
}
status_one() {
name="$$1"
pidfile="$$2"
port="$$3"
if alive "$$pidfile"; then
pid=$$(cat "$$pidfile")
listen=no
lsof -nP -iTCP:"$$port" -sTCP:LISTEN >/dev/null 2>&1 && listen=yes
echo "$$name running pid=$$pid :$$port listen=$$listen"
elif [ -f "$$pidfile" ]; then
echo "$$name stopped (stale pidfile)"
else
echo "$$name stopped"
fi
}
load_env() {
if [ -f "$(ROOT)/.env" ]; then
set -a
. "$(ROOT)/.env"
set +a
fi
}
endef
export CTL
help:
@echo "make build Compile API + production web UI (web/dist; phone uses :$(PORT_API))"
@echo "make box Build Docker computer image lazyboy-box:local (first time / after box/)"
@echo "make start Rebuild and start API (:$(PORT_API)) and frontend (:$(PORT_WEB))"
@echo "make stop Stop both"
@echo "make restart Stop, rebuild, start"
@echo "make status Show PIDs and ports"
@echo "make logs Tail both logs (Ctrl-C to leave)"
build: build-bin build-ui
@echo "built $(BIN) and $(WEBDIR)/dist"
build-bin:
@echo "building lazyboy…"
@cargo build -p lazyboy
build-ui:
@if [ ! -d "$(WEBDIR)/node_modules" ]; then \
echo "npm install…"; \
(cd "$(WEBDIR)" && npm install) || exit 1; \
fi
@echo "building web UI…"
@(cd "$(WEBDIR)" && npm run build) || exit 1
box:
@echo "building computer image lazyboy-box:local…"
@bash "$(ROOT)/box/build.sh"
start: build
@$(MAKE) start-serve
@$(MAKE) start-web
@echo
@echo "API http://127.0.0.1:$(PORT_API)"
@echo "UI http://127.0.0.1:$(PORT_WEB)"
@lan=$$(awk '/手機同一個 Wi-Fi/ {sub("http://", "", $$NF); sub(/:[0-9]+$$/, "", $$NF); print $$NF; exit}' "$(LOG_SERVE)"); \
if [ -n "$$lan" ]; then \
echo "Phone http://$$lan:$(PORT_API)"; \
fi
restart: stop
@$(MAKE) start
stop: stop-web stop-serve
@echo "stopped"
status:
@eval "$$CTL"; \
status_one serve "$(PID_SERVE)" "$(PORT_API)"; \
status_one web "$(PID_WEB)" "$(PORT_WEB)"
logs:
@mkdir -p "$(RUNDIR)"
@touch "$(LOG_SERVE)" "$(LOG_WEB)"
@echo "=== serve $(LOG_SERVE) ==="
@echo "=== web $(LOG_WEB) ==="
@tail -f "$(LOG_SERVE)" "$(LOG_WEB)"
prepare-ui: build-ui
start-serve:
@mkdir -p "$(RUNDIR)"
@eval "$$CTL"; \
if alive "$(PID_SERVE)"; then \
echo "restarting serve with rebuilt binary"; \
stop_one serve "$(PID_SERVE)" "$(PORT_API)"; \
fi; \
load_env; \
LAZYBOY_WEB_HOST="$(HOST)" LAZYBOY_WEB_PORT="$(PORT_API)" nohup "$(BIN)" serve > "$(LOG_SERVE)" 2>&1 < /dev/null & echo $$! > "$(PID_SERVE)"; \
wait_alive "$(PID_SERVE)" serve "$(LOG_SERVE)" || exit 1; \
wait_listen "$(PID_SERVE)" "$(PORT_API)" serve "$(LOG_SERVE)" || exit 1; \
echo "started serve pid=$$(cat "$(PID_SERVE)") :$(PORT_API) log=$(LOG_SERVE)"
start-web:
@mkdir -p "$(RUNDIR)"
@eval "$$CTL"; \
if alive "$(PID_WEB)"; then \
stop_one web "$(PID_WEB)" "$(PORT_WEB)"; \
fi; \
if [ ! -d "$(WEBDIR)/node_modules" ]; then \
echo "npm install…"; \
(cd "$(WEBDIR)" && npm install) || exit 1; \
fi; \
LAZYBOY_WEB_PORT="$(PORT_API)" nohup npm --prefix "$(WEBDIR)" run dev -- --host "$(HOST)" --port "$(PORT_WEB)" > "$(LOG_WEB)" 2>&1 < /dev/null & echo $$! > "$(PID_WEB)"; \
wait_alive "$(PID_WEB)" web "$(LOG_WEB)" || exit 1; \
wait_listen "$(PID_WEB)" "$(PORT_WEB)" web "$(LOG_WEB)" || exit 1; \
echo "started web pid=$$(cat "$(PID_WEB)") :$(PORT_WEB) log=$(LOG_WEB)"
stop-serve:
@eval "$$CTL"; stop_one serve "$(PID_SERVE)" "$(PORT_API)"
stop-web:
@eval "$$CTL"; stop_one web "$(PID_WEB)" "$(PORT_WEB)"