196 lines
5.4 KiB
Bash
196 lines
5.4 KiB
Bash
#!/usr/bin/env bash
|
||
|
||
set -euo pipefail
|
||
|
||
usage() {
|
||
cat <<'EOF'
|
||
用法:
|
||
./scripts/deploy/production-stdb-publish.sh --source-dir build/<version> --database <database> [--server-url http://127.0.0.1:3101] [--server local] [--root-dir /stdb] [--run-as-user spacetimedb] [--clear-database]
|
||
|
||
说明:
|
||
进入维护模式,校验 spacetime_module.wasm.sha256,并在生产实例本机执行 spacetime publish。
|
||
默认使用 http://127.0.0.1:3101,避免与部署机本机 Git/Web 服务的 3000 端口冲突。
|
||
默认使用 /stdb 作为 spacetime CLI root-dir,并以 spacetimedb 用户发布,避免 root CLI 身份污染自托管实例。
|
||
发布时固定追加 --no-config,只使用显式参数,避免工作区或用户目录里的 spacetime 配置干扰目标。
|
||
失败时保留维护模式。
|
||
EOF
|
||
}
|
||
|
||
require_argument() {
|
||
local value="$1"
|
||
local label="$2"
|
||
|
||
if [[ -z "${value}" ]]; then
|
||
echo "[production-stdb-publish] 缺少参数: ${label}" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
validate_spacetime_database_name() {
|
||
local database="$1"
|
||
|
||
if [[ ! "${database}" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
||
echo "[production-stdb-publish] --database 必须匹配 ^[a-z0-9]+(-[a-z0-9]+)*$: ${database}" >&2
|
||
exit 1
|
||
fi
|
||
}
|
||
|
||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||
SOURCE_DIR=""
|
||
DATABASE=""
|
||
SERVER_ALIAS="local"
|
||
SERVER_URL="http://127.0.0.1:3101"
|
||
SPACETIME_ROOT_DIR="/stdb"
|
||
RUN_AS_USER="spacetimedb"
|
||
CLEAR_DATABASE=0
|
||
DEPLOY_COMPLETED=0
|
||
PUBLISH_TMP_DIR=""
|
||
|
||
while [[ $# -gt 0 ]]; do
|
||
case "$1" in
|
||
-h|--help)
|
||
usage
|
||
exit 0
|
||
;;
|
||
--source-dir)
|
||
SOURCE_DIR="${2:?缺少 --source-dir 的值}"
|
||
shift 2
|
||
;;
|
||
--database)
|
||
DATABASE="${2:?缺少 --database 的值}"
|
||
shift 2
|
||
;;
|
||
--server)
|
||
SERVER_ALIAS="${2:?缺少 --server 的值}"
|
||
SERVER_URL=""
|
||
shift 2
|
||
;;
|
||
--server-url)
|
||
SERVER_URL="${2:?缺少 --server-url 的值}"
|
||
shift 2
|
||
;;
|
||
--root-dir)
|
||
SPACETIME_ROOT_DIR="${2:?缺少 --root-dir 的值}"
|
||
shift 2
|
||
;;
|
||
--run-as-user)
|
||
RUN_AS_USER="${2:?缺少 --run-as-user 的值}"
|
||
shift 2
|
||
;;
|
||
--clear-database)
|
||
CLEAR_DATABASE=1
|
||
shift
|
||
;;
|
||
*)
|
||
echo "[production-stdb-publish] 未知参数: $1" >&2
|
||
usage >&2
|
||
exit 1
|
||
;;
|
||
esac
|
||
done
|
||
|
||
require_argument "${SOURCE_DIR}" "--source-dir"
|
||
require_argument "${DATABASE}" "--database"
|
||
validate_spacetime_database_name "${DATABASE}"
|
||
|
||
if [[ ! "${SPACETIME_ROOT_DIR}" == /* || "${SPACETIME_ROOT_DIR}" == *".."* ]]; then
|
||
echo "[production-stdb-publish] --root-dir 必须是 Linux 绝对路径且不能包含 ..: ${SPACETIME_ROOT_DIR}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ -n "${RUN_AS_USER}" && ! "${RUN_AS_USER}" =~ ^[A-Za-z_][A-Za-z0-9_-]*$ ]]; then
|
||
echo "[production-stdb-publish] --run-as-user 只能是本机用户名: ${RUN_AS_USER}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
if [[ ! -d "${SOURCE_DIR}" ]]; then
|
||
echo "[production-stdb-publish] 发布目录不存在: ${SOURCE_DIR}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
SOURCE_DIR="$(cd "${SOURCE_DIR}" && pwd)"
|
||
|
||
if [[ ! -f "${SOURCE_DIR}/spacetime_module.wasm" || ! -f "${SOURCE_DIR}/spacetime_module.wasm.sha256" ]]; then
|
||
echo "[production-stdb-publish] 缺少 spacetime_module.wasm 或 spacetime_module.wasm.sha256: ${SOURCE_DIR}" >&2
|
||
exit 1
|
||
fi
|
||
|
||
on_exit() {
|
||
local exit_code=$?
|
||
if [[ -n "${PUBLISH_TMP_DIR}" && -d "${PUBLISH_TMP_DIR}" ]]; then
|
||
rm -rf "${PUBLISH_TMP_DIR}"
|
||
fi
|
||
if [[ "${exit_code}" -ne 0 && "${DEPLOY_COMPLETED}" -ne 1 ]]; then
|
||
echo "[production-stdb-publish] 发布失败,保持维护模式。" >&2
|
||
fi
|
||
exit "${exit_code}"
|
||
}
|
||
|
||
trap on_exit EXIT
|
||
|
||
"${SCRIPT_DIR}/maintenance-on.sh" "spacetime module publish ${DATABASE}"
|
||
|
||
echo "[production-stdb-publish] 校验 wasm"
|
||
(
|
||
cd "${SOURCE_DIR}"
|
||
sha256sum -c spacetime_module.wasm.sha256
|
||
)
|
||
|
||
PUBLISH_ARGS=(
|
||
--root-dir="${SPACETIME_ROOT_DIR}"
|
||
publish
|
||
"${DATABASE}"
|
||
--bin-path "${SOURCE_DIR}/spacetime_module.wasm"
|
||
--yes
|
||
--no-config
|
||
)
|
||
|
||
if [[ -n "${SERVER_URL}" ]]; then
|
||
PUBLISH_ARGS+=(--server "${SERVER_URL}")
|
||
else
|
||
PUBLISH_ARGS+=(--server "${SERVER_ALIAS}")
|
||
fi
|
||
|
||
if [[ "${CLEAR_DATABASE}" -eq 1 ]]; then
|
||
PUBLISH_ARGS+=(--clear-database)
|
||
fi
|
||
|
||
if [[ -n "${SERVER_URL}" ]]; then
|
||
echo "[production-stdb-publish] 发布 SpacetimeDB module: ${DATABASE} -> ${SERVER_URL}, root=${SPACETIME_ROOT_DIR}"
|
||
else
|
||
echo "[production-stdb-publish] 发布 SpacetimeDB module: ${DATABASE} -> ${SERVER_ALIAS}, root=${SPACETIME_ROOT_DIR}"
|
||
fi
|
||
|
||
if [[ -n "${RUN_AS_USER}" && "$(id -u)" -eq 0 ]]; then
|
||
if ! id "${RUN_AS_USER}" >/dev/null 2>&1; then
|
||
echo "[production-stdb-publish] 发布用户不存在: ${RUN_AS_USER}" >&2
|
||
exit 1
|
||
fi
|
||
PUBLISH_TMP_DIR="$(mktemp -d /tmp/genarrative-stdb-publish.XXXXXX)"
|
||
install -m 0644 "${SOURCE_DIR}/spacetime_module.wasm" "${PUBLISH_TMP_DIR}/spacetime_module.wasm"
|
||
chown -R "${RUN_AS_USER}:${RUN_AS_USER}" "${PUBLISH_TMP_DIR}"
|
||
PUBLISH_ARGS=(
|
||
--root-dir="${SPACETIME_ROOT_DIR}"
|
||
publish
|
||
"${DATABASE}"
|
||
--bin-path "${PUBLISH_TMP_DIR}/spacetime_module.wasm"
|
||
--yes
|
||
--no-config
|
||
)
|
||
if [[ -n "${SERVER_URL}" ]]; then
|
||
PUBLISH_ARGS+=(--server "${SERVER_URL}")
|
||
else
|
||
PUBLISH_ARGS+=(--server "${SERVER_ALIAS}")
|
||
fi
|
||
if [[ "${CLEAR_DATABASE}" -eq 1 ]]; then
|
||
PUBLISH_ARGS+=(--clear-database)
|
||
fi
|
||
runuser -u "${RUN_AS_USER}" -- spacetime "${PUBLISH_ARGS[@]}"
|
||
else
|
||
spacetime "${PUBLISH_ARGS[@]}"
|
||
fi
|
||
|
||
"${SCRIPT_DIR}/maintenance-off.sh"
|
||
DEPLOY_COMPLETED=1
|
||
echo "[production-stdb-publish] 完成"
|