242 lines
7.0 KiB
Bash
242 lines
7.0 KiB
Bash
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
cd "$(dirname "$0")/.."
|
||
|
||
compose_file="docker-compose.local.yml"
|
||
environment_file="runtime/.env"
|
||
credential_file="runtime/bootstrap-credentials.env"
|
||
app_image="jiangling_akaunting:local"
|
||
build_mode="auto"
|
||
|
||
for argument in "$@"; do
|
||
case "$argument" in
|
||
--build)
|
||
build_mode="build"
|
||
;;
|
||
--skip-build)
|
||
build_mode="skip"
|
||
;;
|
||
--help|-h)
|
||
echo "用法:bash deploy/local-init.sh [--build|--skip-build]"
|
||
echo " --build 强制重新构建本地开发镜像"
|
||
echo " --skip-build 只启动已有镜像;镜像不存在时停止"
|
||
exit 0
|
||
;;
|
||
*)
|
||
echo "错误:未知参数 $argument" >&2
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
read_env_value() {
|
||
local key="$1"
|
||
sed -n "s/^${key}=//p" "$environment_file" \
|
||
| tail -n 1 \
|
||
| tr -d '\r' \
|
||
| sed 's/^"//; s/"$//'
|
||
}
|
||
|
||
set_env_value() {
|
||
local key="$1"
|
||
local value="$2"
|
||
local temporary
|
||
temporary="${environment_file}.tmp.$$"
|
||
|
||
awk -v key="$key" -v value="$value" '
|
||
BEGIN { found = 0 }
|
||
index($0, key "=") == 1 {
|
||
print key "=" value
|
||
found = 1
|
||
next
|
||
}
|
||
{ print }
|
||
END {
|
||
if (!found) {
|
||
print key "=" value
|
||
}
|
||
}
|
||
' "$environment_file" > "$temporary"
|
||
|
||
cp "$temporary" "$environment_file"
|
||
rm -f "$temporary"
|
||
chmod 600 "$environment_file" 2>/dev/null || true
|
||
}
|
||
|
||
echo "==> 工作目录: $(pwd)"
|
||
|
||
if ! command -v docker >/dev/null 2>&1; then
|
||
echo "错误:未找到 Docker,请先启动 Docker Desktop。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if ! docker version >/dev/null 2>&1; then
|
||
echo "错误:Docker 尚未就绪,请先启动 Docker Desktop。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [ ! -f "$environment_file" ]; then
|
||
mkdir -p runtime
|
||
app_key="base64:$(head -c 32 /dev/urandom | base64 | tr -d '\r\n')"
|
||
|
||
cat > "$environment_file" <<EOF
|
||
APP_NAME=CaiWuXiTong
|
||
APP_ENV=local
|
||
APP_DEBUG=true
|
||
APP_URL=http://127.0.0.1:18088
|
||
APP_KEY=$app_key
|
||
APP_INSTALLED=false
|
||
APP_LOCALE=zh-CN
|
||
APP_FALLBACK_LOCALE=en-GB
|
||
APP_TIMEZONE=Asia/Shanghai
|
||
LOG_CHANNEL=stack
|
||
|
||
DB_CONNECTION=mysql
|
||
DB_HOST=mysql
|
||
DB_PORT=3306
|
||
DB_DATABASE=akaunting
|
||
DB_USERNAME=akaunting
|
||
DB_PASSWORD=akaunting123
|
||
DB_PREFIX=ak_
|
||
|
||
CACHE_DRIVER=file
|
||
SESSION_DRIVER=file
|
||
QUEUE_CONNECTION=sync
|
||
|
||
SYSTEM_DATABASE_MODE=bootstrap
|
||
UPSTREAM_STORED_CONFIG_ENABLED=false
|
||
UPSTREAM_LOCAL_CONFIG_ENABLED=false
|
||
EOF
|
||
|
||
chmod 600 "$environment_file" 2>/dev/null || true
|
||
echo "==> 已生成本机私有 runtime/.env(不会提交到 Git)。"
|
||
fi
|
||
|
||
image_exists=0
|
||
if docker image inspect "$app_image" >/dev/null 2>&1; then
|
||
image_exists=1
|
||
fi
|
||
|
||
if [ "$build_mode" = "build" ] || { [ "$build_mode" = "auto" ] && [ "$image_exists" -eq 0 ]; }; then
|
||
echo "==> [1/5] 构建本地开发镜像..."
|
||
docker compose -f "$compose_file" build app
|
||
elif [ "$build_mode" = "skip" ] && [ "$image_exists" -eq 0 ]; then
|
||
echo "错误:本地开发镜像不存在,不能使用 --skip-build。" >&2
|
||
exit 1
|
||
else
|
||
echo "==> [1/5] 复用现有本地开发镜像。需要更新依赖时请使用 --build。"
|
||
fi
|
||
|
||
echo "==> [2/5] 启动本地容器..."
|
||
docker compose -f "$compose_file" up -d --no-build
|
||
|
||
echo "==> [3/5] 等待临时 MySQL 就绪..."
|
||
mysql_ready=0
|
||
for i in $(seq 1 60); do
|
||
if docker compose -f "$compose_file" exec -T mysql \
|
||
mysqladmin ping -h 127.0.0.1 -u akaunting -pakaunting123 >/dev/null 2>&1; then
|
||
mysql_ready=1
|
||
echo " 临时 MySQL 已就绪。"
|
||
break
|
||
fi
|
||
|
||
echo " 等待中... ($i/60)"
|
||
sleep 2
|
||
done
|
||
|
||
if [ "$mysql_ready" -ne 1 ]; then
|
||
echo "错误:临时 MySQL 未能在规定时间内启动。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
db_host="$(read_env_value DB_HOST)"
|
||
app_installed="$(read_env_value APP_INSTALLED | tr '[:upper:]' '[:lower:]')"
|
||
|
||
if [ "$db_host" = "mysql" ]; then
|
||
set_env_value SYSTEM_DATABASE_MODE bootstrap
|
||
set_env_value UPSTREAM_STORED_CONFIG_ENABLED false
|
||
set_env_value UPSTREAM_LOCAL_CONFIG_ENABLED false
|
||
fi
|
||
|
||
if [ "$db_host" = "mysql" ] && [ "$app_installed" != "true" ] && [ "$app_installed" != "1" ]; then
|
||
echo "==> [4/5] 初始化仅供首次登录使用的本机引导库..."
|
||
|
||
if [ ! -f "$credential_file" ]; then
|
||
umask 077
|
||
bootstrap_password="Cw!$(od -An -N16 -tx1 /dev/urandom | tr -d ' \r\n')"
|
||
cat > "$credential_file" <<EOF
|
||
BOOTSTRAP_EMAIL=local-bootstrap@caiwu.test
|
||
BOOTSTRAP_PASSWORD=$bootstrap_password
|
||
EOF
|
||
chmod 600 "$credential_file" 2>/dev/null || true
|
||
fi
|
||
|
||
# 文件由脚本生成,值只包含固定邮箱和受限字符集的随机密码。
|
||
# shellcheck disable=SC1090
|
||
source "$credential_file"
|
||
|
||
docker compose -f "$compose_file" exec -T -u www-data app \
|
||
php artisan install --no-interaction \
|
||
--db-host=mysql \
|
||
--db-port=3306 \
|
||
--db-name=akaunting \
|
||
--db-username=akaunting \
|
||
--db-password=akaunting123 \
|
||
--db-prefix=ak_ \
|
||
--company-name="本地引导环境" \
|
||
--company-email="$BOOTSTRAP_EMAIL" \
|
||
--admin-email="$BOOTSTRAP_EMAIL" \
|
||
--admin-password="$BOOTSTRAP_PASSWORD" \
|
||
--locale=zh-CN
|
||
else
|
||
echo "==> [4/5] 当前环境已经初始化,跳过本机引导库安装。"
|
||
fi
|
||
|
||
echo "==> 自动检查本机临时引导库结构..."
|
||
docker compose -f "$compose_file" exec -T -u www-data app php artisan optimize:clear >/dev/null
|
||
docker compose -f "$compose_file" exec -T -u www-data app \
|
||
php artisan local-bootstrap:update --no-ansi
|
||
|
||
echo "==> [5/5] 验证安装状态、数据库和管理员权限..."
|
||
|
||
ready=0
|
||
for i in $(seq 1 30); do
|
||
if docker compose -f "$compose_file" exec -T -u www-data app php artisan app:ready --quiet; then
|
||
ready=1
|
||
break
|
||
fi
|
||
|
||
sleep 2
|
||
done
|
||
|
||
if [ "$ready" -ne 1 ]; then
|
||
echo "错误:应用未通过就绪检查,请运行以下命令查看日志:" >&2
|
||
echo "docker compose -f $compose_file logs --tail=100 app" >&2
|
||
exit 1
|
||
fi
|
||
|
||
http_code="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 15 \
|
||
http://127.0.0.1:18088/auth/login || true)"
|
||
|
||
if [ "$http_code" != "200" ]; then
|
||
echo "错误:登录页返回 HTTP ${http_code:-000}。" >&2
|
||
exit 1
|
||
fi
|
||
|
||
echo ""
|
||
echo "====================================================="
|
||
echo "本地测试环境已就绪:http://127.0.0.1:18088"
|
||
|
||
db_host="$(read_env_value DB_HOST)"
|
||
if [ "$db_host" = "mysql" ]; then
|
||
echo "临时登录凭据保存在本机私有文件:$credential_file"
|
||
echo "请自行打开该文件,不要把内容提交到 Git、聊天或日志。"
|
||
echo ""
|
||
echo "下一步:登录后打开“系统设置 → 数据库管理 → 系统数据库”,"
|
||
echo "点击“连接”,只填写负责人提供的系统数据库密码。"
|
||
else
|
||
echo "已连接团队共享系统数据库,请使用其中属于自己的正式账号登录。"
|
||
fi
|
||
echo "====================================================="
|