#!/usr/bin/env bash set -euo pipefail PROVISION_TOOLS_DIR="${PROVISION_TOOLS_DIR:-provision-tools}" PROVISION_DOWNLOADS_DIR="${PROVISION_DOWNLOADS_DIR:-}" OTELCOL_VERSION="${OTELCOL_VERSION:-0.151.0}" PREPARE_OTELCOL="${PREPARE_OTELCOL:-${ENABLE_OTELCOL:-true}}" OTELCOL_DOWNLOAD_ROOT="${OTELCOL_DOWNLOAD_ROOT:-https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download}" OTELCOL_ARCHIVE_PATH="${OTELCOL_ARCHIVE_PATH:-}" SPACETIME_INSTALLER_URL="${SPACETIME_INSTALLER_URL:-https://install.spacetimedb.com}" SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT:-https://github.com/clockworklabs/SpacetimeDB/releases/latest/download}" SPACETIME_TARGET_HOST="${SPACETIME_TARGET_HOST:-x86_64-unknown-linux-gnu}" SPACETIME_ARCHIVE_PATH="${SPACETIME_ARCHIVE_PATH:-}" SPACETIME_INSTALLER_PATH="${SPACETIME_INSTALLER_PATH:-}" SPACETIME_UPDATE_INSTALLER_PATH="${SPACETIME_UPDATE_INSTALLER_PATH:-}" PROVISION_DOWNLOAD_PROXY="${PROVISION_DOWNLOAD_PROXY:-}" PROVISION_NO_PROXY="${PROVISION_NO_PROXY:-127.0.0.1,localhost}" PROVISION_REQUIRE_LOCAL_DOWNLOADS="${PROVISION_REQUIRE_LOCAL_DOWNLOADS:-false}" PROVISION_TOOLS_TMP_PARENT="${PROVISION_TOOLS_TMP_PARENT:-${WORKSPACE:-$(pwd)}/.tmp/server-provision-tools}" TMP_DIR_TO_CLEAN="" OTELCOL_SOURCE_DESCRIPTION="skipped" SPACETIME_SOURCE_DESCRIPTION="unset" cleanup_tmp_dir() { if [[ -n "${TMP_DIR_TO_CLEAN}" ]]; then rm -rf "${TMP_DIR_TO_CLEAN}" fi } require_cmd() { local name="$1" if ! command -v "${name}" >/dev/null 2>&1; then echo "[prepare-provision-tools] 缺少命令: ${name}" >&2 exit 1 fi } configure_download_proxy() { if [[ -z "${PROVISION_DOWNLOAD_PROXY}" ]]; then return fi export HTTP_PROXY="${PROVISION_DOWNLOAD_PROXY}" export HTTPS_PROXY="${PROVISION_DOWNLOAD_PROXY}" export ALL_PROXY="${PROVISION_DOWNLOAD_PROXY}" export http_proxy="${PROVISION_DOWNLOAD_PROXY}" export https_proxy="${PROVISION_DOWNLOAD_PROXY}" export all_proxy="${PROVISION_DOWNLOAD_PROXY}" export NO_PROXY="${PROVISION_NO_PROXY}" export no_proxy="${PROVISION_NO_PROXY}" echo "[prepare-provision-tools] 已配置下载代理: ${PROVISION_DOWNLOAD_PROXY%%://*}://***" } download_file() { local url="$1" local output="$2" if command -v curl >/dev/null 2>&1; then curl -fsSL --retry 3 --retry-delay 2 "${url}" -o "${output}" elif command -v wget >/dev/null 2>&1; then wget -O "${output}" "${url}" else echo "[prepare-provision-tools] 需要 curl 或 wget 下载: ${url}" >&2 exit 1 fi } validate_relative_dir() { local label="$1" local path="$2" if [[ -z "${path}" ]]; then return fi if [[ "${path}" == /* || "${path}" == *..* || "${path}" == "." ]]; then echo "[prepare-provision-tools] ${label} 只能是工作区内的相对路径: ${path}" >&2 exit 1 fi } make_spacetime_wrapper() { local target="$1" cat >"${target}" <<'EOF' #!/usr/bin/env sh set -eu SELF_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) exec "$SELF_DIR/bin/current/spacetimedb-cli" "$@" EOF chmod 0755 "${target}" } prepare_otelcol() { local tmp_dir="$1" local archive="${tmp_dir}/otelcol-contrib.tar.gz" local extract_dir="${tmp_dir}/otelcol-contrib" local url="${OTELCOL_DOWNLOAD_ROOT}/v${OTELCOL_VERSION}/otelcol-contrib_${OTELCOL_VERSION}_linux_amd64.tar.gz" local downloaded_archive="${PROVISION_DOWNLOADS_DIR}/otelcol-contrib_${OTELCOL_VERSION}_linux_amd64.tar.gz" local source_archive="" local target="${PROVISION_TOOLS_DIR}/otelcol-contrib" require_cmd tar if [[ -n "${OTELCOL_ARCHIVE_PATH}" && -f "${OTELCOL_ARCHIVE_PATH}" ]]; then source_archive="${OTELCOL_ARCHIVE_PATH}" elif [[ -n "${PROVISION_DOWNLOADS_DIR}" && -f "${downloaded_archive}" ]]; then source_archive="${downloaded_archive}" fi if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_archive}" ]]; then echo "[prepare-provision-tools] 要求使用 Windows 已下载的 otelcol-contrib 包,但未找到: ${downloaded_archive}" >&2 exit 1 fi mkdir -p "${extract_dir}" if [[ -n "${source_archive}" ]]; then echo "[prepare-provision-tools] 使用已下载的 otelcol-contrib 包: ${source_archive}" cp "${source_archive}" "${archive}" OTELCOL_SOURCE_DESCRIPTION="local ${source_archive}" else echo "[prepare-provision-tools] 下载 otelcol-contrib: ${url}" download_file "${url}" "${archive}" OTELCOL_SOURCE_DESCRIPTION="download ${url}" fi tar -xzf "${archive}" -C "${extract_dir}" if [[ ! -x "${extract_dir}/otelcol-contrib" ]]; then echo "[prepare-provision-tools] otelcol-contrib 包中缺少可执行文件。" >&2 exit 1 fi install -m 0755 "${extract_dir}/otelcol-contrib" "${target}" "${target}" --version >/dev/null } prepare_spacetime() { local tmp_dir="$1" local install_root="${tmp_dir}/spacetime-root" local target_dir="${PROVISION_TOOLS_DIR}/spacetime" local archive_name="spacetime-${SPACETIME_TARGET_HOST}.tar.gz" local downloaded_archive="${PROVISION_DOWNLOADS_DIR}/${archive_name}" local source_archive="" local update_name="spacetimedb-update-${SPACETIME_TARGET_HOST}" local downloaded_update="${PROVISION_DOWNLOADS_DIR}/${update_name}" local source_update="" local prepared_update="${tmp_dir}/spacetimedb-update" local downloaded_installer="${PROVISION_DOWNLOADS_DIR}/spacetime-install.sh" local source_installer="" mkdir -p "${install_root}" if [[ -n "${SPACETIME_ARCHIVE_PATH}" && -f "${SPACETIME_ARCHIVE_PATH}" ]]; then source_archive="${SPACETIME_ARCHIVE_PATH}" elif [[ -n "${PROVISION_DOWNLOADS_DIR}" && -f "${downloaded_archive}" ]]; then source_archive="${downloaded_archive}" fi if [[ -n "${source_archive}" ]]; then echo "[prepare-provision-tools] 使用已下载的 SpacetimeDB release tarball: ${source_archive}" mkdir -p "${install_root}/bin/current" tar -xzf "${source_archive}" -C "${install_root}/bin/current" chmod 0755 "${install_root}/bin/current/spacetimedb-cli" "${install_root}/bin/current/spacetimedb-standalone" SPACETIME_SOURCE_DESCRIPTION="local archive ${source_archive}" elif [[ -n "${SPACETIME_UPDATE_INSTALLER_PATH}" && -f "${SPACETIME_UPDATE_INSTALLER_PATH}" ]]; then source_update="${SPACETIME_UPDATE_INSTALLER_PATH}" elif [[ -n "${PROVISION_DOWNLOADS_DIR}" && -f "${downloaded_update}" ]]; then source_update="${downloaded_update}" fi if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_archive}" ]]; then echo "[prepare-provision-tools] 要求使用 Windows 已下载的 SpacetimeDB release tarball,但未找到: ${downloaded_archive}" >&2 exit 1 fi if [[ -n "${source_archive}" ]]; then : elif [[ -n "${source_update}" ]]; then echo "[prepare-provision-tools] 使用已下载的 SpacetimeDB Linux update installer: ${source_update}" cp "${source_update}" "${prepared_update}" chmod 0755 "${prepared_update}" TMPDIR="${tmp_dir}" "${prepared_update}" --root-dir "${install_root}" -y SPACETIME_SOURCE_DESCRIPTION="local update ${source_update}" else if [[ -n "${SPACETIME_INSTALLER_PATH}" && -f "${SPACETIME_INSTALLER_PATH}" ]]; then source_installer="${SPACETIME_INSTALLER_PATH}" elif [[ -n "${PROVISION_DOWNLOADS_DIR}" && -f "${downloaded_installer}" ]]; then source_installer="${downloaded_installer}" fi if [[ "${PROVISION_REQUIRE_LOCAL_DOWNLOADS}" == "true" && -z "${source_installer}" ]]; then echo "[prepare-provision-tools] 要求使用 Windows 已下载的 SpacetimeDB 官方安装器脚本,但未找到: ${downloaded_installer}" >&2 exit 1 elif [[ -n "${source_installer}" ]]; then echo "[prepare-provision-tools] 使用已下载的 SpacetimeDB 官方安装器脚本: ${source_installer}" cp "${source_installer}" "${tmp_dir}/spacetime-install.sh" else echo "[prepare-provision-tools] 下载 SpacetimeDB 官方安装器脚本: ${SPACETIME_INSTALLER_URL}" download_file "${SPACETIME_INSTALLER_URL}" "${tmp_dir}/spacetime-install.sh" fi chmod 0755 "${tmp_dir}/spacetime-install.sh" TMPDIR="${tmp_dir}" SPACETIME_DOWNLOAD_ROOT="${SPACETIME_DOWNLOAD_ROOT}" sh "${tmp_dir}/spacetime-install.sh" --root-dir "${install_root}" -y SPACETIME_SOURCE_DESCRIPTION="installer ${SPACETIME_INSTALLER_URL}; download root ${SPACETIME_DOWNLOAD_ROOT}" fi if [[ ! -x "${install_root}/bin/current/spacetimedb-cli" ]]; then echo "[prepare-provision-tools] SpacetimeDB 安装结果缺少 bin/current/spacetimedb-cli。" >&2 exit 1 fi if [[ ! -x "${install_root}/bin/current/spacetimedb-standalone" ]]; then echo "[prepare-provision-tools] SpacetimeDB 安装结果缺少 bin/current/spacetimedb-standalone。" >&2 exit 1 fi mkdir -p "${target_dir}" cp -a "${install_root}/bin" "${target_dir}/bin" make_spacetime_wrapper "${target_dir}/spacetime" "${target_dir}/spacetime" --version >/dev/null } main() { local tmp_dir require_cmd chmod require_cmd cp require_cmd install require_cmd mktemp require_cmd rm require_cmd tar validate_relative_dir "PROVISION_TOOLS_DIR" "${PROVISION_TOOLS_DIR}" validate_relative_dir "PROVISION_DOWNLOADS_DIR" "${PROVISION_DOWNLOADS_DIR}" if [[ -n "${PROVISION_DOWNLOADS_DIR}" && "${PROVISION_DOWNLOADS_DIR%/}" == "${PROVISION_TOOLS_DIR%/}" ]]; then echo "[prepare-provision-tools] PROVISION_DOWNLOADS_DIR 不能等于 PROVISION_TOOLS_DIR,否则会被清理: ${PROVISION_DOWNLOADS_DIR}" >&2 exit 1 fi configure_download_proxy mkdir -p "${PROVISION_TOOLS_TMP_PARENT}" tmp_dir="$(mktemp -d "${PROVISION_TOOLS_TMP_PARENT%/}/run.XXXXXX")" TMP_DIR_TO_CLEAN="${tmp_dir}" trap cleanup_tmp_dir EXIT rm -rf "${PROVISION_TOOLS_DIR}" mkdir -p "${PROVISION_TOOLS_DIR}" if [[ "${PREPARE_OTELCOL}" == "true" ]]; then prepare_otelcol "${tmp_dir}" else echo "[prepare-provision-tools] PREPARE_OTELCOL=${PREPARE_OTELCOL},跳过 otelcol-contrib 工具包准备。" fi prepare_spacetime "${tmp_dir}" cat >"${PROVISION_TOOLS_DIR}/MANIFEST.txt" <