#!/usr/bin/env bash
set -Eeuo pipefail
BRANCH="${1:-main}"
MODE="${2:-bootstrap}"
REPO_ROOT="${SANPO_DOCS_REPO:-/home/ubuntu/sanporobot/robot}"
SITE_ROOT="${SANPO_DOCS_SITE_ROOT:-/var/www/docs.sanporobot.com}"
WORKTREE_ROOT="${SANPO_DOCS_WORKTREE_ROOT:-/home/ubuntu/sanporobot/docs-worktrees}"
VENV_DIR="${SANPO_DOCS_VENV:-/home/ubuntu/sanporobot/robot/.venv}"
LOCK_FILE="${SANPO_DOCS_LOCK:-/tmp/sanpo-docs-publish.lock}"
V4_MODE="${SANPO_DOCS_V4_MODE:-preserve}"
V6_MODE="${SANPO_DOCS_V6_MODE:-preserve}"
if [[ "${BRANCH}" != "main" && "${BRANCH}" != "unified-main" ]]; then
echo "Usage: $0 [main|unified-main]" >&2
exit 2
fi
if [[ "${V4_MODE}" != "preserve" && "${V4_MODE}" != "rebuild" ]]; then
echo "SANPO_DOCS_V4_MODE must be preserve or rebuild." >&2
exit 2
fi
if [[ "${V6_MODE}" != "preserve" && "${V6_MODE}" != "rebuild" ]]; then
echo "SANPO_DOCS_V6_MODE must be preserve or rebuild." >&2
exit 2
fi
if [[ "${MODE}" != "prepared" && "${SANPO_DOCS_LOCK_HELD:-0}" != "1" ]]; then
exec 9>"${LOCK_FILE}"
if ! flock -n 9; then
echo "Another documentation deployment is already running." >&2
exit 1
fi
fi
cleanup_worktree() {
if [[ -n "${TEMP_WORKTREE:-}" ]] && [[ -d "${TEMP_WORKTREE}" ]]; then
git -C "${REPO_ROOT}" worktree remove --force "${TEMP_WORKTREE}" >/dev/null 2>&1 || true
fi
}
if [[ "${MODE}" != "prepared" ]]; then
if [[ ! -d "${REPO_ROOT}/.git" ]]; then
echo "Git repository not found: ${REPO_ROOT}" >&2
exit 1
fi
if [[ -n "$(git -C "${REPO_ROOT}" status --porcelain --untracked-files=no)" ]]; then
echo "Tracked changes exist in ${REPO_ROOT}; deployment aborted." >&2
exit 1
fi
echo "Fetching origin/${BRANCH} ..."
git -C "${REPO_ROOT}" fetch --prune origin "${BRANCH}"
COMMIT_SHA="$(git -C "${REPO_ROOT}" rev-parse "origin/${BRANCH}")"
mkdir -p "${WORKTREE_ROOT}"
TEMP_WORKTREE="${WORKTREE_ROOT}/publish-${BRANCH}-$$"
trap cleanup_worktree EXIT
git -C "${REPO_ROOT}" worktree add --detach "${TEMP_WORKTREE}" "${COMMIT_SHA}" >/dev/null
SANPO_DOCS_REPO="${REPO_ROOT}" \
SANPO_DOCS_SITE_ROOT="${SITE_ROOT}" \
SANPO_DOCS_WORKTREE_ROOT="${WORKTREE_ROOT}" \
SANPO_DOCS_VENV="${VENV_DIR}" \
SANPO_DOCS_LOCK="${LOCK_FILE}" \
SANPO_DOCS_V4_MODE="${V4_MODE}" \
SANPO_DOCS_V6_MODE="${V6_MODE}" \
bash "${TEMP_WORKTREE}/scripts/docs/publish-server.sh" "${BRANCH}" prepared
exit $?
fi
SOURCE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
COMMIT_SHA="$(git -C "${SOURCE_ROOT}" rev-parse HEAD)"
SHORT_SHA="${COMMIT_SHA:0:12}"
RELEASE_ID="$(date +%Y%m%d-%H%M%S)-${SHORT_SHA}"
if [[ "${BRANCH}" == "main" ]]; then
RELEASE_PARENT="${SITE_ROOT}/releases"
LINK_NAME="${SITE_ROOT}/current"
else
RELEASE_PARENT="${SITE_ROOT}/previews"
LINK_NAME="${SITE_ROOT}/preview-current"
fi
RELEASE_DIR="${RELEASE_PARENT}/${RELEASE_ID}"
mkdir -p "${RELEASE_PARENT}" "${RELEASE_DIR}"
PUBLISH_SUCCEEDED=0
cleanup_release() {
if [[ "${PUBLISH_SUCCEEDED}" != "1" ]] && [[ "${RELEASE_DIR}" == "${RELEASE_PARENT}/"* ]]; then
rm -rf -- "${RELEASE_DIR}"
fi
}
trap cleanup_release EXIT
if [[ -d "${SITE_ROOT}/current/v3" ]]; then
V3_SOURCE="${SITE_ROOT}/current/v3"
elif [[ -d "${REPO_ROOT}/docs_versions/v3" ]]; then
V3_SOURCE="${REPO_ROOT}/docs_versions/v3"
else
echo "Existing V3 static documentation was not found; deployment aborted." >&2
rmdir "${RELEASE_DIR}" 2>/dev/null || true
exit 1
fi
if [[ -d "${SITE_ROOT}/current/v4" ]]; then
V4_SOURCE="${SITE_ROOT}/current/v4"
elif [[ -d "${REPO_ROOT}/docs_versions/v4" ]]; then
V4_SOURCE="${REPO_ROOT}/docs_versions/v4"
else
echo "Existing V4 static documentation was not found; deployment aborted." >&2
rmdir "${RELEASE_DIR}" 2>/dev/null || true
exit 1
fi
if [[ -d "${SITE_ROOT}/current/v6" ]]; then
V6_SOURCE="${SITE_ROOT}/current/v6"
elif [[ -d "${REPO_ROOT}/docs_versions/v6" ]]; then
V6_SOURCE="${REPO_ROOT}/docs_versions/v6"
else
echo "Existing V6 static documentation was not found; deployment aborted." >&2
rmdir "${RELEASE_DIR}" 2>/dev/null || true
exit 1
fi
PYTHON_BIN="${VENV_DIR}/bin/python"
if [[ ! -x "${PYTHON_BIN}" ]]; then
echo "Creating documentation virtual environment: ${VENV_DIR}"
python3 -m venv "${VENV_DIR}"
fi
if ! "${PYTHON_BIN}" -c "import myst_parser, sphinx, sphinx_rtd_theme" >/dev/null 2>&1; then
"${VENV_DIR}/bin/python" -m pip install \
-r "${SOURCE_ROOT}/products/spine/v8/docs/requirements.txt"
fi
echo "Building ${BRANCH}@${SHORT_SHA} ..."
SANPO_DOCS_PYTHON="${PYTHON_BIN}" \
SANPO_DOCS_V3_SOURCE="${V3_SOURCE}" \
SANPO_DOCS_V4_SOURCE="${V4_SOURCE}" \
SANPO_DOCS_V6_SOURCE="${V6_SOURCE}" \
SANPO_DOCS_V4_MODE="${V4_MODE}" \
SANPO_DOCS_V6_MODE="${V6_MODE}" \
SANPO_DOCS_BRANCH="${BRANCH}" \
SANPO_DOCS_COMMIT="${COMMIT_SHA}" \
bash "${SOURCE_ROOT}/scripts/docs/build-docs.sh" "${RELEASE_DIR}"
if [[ "${V4_MODE}" == "rebuild" ]]; then
echo "V4 intentionally rebuilt."
else
echo "V4 preserved; only the shared version selector was normalized."
fi
if [[ "${V6_MODE}" == "rebuild" ]]; then
echo "V6 intentionally rebuilt."
else
echo "V6 preserved; only the shared version selector was normalized."
fi
NEXT_LINK="${LINK_NAME}.next"
ln -sfn "${RELEASE_DIR}" "${NEXT_LINK}"
mv -Tf "${NEXT_LINK}" "${LINK_NAME}"
PUBLISH_SUCCEEDED=1
echo "Published ${BRANCH}@${SHORT_SHA}"
echo "Release: ${RELEASE_DIR}"
echo "Active link: ${LINK_NAME}"