173 lines
4.8 KiB
Bash
Executable File
173 lines
4.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
# 构建“一键部署包”(代码 + vendor + 加密数据库快照)
|
||
# 目标:下载压缩包 → 解压 → 运行 install.sh → 即可恢复到最新数据并可访问。
|
||
#
|
||
# 依赖:git / tar / gzip
|
||
# 可选:composer(仅当需要现装 vendor)
|
||
#
|
||
# 用法:
|
||
# bash scripts/build_oneclick_bundle.sh
|
||
# 输出:
|
||
# /app/working/dist/saasshop_bundle_<timestamp>.tar.gz
|
||
# /app/working/dist/saasshop_bundle_latest.tar.gz
|
||
|
||
REPO_DIR=$(cd "$(dirname "$0")/.." && pwd)
|
||
cd "$REPO_DIR"
|
||
|
||
DIST_DIR="/app/working/dist"
|
||
mkdir -p "$DIST_DIR"
|
||
|
||
DATA_REPO_SSH=""
|
||
if [[ -f /app/working.secret/saasshop_data_repo_ssh ]]; then
|
||
DATA_REPO_SSH=$(cat /app/working.secret/saasshop_data_repo_ssh)
|
||
fi
|
||
|
||
if [[ "$DATA_REPO_SSH" == "" ]]; then
|
||
echo "缺少数据仓地址:/app/working.secret/saasshop_data_repo_ssh"
|
||
exit 31
|
||
fi
|
||
|
||
STAMP=$(date +%Y%m%d_%H%M%S)
|
||
BUNDLE_ROOT=$(mktemp -d)
|
||
trap 'rm -rf "$BUNDLE_ROOT" || true' EXIT
|
||
|
||
APP_DIR="$BUNDLE_ROOT/saasshop"
|
||
mkdir -p "$APP_DIR"
|
||
|
||
# 1) 打包代码(不带 .git)
|
||
echo "[bundle] copying app files ..."
|
||
# 使用 tar 管道复制(比 cp -a 更容易排除)
|
||
tar \
|
||
--exclude=".git" \
|
||
--exclude="node_modules" \
|
||
--exclude="storage/logs" \
|
||
--exclude="storage/framework/cache" \
|
||
--exclude="storage/framework/sessions" \
|
||
--exclude="storage/framework/views" \
|
||
--exclude="storage/app/private" \
|
||
--exclude=".env" \
|
||
-cf - . | (cd "$APP_DIR" && tar -xf -)
|
||
|
||
# 2) 确保 vendor 存在(无构建链/傻瓜部署,优先直接随包携带)
|
||
if [[ ! -d "$APP_DIR/vendor" ]]; then
|
||
echo "[bundle] vendor 不存在,尝试 composer install --no-dev ..."
|
||
if command -v composer >/dev/null 2>&1; then
|
||
(cd "$APP_DIR" && composer install --no-dev --prefer-dist --no-interaction)
|
||
else
|
||
echo "[bundle] composer 不存在且 vendor 缺失,无法构建傻瓜包"
|
||
exit 32
|
||
fi
|
||
fi
|
||
|
||
# 3) 拉取数据仓最新快照
|
||
echo "[bundle] fetching latest encrypted snapshot from data repo ..."
|
||
DATA_TMP="$BUNDLE_ROOT/data_repo"
|
||
git clone "$DATA_REPO_SSH" "$DATA_TMP" >/dev/null
|
||
|
||
if [[ ! -f "$DATA_TMP/snapshots/latest.sql.gz.enc" ]]; then
|
||
echo "数据仓缺少 snapshots/latest.sql.gz.enc"
|
||
exit 33
|
||
fi
|
||
|
||
mkdir -p "$APP_DIR/bundle/snapshots"
|
||
cp -f "$DATA_TMP/snapshots/latest.sql.gz.enc" "$APP_DIR/bundle/snapshots/latest.sql.gz.enc"
|
||
if [[ -f "$DATA_TMP/snapshots/manifest.json" ]]; then
|
||
cp -f "$DATA_TMP/snapshots/manifest.json" "$APP_DIR/bundle/snapshots/manifest.json"
|
||
fi
|
||
|
||
# 4) 写入 install.sh(真正一键入口)
|
||
cat > "$APP_DIR/install.sh" <<'EOF'
|
||
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
# SaaSShop 一键部署脚本(随 bundle 一起发放)
|
||
# 用法:
|
||
# export SAASSHOP_DB_SNAPSHOT_KEY='解密密钥'
|
||
# bash install.sh
|
||
#
|
||
# 你也可以先准备好 .env(推荐),脚本会优先读取项目根目录 .env。
|
||
|
||
APP_DIR=$(cd "$(dirname "$0")" && pwd)
|
||
cd "$APP_DIR"
|
||
|
||
if [[ ! -f .env ]]; then
|
||
if [[ -f .env.example ]]; then
|
||
cp .env.example .env
|
||
echo "[install] 已生成 .env(来自 .env.example),请按需修改 DB_* / APP_URL 等配置。"
|
||
else
|
||
echo "[install] 缺少 .env 与 .env.example,无法继续"
|
||
exit 41
|
||
fi
|
||
fi
|
||
|
||
# 读取 .env(仅用于 DB 连接)
|
||
set -a
|
||
# shellcheck disable=SC1091
|
||
source .env
|
||
set +a
|
||
|
||
DB_HOST=${DB_HOST:-127.0.0.1}
|
||
DB_PORT=${DB_PORT:-3306}
|
||
DB_DATABASE=${DB_DATABASE:-appdb}
|
||
DB_USERNAME=${DB_USERNAME:-appuser}
|
||
DB_PASSWORD=${DB_PASSWORD:-}
|
||
|
||
if [[ "${SAASSHOP_DB_SNAPSHOT_KEY:-}" == "" ]]; then
|
||
echo "[install] 缺少 SAASSHOP_DB_SNAPSHOT_KEY:无法解密并恢复完整数据。"
|
||
echo "[install] 请先:export SAASSHOP_DB_SNAPSHOT_KEY='...密钥...'"
|
||
exit 42
|
||
fi
|
||
|
||
# 权限准备
|
||
mkdir -p storage bootstrap/cache
|
||
chmod -R ug+rwX storage bootstrap/cache || true
|
||
|
||
# APP_KEY
|
||
if ! grep -q '^APP_KEY=' .env || [[ "${APP_KEY:-}" == "" ]]; then
|
||
echo "[install] 生成 APP_KEY ..."
|
||
php artisan key:generate --force
|
||
fi
|
||
|
||
echo "[install] 导入最新数据库快照 ..."
|
||
ENC_FILE="bundle/snapshots/latest.sql.gz.enc"
|
||
if [[ ! -f "$ENC_FILE" ]]; then
|
||
echo "[install] 缺少快照文件:$ENC_FILE"
|
||
exit 43
|
||
fi
|
||
|
||
TMP_DIR=$(mktemp -d)
|
||
trap 'rm -rf "$TMP_DIR" || true' EXIT
|
||
SQL_GZ="$TMP_DIR/latest.sql.gz"
|
||
|
||
openssl enc -d -aes-256-cbc -pbkdf2 \
|
||
-pass env:SAASSHOP_DB_SNAPSHOT_KEY \
|
||
-in "$ENC_FILE" -out "$SQL_GZ"
|
||
|
||
gzip -dc "$SQL_GZ" | mysql \
|
||
--host="$DB_HOST" --port="$DB_PORT" \
|
||
--user="$DB_USERNAME" --password="$DB_PASSWORD"
|
||
|
||
echo "[install] 清理缓存 ..."
|
||
php artisan optimize:clear
|
||
|
||
echo "[done] 部署完成。接下来:配置 nginx 指向 public/,即可访问。"
|
||
EOF
|
||
chmod +x "$APP_DIR/install.sh"
|
||
|
||
# 5) 打包
|
||
OUT_FILE="$DIST_DIR/saasshop_bundle_${STAMP}.tar.gz"
|
||
LATEST_FILE="$DIST_DIR/saasshop_bundle_latest.tar.gz"
|
||
|
||
echo "[bundle] creating tar.gz ..."
|
||
(
|
||
cd "$BUNDLE_ROOT"
|
||
tar -czf "$OUT_FILE" saasshop
|
||
)
|
||
|
||
cp -f "$OUT_FILE" "$LATEST_FILE"
|
||
|
||
echo "[bundle] output: $OUT_FILE"
|
||
echo "[bundle] latest: $LATEST_FILE"
|