534 lines
20 KiB
Bash
Executable File
534 lines
20 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# =============================================================================
|
|
# setup/configure_runners.sh — Interactive runners.conf configuration wizard
|
|
# Prompts for each runner's fields with validation and progress tracking.
|
|
# Persists answers to runners.conf as each prompt is completed.
|
|
# Defaults are pulled from .env — nothing is hardcoded.
|
|
# =============================================================================
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
PROJECT_ROOT="${SCRIPT_DIR}/.."
|
|
RUNNERS_CONF="${PROJECT_ROOT}/runners.conf"
|
|
|
|
# shellcheck source=../lib/common.sh
|
|
# shellcheck disable=SC1091
|
|
source "${PROJECT_ROOT}/lib/common.sh"
|
|
|
|
# Load .env for defaults (RUNNER_DEFAULT_IMAGE, RUNNER_DEFAULT_CAPACITY, etc.)
|
|
load_env
|
|
|
|
# Colors — only emit ANSI escapes when stdout is a terminal (not piped/redirected)
|
|
if [[ -t 1 ]]; then
|
|
C_RESET='\033[0m'; C_BOLD='\033[1m'; C_GREEN='\033[0;32m'
|
|
C_YELLOW='\033[0;33m'; C_RED='\033[0;31m'; C_DIM='\033[2m'
|
|
else
|
|
C_RESET=''; C_BOLD=''; C_GREEN=''; C_YELLOW=''; C_RED=''; C_DIM=''
|
|
fi
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Load existing runner entries as defaults (idempotent re-runs).
|
|
# If runners.conf already exists and is INI format, we read existing values
|
|
# to pre-fill prompts when re-running the wizard.
|
|
# ---------------------------------------------------------------------------
|
|
DEFAULTS_CONF=""
|
|
cleanup_defaults_conf() {
|
|
if [[ -n "$DEFAULTS_CONF" ]] && [[ -f "$DEFAULTS_CONF" ]]; then
|
|
rm -f "$DEFAULTS_CONF"
|
|
fi
|
|
}
|
|
trap cleanup_defaults_conf EXIT
|
|
|
|
EXISTING_SECTIONS=()
|
|
if [[ -f "$RUNNERS_CONF" ]]; then
|
|
# Keep a snapshot for defaults so we can rewrite runners.conf incrementally
|
|
# without losing pre-filled values when the wizard is re-run.
|
|
DEFAULTS_CONF=$(mktemp)
|
|
cp "$RUNNERS_CONF" "$DEFAULTS_CONF"
|
|
while IFS= read -r sec; do
|
|
[[ -z "$sec" ]] && continue
|
|
EXISTING_SECTIONS+=("$sec")
|
|
done < <(ini_list_sections "$DEFAULTS_CONF")
|
|
fi
|
|
EXISTING_COUNT=${#EXISTING_SECTIONS[@]}
|
|
|
|
ini_default_get() {
|
|
local section="$1" key="$2" default="${3:-}"
|
|
if [[ -z "$DEFAULTS_CONF" ]]; then
|
|
printf '%s' "$default"
|
|
return 0
|
|
fi
|
|
ini_get "$DEFAULTS_CONF" "$section" "$key" "$default"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Validation helpers
|
|
# ---------------------------------------------------------------------------
|
|
validate_runner_name() {
|
|
[[ "$1" =~ ^[a-zA-Z0-9][a-zA-Z0-9_-]*$ ]]
|
|
}
|
|
|
|
validate_runner_type() {
|
|
[[ "$1" == "docker" || "$1" == "native" ]]
|
|
}
|
|
|
|
validate_runner_host() {
|
|
[[ "$1" == "unraid" || "$1" == "fedora" || "$1" == "local" || "$1" == "custom" ]]
|
|
}
|
|
|
|
validate_runner_path() {
|
|
# shellcheck disable=SC2088 # tilde intentionally stored as literal string
|
|
[[ "$1" == /* || "$1" == "~/"* || "$1" == "~" ]]
|
|
}
|
|
|
|
validate_runner_repos() {
|
|
if [[ "$1" == "all" ]]; then return 0; fi
|
|
# Check against known REPO_*_NAME values
|
|
[[ "$1" == "${REPO_1_NAME:-}" ]] || [[ "$1" == "${REPO_2_NAME:-}" ]] || [[ "$1" == "${REPO_3_NAME:-}" ]]
|
|
}
|
|
|
|
validate_capacity() {
|
|
[[ "$1" =~ ^[1-9][0-9]*$ ]]
|
|
}
|
|
|
|
validate_docker_cpu() {
|
|
[[ -z "$1" ]] || [[ "$1" =~ ^[0-9]+(\.[0-9]+)?$ ]]
|
|
}
|
|
|
|
validate_docker_memory() {
|
|
[[ -z "$1" ]] || [[ "$1" =~ ^[0-9]+[kmgKMG]?$ ]]
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Prompt function — matches configure_env.sh UX (progress counter, default
|
|
# values in yellow brackets, validation loop with red error hints).
|
|
# Sets the global PROMPT_RESULT to the validated user input.
|
|
# ---------------------------------------------------------------------------
|
|
CURRENT_PROMPT=0
|
|
TOTAL_PROMPTS=0
|
|
|
|
prompt_field() {
|
|
local field_name="$1" # e.g. "name", "ssh_host"
|
|
local description="$2" # human-readable hint shown in parentheses
|
|
local validation="$3" # validator key
|
|
local default="${4:-}" # pre-filled value shown in [brackets]; Enter accepts it
|
|
local allow_empty="${5:-false}" # true if empty is a valid answer
|
|
|
|
CURRENT_PROMPT=$((CURRENT_PROMPT + 1))
|
|
|
|
local progress
|
|
progress=$(printf '[%d/%d]' "$CURRENT_PROMPT" "$TOTAL_PROMPTS")
|
|
|
|
local prompt_text
|
|
if [[ -n "$default" ]]; then
|
|
prompt_text=$(printf '%b%s%b %s (%s) %b[%s]%b: ' "$C_DIM" "$progress" "$C_RESET" "$field_name" "$description" "$C_YELLOW" "$default" "$C_RESET")
|
|
else
|
|
prompt_text=$(printf '%b%s%b %s (%s): ' "$C_DIM" "$progress" "$C_RESET" "$field_name" "$description")
|
|
fi
|
|
|
|
local value
|
|
while true; do
|
|
printf '%b' "$prompt_text"
|
|
read -r value
|
|
|
|
if [[ -z "$value" ]]; then
|
|
value="$default"
|
|
fi
|
|
|
|
# Allow empty when explicitly permitted (optional fields)
|
|
if [[ -z "$value" ]] && [[ "$allow_empty" == "true" ]]; then
|
|
break
|
|
fi
|
|
|
|
if [[ -z "$value" ]]; then
|
|
printf '%b Invalid: value cannot be empty%b\n' "$C_RED" "$C_RESET"
|
|
continue
|
|
fi
|
|
|
|
case "$validation" in
|
|
runner_name)
|
|
if validate_runner_name "$value"; then break; fi
|
|
printf '%b Invalid: alphanumeric, hyphens, and underscores only%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
runner_type)
|
|
if validate_runner_type "$value"; then break; fi
|
|
printf '%b Invalid: must be "docker" or "native"%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
runner_host)
|
|
if validate_runner_host "$value"; then break; fi
|
|
printf '%b Invalid: must be unraid, fedora, local, or custom%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
runner_path)
|
|
if validate_runner_path "$value"; then break; fi
|
|
printf '%b Invalid path (must start with / or ~/)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
runner_repos)
|
|
if validate_runner_repos "$value"; then break; fi
|
|
printf '%b Invalid: must be "all" or a known repo name%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
capacity)
|
|
if validate_capacity "$value"; then break; fi
|
|
printf '%b Invalid: must be a positive integer (>= 1)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
docker_cpu)
|
|
if validate_docker_cpu "$value"; then break; fi
|
|
printf '%b Invalid: must be a positive number (e.g. 2.0, 0.5) or empty%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
docker_memory)
|
|
if validate_docker_memory "$value"; then break; fi
|
|
printf '%b Invalid: must be Docker memory format (e.g. 2g, 512m) or empty%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
bool)
|
|
if [[ "$value" == "true" || "$value" == "false" ]]; then break; fi
|
|
printf '%b Invalid: must be "true" or "false"%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
ip)
|
|
if validate_ip "$value"; then break; fi
|
|
printf '%b Invalid IP address format (expected: x.x.x.x)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
port)
|
|
if validate_port "$value"; then break; fi
|
|
printf '%b Invalid port (expected: 1-65535)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
optional_path)
|
|
if validate_optional_path "$value"; then break; fi
|
|
printf '%b Invalid path (must start with / or ~/ or be empty)%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
nonempty|*)
|
|
if validate_nonempty "$value"; then break; fi
|
|
printf '%b Invalid: value cannot be empty%b\n' "$C_RED" "$C_RESET"
|
|
;;
|
|
esac
|
|
done
|
|
|
|
PROMPT_RESULT="$value"
|
|
}
|
|
|
|
init_runners_conf() {
|
|
cat > "$RUNNERS_CONF" <<'HEADER'
|
|
# =============================================================================
|
|
# runners.conf — Gitea Actions Runner Definitions (INI format)
|
|
# Generated by setup/configure_runners.sh — edit manually or re-run wizard.
|
|
# Use manage_runner.sh to add/remove runners dynamically.
|
|
# See runners.conf.example for field reference.
|
|
# =============================================================================
|
|
|
|
HEADER
|
|
}
|
|
|
|
ensure_runner_section() {
|
|
local section="$1"
|
|
if ! grep -Fqx "[$section]" "$RUNNERS_CONF" 2>/dev/null; then
|
|
printf '[%s]\n\n' "$section" >> "$RUNNERS_CONF"
|
|
fi
|
|
}
|
|
|
|
save_runner_field() {
|
|
local section="$1" key="$2" value="$3"
|
|
ini_set "$RUNNERS_CONF" "$section" "$key" "$value"
|
|
_cdata_set "${section}:${key}" "$value"
|
|
}
|
|
|
|
# ===========================================================================
|
|
# Main
|
|
# ===========================================================================
|
|
|
|
printf '\n%b╔══════════════════════════════════════════════════════════╗%b\n' "$C_BOLD" "$C_RESET"
|
|
printf '%b║ Gitea Migration — Runner Setup ║%b\n' "$C_BOLD" "$C_RESET"
|
|
printf '%b╚══════════════════════════════════════════════════════════╝%b\n\n' "$C_BOLD" "$C_RESET"
|
|
printf 'Press Enter to keep the current value shown in [brackets].\n'
|
|
printf 'Defaults are pulled from .env variables.\n'
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Ask how many runners to configure.
|
|
# Default is 3 (unraid + fedora + macbook) or the count from existing config.
|
|
# ---------------------------------------------------------------------------
|
|
local_default=3
|
|
if [[ $EXISTING_COUNT -gt 0 ]]; then
|
|
local_default=$EXISTING_COUNT
|
|
fi
|
|
|
|
printf '\n%b── RUNNER COUNT ──────────────────────────────────────────%b\n' "$C_BOLD" "$C_RESET"
|
|
printf 'How many runners to configure? %b[%s]%b: ' "$C_YELLOW" "$local_default" "$C_RESET"
|
|
read -r runner_count
|
|
if [[ -z "$runner_count" ]]; then
|
|
runner_count=$local_default
|
|
fi
|
|
if ! [[ "$runner_count" =~ ^[0-9]+$ ]] || [[ "$runner_count" -lt 1 ]]; then
|
|
printf '%b Invalid: must be a positive number. Using %d.%b\n' "$C_RED" "$local_default" "$C_RESET"
|
|
runner_count=$local_default
|
|
fi
|
|
|
|
# Prompt count per runner:
|
|
# name(1) + host(1) + type(1) + data_path(1) + labels(1) + default_image(1) +
|
|
# repos(1) + capacity(1) + cpu(1) + memory(1) + boot(1) = 11
|
|
# Custom host adds: ssh_host(1) + ssh_user(1) + ssh_port(1) + ssh_key(1) = 4
|
|
# We estimate max 11 per runner for progress display
|
|
TOTAL_PROMPTS=$((runner_count * 11))
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Configure runner definitions
|
|
# ---------------------------------------------------------------------------
|
|
# Keep arrays for end-of-run summary; values are persisted immediately.
|
|
COLLECTED_NAMES=()
|
|
# Bash 3.2 compatible key-value store (no associative arrays)
|
|
_CDATA_KEYS=()
|
|
_CDATA_VALS=()
|
|
|
|
_cdata_set() {
|
|
local k="$1" v="$2" i
|
|
for i in "${!_CDATA_KEYS[@]}"; do
|
|
if [[ "${_CDATA_KEYS[$i]}" == "$k" ]]; then
|
|
_CDATA_VALS[i]="$v"
|
|
return 0
|
|
fi
|
|
done
|
|
_CDATA_KEYS+=("$k")
|
|
_CDATA_VALS+=("$v")
|
|
}
|
|
|
|
_cdata_get() {
|
|
local k="$1" default="${2:-}" i
|
|
for i in "${!_CDATA_KEYS[@]}"; do
|
|
if [[ "${_CDATA_KEYS[$i]}" == "$k" ]]; then
|
|
printf '%s' "${_CDATA_VALS[$i]}"
|
|
return 0
|
|
fi
|
|
done
|
|
printf '%s' "$default"
|
|
}
|
|
|
|
init_runners_conf
|
|
|
|
for ((i = 0; i < runner_count; i++)); do
|
|
runner_num=$((i + 1))
|
|
printf '\n%b── RUNNER %d OF %d ──────────────────────────────────────────%b\n' "$C_BOLD" "$runner_num" "$runner_count" "$C_RESET"
|
|
|
|
# Existing defaults from previous runners.conf (if available)
|
|
ex_name="${EXISTING_SECTIONS[$i]:-}"
|
|
|
|
# --- name ---
|
|
name_default="$ex_name"
|
|
if [[ -z "$name_default" ]]; then
|
|
case $i in
|
|
0) name_default="unraid-runner" ;;
|
|
1) name_default="fedora-runner" ;;
|
|
2) name_default="macbook-runner" ;;
|
|
*) name_default="runner-${runner_num}" ;;
|
|
esac
|
|
fi
|
|
prompt_field "name" "runner display name in Gitea" "runner_name" "$name_default"
|
|
r_name="$PROMPT_RESULT"
|
|
COLLECTED_NAMES+=("$r_name")
|
|
ensure_runner_section "$r_name"
|
|
|
|
# --- host ---
|
|
host_default=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
host_default=$(ini_default_get "$ex_name" "host" "")
|
|
fi
|
|
if [[ -z "$host_default" ]]; then
|
|
case $i in
|
|
0) host_default="unraid" ;;
|
|
1) host_default="fedora" ;;
|
|
2) host_default="local" ;;
|
|
*) host_default="unraid" ;;
|
|
esac
|
|
fi
|
|
prompt_field "host" "unraid, fedora, local, or custom" "runner_host" "$host_default"
|
|
r_host="$PROMPT_RESULT"
|
|
save_runner_field "$r_name" "host" "$r_host"
|
|
|
|
# Show resolved SSH details for known hosts
|
|
case "$r_host" in
|
|
unraid)
|
|
printf '%b → SSH: %s@%s:%s%b\n' "$C_DIM" "${UNRAID_SSH_USER:-<not set>}" "${UNRAID_IP:-<not set>}" "${UNRAID_SSH_PORT:-22}" "$C_RESET"
|
|
if [[ -n "${UNRAID_SSH_KEY:-}" ]]; then
|
|
printf '%b → SSH key: %s%b\n' "$C_DIM" "${UNRAID_SSH_KEY}" "$C_RESET"
|
|
fi
|
|
;;
|
|
fedora)
|
|
printf '%b → SSH: %s@%s:%s%b\n' "$C_DIM" "${FEDORA_SSH_USER:-<not set>}" "${FEDORA_IP:-<not set>}" "${FEDORA_SSH_PORT:-22}" "$C_RESET"
|
|
if [[ -n "${FEDORA_SSH_KEY:-}" ]]; then
|
|
printf '%b → SSH key: %s%b\n' "$C_DIM" "${FEDORA_SSH_KEY}" "$C_RESET"
|
|
fi
|
|
;;
|
|
local)
|
|
printf '%b → Runs on this machine (no SSH)%b\n' "$C_DIM" "$C_RESET"
|
|
;;
|
|
custom)
|
|
# Prompt for custom SSH details
|
|
ex_ssh_host=""
|
|
ex_ssh_user=""
|
|
ex_ssh_port=""
|
|
ex_ssh_key=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
ex_ssh_host=$(ini_default_get "$ex_name" "ssh_host" "")
|
|
ex_ssh_user=$(ini_default_get "$ex_name" "ssh_user" "")
|
|
ex_ssh_port=$(ini_default_get "$ex_name" "ssh_port" "22")
|
|
ex_ssh_key=$(ini_default_get "$ex_name" "ssh_key" "")
|
|
fi
|
|
prompt_field "ssh_host" "IP address of remote host" "ip" "$ex_ssh_host"
|
|
save_runner_field "$r_name" "ssh_host" "$PROMPT_RESULT"
|
|
prompt_field "ssh_user" "SSH username" "nonempty" "${ex_ssh_user:-root}"
|
|
save_runner_field "$r_name" "ssh_user" "$PROMPT_RESULT"
|
|
prompt_field "ssh_port" "SSH port" "port" "${ex_ssh_port:-22}"
|
|
save_runner_field "$r_name" "ssh_port" "$PROMPT_RESULT"
|
|
prompt_field "ssh_key" "path to SSH key (empty = ssh-agent)" "optional_path" "$ex_ssh_key" "true"
|
|
save_runner_field "$r_name" "ssh_key" "$PROMPT_RESULT"
|
|
# Adjust total prompts (added 4 custom fields, but we already allocated 10)
|
|
;;
|
|
esac
|
|
|
|
# --- type ---
|
|
type_default=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
type_default=$(ini_default_get "$ex_name" "type" "")
|
|
fi
|
|
if [[ -z "$type_default" ]]; then
|
|
if [[ "$r_host" == "local" ]]; then type_default="native"; else type_default="docker"; fi
|
|
fi
|
|
prompt_field "type" "docker (Linux) or native (macOS)" "runner_type" "$type_default"
|
|
r_type="$PROMPT_RESULT"
|
|
save_runner_field "$r_name" "type" "$r_type"
|
|
|
|
# --- data_path ---
|
|
path_default=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
path_default=$(ini_default_get "$ex_name" "data_path" "")
|
|
fi
|
|
if [[ -z "$path_default" ]]; then
|
|
if [[ "$r_type" == "native" ]]; then
|
|
path_default="${LOCAL_RUNNER_DATA_PATH:-~/gitea-runner}"
|
|
else
|
|
path_default="${RUNNER_DEFAULT_DATA_PATH:-/mnt/nvme/gitea-runner}"
|
|
fi
|
|
fi
|
|
prompt_field "data_path" "absolute path for runner data" "runner_path" "$path_default"
|
|
save_runner_field "$r_name" "data_path" "$PROMPT_RESULT"
|
|
|
|
# --- labels ---
|
|
labels_default=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
labels_default=$(ini_default_get "$ex_name" "labels" "")
|
|
fi
|
|
if [[ -z "$labels_default" ]]; then
|
|
if [[ "$r_type" == "native" ]]; then labels_default="macos"; else labels_default="linux"; fi
|
|
fi
|
|
prompt_field "labels" "workflow runs-on value" "nonempty" "$labels_default"
|
|
save_runner_field "$r_name" "labels" "$PROMPT_RESULT"
|
|
|
|
# --- default_image (skip for native) ---
|
|
if [[ "$r_type" == "docker" ]]; then
|
|
image_default=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
image_default=$(ini_default_get "$ex_name" "default_image" "")
|
|
fi
|
|
if [[ -z "$image_default" ]]; then
|
|
image_default="${RUNNER_DEFAULT_IMAGE:-catthehacker/ubuntu:act-latest}"
|
|
fi
|
|
prompt_field "default_image" "Docker image for job execution" "nonempty" "$image_default"
|
|
save_runner_field "$r_name" "default_image" "$PROMPT_RESULT"
|
|
else
|
|
save_runner_field "$r_name" "default_image" ""
|
|
CURRENT_PROMPT=$((CURRENT_PROMPT + 1)) # skip but count for progress
|
|
fi
|
|
|
|
# --- repos ---
|
|
repos_default=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
repos_default=$(ini_default_get "$ex_name" "repos" "all")
|
|
fi
|
|
if [[ -z "$repos_default" ]]; then repos_default="all"; fi
|
|
# Build hint with known repo names
|
|
repos_hint="token scope: all"
|
|
for var in REPO_1_NAME REPO_2_NAME REPO_3_NAME; do
|
|
if [[ -n "${!var:-}" ]]; then
|
|
repos_hint="${repos_hint}, ${!var}"
|
|
fi
|
|
done
|
|
prompt_field "repos" "$repos_hint" "runner_repos" "$repos_default"
|
|
save_runner_field "$r_name" "repos" "$PROMPT_RESULT"
|
|
|
|
# --- capacity ---
|
|
cap_default=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
cap_default=$(ini_default_get "$ex_name" "capacity" "")
|
|
fi
|
|
if [[ -z "$cap_default" ]]; then
|
|
cap_default="${RUNNER_DEFAULT_CAPACITY:-1}"
|
|
fi
|
|
prompt_field "capacity" "max concurrent jobs (>= 1)" "capacity" "$cap_default"
|
|
save_runner_field "$r_name" "capacity" "$PROMPT_RESULT"
|
|
|
|
# --- cpu (skip for native) ---
|
|
if [[ "$r_type" == "docker" ]]; then
|
|
cpu_default=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
cpu_default=$(ini_default_get "$ex_name" "cpu" "")
|
|
fi
|
|
prompt_field "cpu" "Docker CPU limit (e.g. 2.0, empty = no limit)" "docker_cpu" "$cpu_default" "true"
|
|
save_runner_field "$r_name" "cpu" "$PROMPT_RESULT"
|
|
else
|
|
save_runner_field "$r_name" "cpu" ""
|
|
CURRENT_PROMPT=$((CURRENT_PROMPT + 1))
|
|
fi
|
|
|
|
# --- memory (skip for native) ---
|
|
if [[ "$r_type" == "docker" ]]; then
|
|
mem_default=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
mem_default=$(ini_default_get "$ex_name" "memory" "")
|
|
fi
|
|
prompt_field "memory" "Docker memory limit (e.g. 2g, empty = no limit)" "docker_memory" "$mem_default" "true"
|
|
save_runner_field "$r_name" "memory" "$PROMPT_RESULT"
|
|
else
|
|
save_runner_field "$r_name" "memory" ""
|
|
CURRENT_PROMPT=$((CURRENT_PROMPT + 1))
|
|
fi
|
|
|
|
# --- boot (skip for docker — only applies to native macOS runners) ---
|
|
# boot=true installs the launchd plist to /Library/LaunchDaemons/ (starts at
|
|
# boot before login, requires sudo). boot=false installs to ~/Library/LaunchAgents/
|
|
# (starts at login, no sudo needed).
|
|
if [[ "$r_type" == "native" ]]; then
|
|
boot_default=""
|
|
if [[ -n "$ex_name" ]]; then
|
|
boot_default=$(ini_default_get "$ex_name" "boot" "false")
|
|
fi
|
|
if [[ -z "$boot_default" ]]; then boot_default="false"; fi
|
|
prompt_field "boot" "start at boot (before login)? requires sudo [true/false]" "bool" "$boot_default"
|
|
save_runner_field "$r_name" "boot" "$PROMPT_RESULT"
|
|
else
|
|
save_runner_field "$r_name" "boot" ""
|
|
CURRENT_PROMPT=$((CURRENT_PROMPT + 1))
|
|
fi
|
|
done
|
|
|
|
# ===========================================================================
|
|
# Summary — green border box + table
|
|
# ===========================================================================
|
|
printf '\n%b╔══════════════════════════════════════════════════════════╗%b\n' "$C_GREEN" "$C_RESET"
|
|
printf '%b║ Runner Configuration Complete ║%b\n' "$C_GREEN" "$C_RESET"
|
|
printf '%b╚══════════════════════════════════════════════════════════╝%b\n\n' "$C_GREEN" "$C_RESET"
|
|
|
|
printf '%bRunners configured:%b %d\n\n' "$C_BOLD" "$C_RESET" "${#COLLECTED_NAMES[@]}"
|
|
printf '%-20s %-10s %-8s %-6s %-10s %-6s %-10s %-24s\n' "NAME" "HOST" "TYPE" "BOOT" "LABELS" "CAP" "REPOS" "DATA PATH"
|
|
printf '%-20s %-10s %-8s %-6s %-10s %-6s %-10s %-24s\n' "----" "----" "----" "----" "------" "---" "-----" "---------"
|
|
|
|
for r_name in "${COLLECTED_NAMES[@]}"; do
|
|
printf '%-20s %-10s %-8s %-6s %-10s %-6s %-10s %-24s\n' \
|
|
"$r_name" \
|
|
"$(_cdata_get "${r_name}:host")" \
|
|
"$(_cdata_get "${r_name}:type")" \
|
|
"$(_cdata_get "${r_name}:boot" "—")" \
|
|
"$(_cdata_get "${r_name}:labels")" \
|
|
"$(_cdata_get "${r_name}:capacity")" \
|
|
"$(_cdata_get "${r_name}:repos")" \
|
|
"$(_cdata_get "${r_name}:data_path")"
|
|
done
|
|
|
|
printf '\n Saved to: %s\n\n' "$RUNNERS_CONF"
|
|
printf 'Next step: run %bsetup/macbook.sh%b to install local prerequisites.\n' "$C_BOLD" "$C_RESET"
|