#!/bin/bash set -e # ============================================================================= # officer-setup — the platform, on a machine that is already provisioned # # The second half of the install. machine-setup/ brings a blank box up to a # usable machine; this puts Officer on top of it. # # Run as root: sudo scripts/setup/officer-setup.sh # ============================================================================= SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROGRESS_FILE="$SCRIPT_DIR/officer-setup/.setup-progress" ONLY_STEP="" while [[ $# -gt 0 ]]; do case "$1" in --only) ONLY_STEP="${2:-}" shift 2 ;; --only=*) ONLY_STEP="${1#*=}" shift ;; -l | --list) grep -oP '^step "\K[^"]+' "${BASH_SOURCE[0]}" exit 0 ;; -h | --help) echo "usage: officer-setup.sh [--only ] [--list]" exit 0 ;; *) echo "unknown option: $1" >&2 && exit 2 ;; esac done # shellcheck source=officer-setup/lib/base.sh source "$SCRIPT_DIR/officer-setup/lib/base.sh" # shellcheck source=officer-setup/lib/preflight.sh source "$SCRIPT_DIR/officer-setup/lib/preflight.sh" trap 'echo ""; echo -e "${RED}╔══════════════════════════════════════════════════╗${NC}"; echo -e "${RED}║ OFFICER SETUP FAILED${NC}"; echo -e "${RED}║ Step: ${CURRENT_STEP:-unknown}${NC}"; echo -e "${RED}║ Line: $LINENO${NC}"; echo -e "${RED}║ Command: $BASH_COMMAND${NC}"; echo -e "${RED}╚══════════════════════════════════════════════════╝${NC}"' ERR # ============================================================================= # 1. Pre-flight # ============================================================================= echo "" echo -e "${BOLD}╔══════════════════════════════════════════════════╗${NC}" echo -e "${BOLD}║ Officer Setup ║${NC}" echo -e "${BOLD}╚══════════════════════════════════════════════════╝${NC}" if [[ "$EUID" -ne 0 ]]; then fail "Please run as root: sudo ./officer-setup.sh" fi # ── what machine-setup already established ── echo "" if load_machine_answers; then info "Read from machine-setup: ${MACHINE_ANSWERS}" else warn "machine-setup has not run on this machine" echo " That is fine if you provisioned it another way — the questions it" echo " would have answered are asked below instead." fi # ── the account ── # # A remembered answer can go stale: the account it names may have been renamed or # removed since machine-setup ran. That is a reason to ask again, not a reason to # stop — so the remembered value is checked before it is trusted, and a bad one # is reported and replaced rather than ending the run. if [[ -n "$USERNAME" ]] && ! owner_exists; then warn "the remembered account '${USERNAME}' does not exist on this machine any more" USERNAME="" fi while [[ -z "$USERNAME" ]] || ! owner_exists; do echo "" info "Which account owns this Officer install?" echo " Its files, its node_modules and its pm2 process list all belong to" echo " this account rather than to root." echo "" ask_required USERNAME "Username" "${SUDO_USER:-}" owner_exists || warn "There is no account called '${USERNAME}' on this machine." done resolve_user_home # ── where it goes ── if [[ -z "$OFFICER_ROOT" ]]; then echo "" info "Where should Officer be installed?" echo " One directory holding the app, its data, the item store and any" echo " containers the app store provisions." echo "" ask_required OFFICER_ROOT "Path" "${USER_HOME}/officerdev" fi OFFICER_ROOT="${OFFICER_ROOT/#\~/$USER_HOME}" [[ "$OFFICER_ROOT" == /* ]] || fail "That needs to be an absolute path — got '${OFFICER_ROOT}'" OFFICER_ROOT="${OFFICER_ROOT%/}" info "Account: ${USERNAME} (home ${USER_HOME})" info "Officer: ${OFFICER_ROOT}" [[ -n "$MACHINE_ROLE" ]] && info "Role: ${MACHINE_ROLE}" # ── is the machine actually ready ── # # Checked and reported together. Finding out about a missing bun three sections # in, after a repository has been cloned and a database started, is a worse way # to learn it. echo "" info "What Officer needs from this machine" mapfile -t MISSING < <(missing_tools) mapfile -t MISSING_OPT < <(missing_optional_tools) for t in "${REQUIRED_TOOLS[@]}"; do if command -v "$t" &>/dev/null; then printf ' %-6s %-10s %s\n' "$t" "ok" "$(tool_why "$t")" else printf ' %-6s %-10s %s\n' "$t" "MISSING" "$(tool_why "$t")" fi done for t in "${OPTIONAL_TOOLS[@]}"; do if command -v "$t" &>/dev/null; then printf ' %-6s %-10s %s\n' "$t" "ok" "$(tool_why "$t")" else printf ' %-6s %-10s %s\n' "$t" "absent" "$(tool_why "$t") — optional" fi done if ((${#MISSING[@]} > 0)); then echo "" fail "Missing: ${MISSING[*]}. Run scripts/setup/machine-setup/machine-setup.sh first, or install them yourself." fi if ((${#MISSING_OPT[@]} > 0)); then echo "" warn "No Docker. Postgres will have to be one you already run, and the app" echo " store cannot provision anything until Docker is installed." fi if [[ -f "$PROGRESS_FILE" ]]; then echo "" info "Resuming — $(wc -l <"$PROGRESS_FILE") step(s) already done, and they will be skipped" echo " To start over instead: sudo rm ${PROGRESS_FILE}" else echo "" echo " This can be stopped at any point and run again later. Completed" echo " steps are remembered and skipped." fi # ============================================================================= # NOT BUILT YET # ============================================================================= # # 2 Repository clone or locate the platform at $OFFICER_ROOT/platform # 3 Dependencies bun install # 4 Database Postgres in docker, or one you already run # 5 Environment .env # 6 Schema db:push # 7 Build gen:index # 8 Services pm2 startOrRestart · save · startup # 9 Verify are the processes actually up echo "" echo -e "${BOLD} Pre-flight complete.${NC} The remaining sections are not built yet." echo ""