CaiWuXiTong/deploy/local-init.sh

242 lines
7.0 KiB
Bash
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.

#!/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 "====================================================="