Files
Jayway Liu 05f2ee416e
Verify / verify (push) Successful in 5m1s
fix(dev): dev_up 以数据库为准幂等初始化管理员
此前凭据文件存在但数据库重建时会跳过 init_local.py,导致本地无
admin 无法登录;改为每次启动都执行(脚本本身按数据库幂等)。
2026-09-26 20:45:22 +08:00

124 lines
3.6 KiB
Bash
Executable File
Raw Permalink 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.
#!/usr/bin/env bash
# 一键启动本地开发环境:迁移 → 初始化管理员 → 构建前端 → 启动 API+worker → 打开页面。
# 默认使用 SQLite 轻量开发库(var/db.sqlite3);设置 DATABASE_URL 则使用 PostgreSQL。
# Ctrl-C 或 --stop 停止本脚本启动的进程。
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$ROOT"
PORT="${PORT:-8000}"
SERVER_PID_FILE="var/dev-server.pid"
WORKER_PID_FILE="var/dev-worker.pid"
SERVER_LOG="var/dev-server.log"
WORKER_LOG="var/dev-worker.log"
die() { echo "错误:$*" >&2; exit 1; }
detect_python() {
if [ -x ".venv/bin/python" ]; then
PY=".venv/bin/python"
elif command -v uv >/dev/null 2>&1; then
PY="uv run python"
else
die "未找到 .venv/bin/python 或 uv,请先安装依赖(uv sync)"
fi
}
read_pidfile() { [ -f "$1" ] && cat "$1" || true; }
stop_all() {
local stopped=0 pid
for file in "$SERVER_PID_FILE" "$WORKER_PID_FILE"; do
pid="$(read_pidfile "$file")"
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
kill "$pid" 2>/dev/null || true
stopped=1
fi
rm -f "$file"
done
[ "$stopped" = 1 ] && echo "已停止本地开发服务" || echo "没有正在运行的开发服务"
}
health_ok() { curl -fsS --max-time 2 "http://127.0.0.1:$PORT/api/health" >/dev/null 2>&1; }
open_page() {
local url="http://127.0.0.1:$PORT/"
if command -v open >/dev/null 2>&1; then open "$url"
elif command -v xdg-open >/dev/null 2>&1; then xdg-open "$url" >/dev/null 2>&1 || true
fi
}
case "${1:-}" in
--stop)
stop_all
exit 0
;;
"" | --no-open) ;;
*) die "未知参数:$1(支持 --stop / --no-open)" ;;
esac
detect_python
mkdir -p var
if health_ok; then
echo "已在 $PORT 端口运行,直接打开页面"
[ "${1:-}" != "--no-open" ] && open_page
exit 0
fi
if [ -z "${DATABASE_URL:-}" ]; then
echo "未设置 DATABASE_URL,使用 SQLite 轻量开发库 var/db.sqlite3(仅限页面测试与开发回归)"
fi
echo "执行数据库迁移…"
$PY manage.py migrate --no-input >/dev/null
# init_local.py 以数据库为准幂等执行:缺 admin 时创建并写凭据文件,已存在则跳过
echo "初始化本地管理员(已存在则跳过)…"
PYTHONPATH="$ROOT" $PY scripts/init_local.py
if [ ! -d frontend/dist ]; then
echo "构建前端(首次)…"
npm run build >/dev/null
fi
echo "启动 worker(日志 ${WORKER_LOG})…"
nohup $PY manage.py import_worker >"$WORKER_LOG" 2>&1 &
echo $! >"$WORKER_PID_FILE"
echo "启动 API 服务…"
nohup $PY manage.py runserver "127.0.0.1:$PORT" --noreload >"$SERVER_LOG" 2>&1 &
echo $! >"$SERVER_PID_FILE"
cleanup() {
stop_all >/dev/null 2>&1 || true
}
trap cleanup INT TERM
for _ in $(seq 1 30); do
if health_ok; then
break
fi
if [ -n "$(read_pidfile "$SERVER_PID_FILE")" ] && ! kill -0 "$(read_pidfile "$SERVER_PID_FILE")" 2>/dev/null; then
tail -20 "$SERVER_LOG" >&2
die "API 服务启动失败(完整日志:${SERVER_LOG})"
fi
sleep 1
done
health_ok || { tail -20 "$SERVER_LOG" >&2; die "健康检查超时(日志:${SERVER_LOG})"; }
echo
echo "本地开发环境已就绪:http://127.0.0.1:$PORT"
[ -f var/local-access.txt ] && echo "登录凭据:var/local-access.txt(用户名 admin,权限 0600)"
if [ -z "${DATABASE_URL:-}" ]; then
echo "提示:当前为 SQLite 轻量模式;高精度金额聚合与生产验收请按 README 配置 PostgreSQL。"
fi
echo "日志:${SERVER_LOG} / ${WORKER_LOG} · Ctrl-C 或 scripts/dev_up.sh --stop 停止"
echo
[ "${1:-}" != "--no-open" ] && open_page
wait "$(read_pidfile "$SERVER_PID_FILE")" || true
cleanup