Convert docs to sphinx
This commit is contained in:
471
tests/prepare.sh
Executable file
471
tests/prepare.sh
Executable file
@@ -0,0 +1,471 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -u
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
|
||||
VENV_DIR="${FFX_TEST_VENV_DIR:-${ROOT_DIR}/.venv}"
|
||||
VENV_BIN_DIR="${VENV_DIR}/bin"
|
||||
VENV_PYTHON="${VENV_BIN_DIR}/python"
|
||||
VENV_PIP="${VENV_BIN_DIR}/pip"
|
||||
|
||||
CHECK_ONLY=0
|
||||
READINESS_FAILURES=0
|
||||
INSTALL_FAILURES=0
|
||||
|
||||
MISSING_REQUIRED_SYSTEM=()
|
||||
|
||||
COLOR_RESET=""
|
||||
COLOR_GREEN=""
|
||||
COLOR_YELLOW=""
|
||||
COLOR_RED=""
|
||||
|
||||
if [ -t 1 ]; then
|
||||
COLOR_RESET="$(printf '\033[0m')"
|
||||
COLOR_GREEN="$(printf '\033[32m')"
|
||||
COLOR_YELLOW="$(printf '\033[33m')"
|
||||
COLOR_RED="$(printf '\033[31m')"
|
||||
fi
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
Usage: $(basename "$0") [--check] [--help]
|
||||
|
||||
Prepare the repo-local FFX test environment at:
|
||||
${VENV_DIR}
|
||||
|
||||
Actions:
|
||||
- verify or install required system commands for tests
|
||||
- create or reuse the repo-local test virtualenv
|
||||
- install this repository into the venv with Python test and docs extras
|
||||
|
||||
Options:
|
||||
--check Report readiness only. Do not create, install, or modify.
|
||||
--help Show this help text.
|
||||
|
||||
Environment overrides:
|
||||
FFX_TEST_VENV_DIR Override the test virtualenv path. Defaults to ${ROOT_DIR}/.venv.
|
||||
|
||||
Notes:
|
||||
- This script prepares a project-local test environment, not the persistent user bundle.
|
||||
- The persistent bundle setup remains owned by tools/setup.sh.
|
||||
EOF
|
||||
}
|
||||
|
||||
status_ok() {
|
||||
printf '%sok%s' "${COLOR_GREEN}" "${COLOR_RESET}"
|
||||
}
|
||||
|
||||
status_warn() {
|
||||
printf '%swarn%s' "${COLOR_YELLOW}" "${COLOR_RESET}"
|
||||
}
|
||||
|
||||
status_fail() {
|
||||
printf '%sfailed%s' "${COLOR_RED}" "${COLOR_RESET}"
|
||||
}
|
||||
|
||||
report_component() {
|
||||
local level="$1"
|
||||
local label="$2"
|
||||
local detail="$3"
|
||||
local rendered_status=""
|
||||
|
||||
case "${level}" in
|
||||
ok)
|
||||
rendered_status="$(status_ok)"
|
||||
;;
|
||||
warn)
|
||||
rendered_status="$(status_warn)"
|
||||
;;
|
||||
*)
|
||||
rendered_status="$(status_fail)"
|
||||
;;
|
||||
esac
|
||||
|
||||
printf '[%s] %s%s\n' "${rendered_status}" "${label}" "${detail:+: $detail}"
|
||||
}
|
||||
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_python_venv_support() {
|
||||
python3 -m venv --help >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_system_command() {
|
||||
command_exists "$1"
|
||||
}
|
||||
|
||||
check_venv_python() {
|
||||
[ -x "${VENV_PYTHON}" ]
|
||||
}
|
||||
|
||||
check_venv_pip() {
|
||||
check_venv_python && "${VENV_PIP}" --version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_venv_ffx() {
|
||||
check_venv_python && "${VENV_PYTHON}" -m ffx version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_venv_pytest() {
|
||||
check_venv_python && "${VENV_PYTHON}" -m pytest --version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_venv_sphinx() {
|
||||
check_venv_python && "${VENV_BIN_DIR}/sphinx-build" --version >/dev/null 2>&1
|
||||
}
|
||||
|
||||
check_venv_docs_packages() {
|
||||
check_venv_python && "${VENV_PYTHON}" - <<'PY' >/dev/null 2>&1
|
||||
import esbonio
|
||||
import sphinx
|
||||
import sphinx_rtd_theme
|
||||
PY
|
||||
}
|
||||
|
||||
check_editable_install() {
|
||||
check_venv_python && FFX_REPO_ROOT="${ROOT_DIR}" "${VENV_PYTHON}" - <<'PY' >/dev/null 2>&1
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import ffx
|
||||
|
||||
repo_root = Path(os.environ["FFX_REPO_ROOT"]).resolve()
|
||||
package_path = Path(ffx.__file__).resolve()
|
||||
|
||||
raise SystemExit(0 if repo_root in package_path.parents else 1)
|
||||
PY
|
||||
}
|
||||
|
||||
check_python_environment_ready() {
|
||||
check_venv_python &&
|
||||
check_venv_pip &&
|
||||
check_venv_pytest &&
|
||||
check_venv_sphinx &&
|
||||
check_venv_docs_packages &&
|
||||
check_venv_ffx &&
|
||||
check_editable_install
|
||||
}
|
||||
|
||||
command_detail() {
|
||||
command -v "$1" || printf "command '%s' not found" "$1"
|
||||
}
|
||||
|
||||
python_venv_detail() {
|
||||
if check_python_venv_support; then
|
||||
printf 'python3 -m venv is available'
|
||||
else
|
||||
printf 'python3 venv support is unavailable'
|
||||
fi
|
||||
}
|
||||
|
||||
venv_python_detail() {
|
||||
if check_venv_python; then
|
||||
printf '%s' "${VENV_PYTHON}"
|
||||
else
|
||||
printf 'missing %s' "${VENV_PYTHON}"
|
||||
fi
|
||||
}
|
||||
|
||||
venv_pip_detail() {
|
||||
if check_venv_pip; then
|
||||
"${VENV_PIP}" --version
|
||||
else
|
||||
printf 'missing pip in %s' "${VENV_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
venv_ffx_detail() {
|
||||
if check_venv_ffx; then
|
||||
printf 'ffx import and CLI entry are available'
|
||||
else
|
||||
printf 'ffx is not installed in %s' "${VENV_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
venv_pytest_detail() {
|
||||
if check_venv_pytest; then
|
||||
"${VENV_PYTHON}" -m pytest --version 2>/dev/null | head -n 1
|
||||
else
|
||||
printf 'pytest is not installed in %s' "${VENV_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
venv_sphinx_detail() {
|
||||
if check_venv_sphinx; then
|
||||
"${VENV_BIN_DIR}/sphinx-build" --version 2>&1
|
||||
else
|
||||
printf 'sphinx-build is not installed in %s' "${VENV_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
venv_docs_packages_detail() {
|
||||
if check_venv_docs_packages; then
|
||||
printf 'Sphinx, Read the Docs theme, and Esbonio packages are importable'
|
||||
else
|
||||
printf 'one or more docs packages are missing in %s' "${VENV_DIR}"
|
||||
fi
|
||||
}
|
||||
|
||||
editable_install_detail() {
|
||||
if check_editable_install; then
|
||||
printf 'ffx resolves from %s' "${ROOT_DIR}"
|
||||
else
|
||||
printf 'ffx does not resolve from the project source tree'
|
||||
fi
|
||||
}
|
||||
|
||||
report_required_command() {
|
||||
local label="$1"
|
||||
local command_name="$2"
|
||||
|
||||
if check_system_command "${command_name}"; then
|
||||
report_component ok "${label}" "$(command_detail "${command_name}")"
|
||||
else
|
||||
report_component failed "${label}" "$(command_detail "${command_name}")"
|
||||
MISSING_REQUIRED_SYSTEM+=("${command_name}")
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
print_system_status() {
|
||||
MISSING_REQUIRED_SYSTEM=()
|
||||
|
||||
echo "System toolchain status:"
|
||||
report_required_command "git" "git"
|
||||
report_required_command "python3" "python3"
|
||||
|
||||
if check_system_command "python3" && check_python_venv_support; then
|
||||
report_component ok "python3 venv" "$(python_venv_detail)"
|
||||
else
|
||||
report_component failed "python3 venv" "$(python_venv_detail)"
|
||||
MISSING_REQUIRED_SYSTEM+=("python3-venv")
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
report_required_command "ffmpeg" "ffmpeg"
|
||||
report_required_command "ffprobe" "ffprobe"
|
||||
report_required_command "cpulimit" "cpulimit"
|
||||
}
|
||||
|
||||
print_python_status() {
|
||||
echo "Repo test and docs virtualenv status:"
|
||||
|
||||
if check_venv_python; then
|
||||
report_component ok "test virtualenv" "$(venv_python_detail)"
|
||||
else
|
||||
report_component failed "test virtualenv" "$(venv_python_detail)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
if check_venv_pip; then
|
||||
report_component ok "test pip" "$(venv_pip_detail)"
|
||||
else
|
||||
report_component failed "test pip" "$(venv_pip_detail)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
if check_venv_pytest; then
|
||||
report_component ok "test pytest" "$(venv_pytest_detail)"
|
||||
else
|
||||
report_component failed "test pytest" "$(venv_pytest_detail)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
if check_venv_sphinx; then
|
||||
report_component ok "docs sphinx" "$(venv_sphinx_detail)"
|
||||
else
|
||||
report_component failed "docs sphinx" "$(venv_sphinx_detail)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
if check_venv_docs_packages; then
|
||||
report_component ok "docs packages" "$(venv_docs_packages_detail)"
|
||||
else
|
||||
report_component failed "docs packages" "$(venv_docs_packages_detail)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
if check_venv_ffx; then
|
||||
report_component ok "test ffx" "$(venv_ffx_detail)"
|
||||
else
|
||||
report_component failed "test ffx" "$(venv_ffx_detail)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
|
||||
if check_editable_install; then
|
||||
report_component ok "editable source" "$(editable_install_detail)"
|
||||
else
|
||||
report_component failed "editable source" "$(editable_install_detail)"
|
||||
READINESS_FAILURES=$((READINESS_FAILURES + 1))
|
||||
fi
|
||||
}
|
||||
|
||||
print_status_report() {
|
||||
READINESS_FAILURES=0
|
||||
|
||||
print_system_status
|
||||
echo
|
||||
print_python_status
|
||||
}
|
||||
|
||||
detect_package_manager() {
|
||||
if command_exists apt-get; then
|
||||
printf 'apt-get\n'
|
||||
return 0
|
||||
fi
|
||||
if command_exists pacman; then
|
||||
printf 'pacman\n'
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
run_root_command() {
|
||||
if [ "${EUID}" -eq 0 ]; then
|
||||
"$@"
|
||||
elif command_exists sudo; then
|
||||
sudo -n "$@"
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
install_system_requirements() {
|
||||
local package_manager
|
||||
|
||||
if [ "${#MISSING_REQUIRED_SYSTEM[@]}" -eq 0 ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! package_manager="$(detect_package_manager)"; then
|
||||
printf 'No supported package manager found for automatic system preparation.\n' >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "${package_manager}" in
|
||||
apt-get)
|
||||
printf 'Installing required system dependencies via apt-get...\n'
|
||||
if ! run_root_command apt-get update; then
|
||||
printf 'apt-get update failed or requires interactive sudo.\n' >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
if ! run_root_command apt-get install -y git python3 python3-venv ffmpeg cpulimit; then
|
||||
printf 'apt-get install failed or requires interactive sudo.\n' >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
pacman)
|
||||
printf 'Installing required system dependencies via pacman...\n'
|
||||
if ! run_root_command pacman -Sy --noconfirm git python ffmpeg cpulimit; then
|
||||
printf 'pacman install failed or requires interactive sudo.\n' >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
ensure_test_venv() {
|
||||
if ! check_venv_python; then
|
||||
printf 'Creating repo test virtualenv at %s...\n' "${VENV_DIR}"
|
||||
if ! python3 -m venv "${VENV_DIR}"; then
|
||||
printf 'Failed to create test virtualenv at %s.\n' "${VENV_DIR}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! check_venv_pip; then
|
||||
printf 'Missing pip in %s.\n' "${VENV_DIR}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
printf 'Installing FFX package with test and docs extras into %s...\n' "${VENV_DIR}"
|
||||
if ! (
|
||||
cd "${ROOT_DIR}" &&
|
||||
"${VENV_PIP}" install --editable '.[test,docs]'
|
||||
); then
|
||||
printf 'Failed to install FFX package with test and docs extras into %s.\n' "${VENV_DIR}" >&2
|
||||
INSTALL_FAILURES=$((INSTALL_FAILURES + 1))
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--check)
|
||||
CHECK_ONLY=1
|
||||
;;
|
||||
--help|-h)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
printf 'Unknown option: %s\n\n' "$1" >&2
|
||||
usage >&2
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
main() {
|
||||
parse_args "$@"
|
||||
|
||||
print_status_report
|
||||
|
||||
if [ "${CHECK_ONLY}" -eq 0 ]; then
|
||||
if [ "${#MISSING_REQUIRED_SYSTEM[@]}" -gt 0 ]; then
|
||||
echo
|
||||
install_system_requirements
|
||||
fi
|
||||
|
||||
if check_python_environment_ready; then
|
||||
echo
|
||||
report_component ok "Python package install" "repo test and docs virtualenv is already ready"
|
||||
elif check_system_command "python3" && check_python_venv_support; then
|
||||
echo
|
||||
ensure_test_venv
|
||||
fi
|
||||
|
||||
echo
|
||||
print_status_report
|
||||
fi
|
||||
|
||||
echo
|
||||
if [ "${INSTALL_FAILURES}" -gt 0 ]; then
|
||||
echo "One or more test preparation steps failed; see the status checks above." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${READINESS_FAILURES}" -gt 0 ]; then
|
||||
if [ "${CHECK_ONLY}" -eq 1 ]; then
|
||||
echo "The FFX test and docs environment is incomplete." >&2
|
||||
else
|
||||
echo "Required test or docs components are still missing after preparation." >&2
|
||||
fi
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${CHECK_ONLY}" -eq 1 ]; then
|
||||
echo "The FFX test and docs environment is ready."
|
||||
else
|
||||
echo "The FFX test and docs environment is prepared."
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user