193 lines
4.7 KiB
Bash
193 lines
4.7 KiB
Bash
#!/usr/bin/env bash
|
|
# AMMIDS Shared Functions Library
|
|
# Location: init/scripts/functions.sh
|
|
# Sourced by all other scripts in this directory
|
|
|
|
# Prevent direct execution
|
|
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
|
echo "This is a library, not a script. Source it instead."
|
|
exit 1
|
|
fi
|
|
|
|
# --- Color Codes ---
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
TITLE='\033[38;2;17;97;2m'
|
|
NC='\033[0m'
|
|
|
|
# --- Path Resolution ---
|
|
# Standardised for project structure: /init/scripts/xxx.sh
|
|
# Sets: SCRIPT_DIR, INIT_DIR, ROOT_DIR
|
|
# --- Path Resolution ---
|
|
resolve_paths() {
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)"
|
|
|
|
# Detect if we're in init/scripts/ or at project root
|
|
if [[ "$SCRIPT_DIR" == */init/scripts ]]; then
|
|
# Called from init/scripts/ (e.g., set_env.sh, config_gen.sh)
|
|
INIT_DIR="$(dirname "$SCRIPT_DIR")"
|
|
ROOT_DIR="$(dirname "$INIT_DIR")"
|
|
else
|
|
# Called from project root (e.g., setup.sh)
|
|
ROOT_DIR="$SCRIPT_DIR"
|
|
INIT_DIR="${ROOT_DIR}/init"
|
|
fi
|
|
|
|
ENV_FILE="${ROOT_DIR}/.env"
|
|
COMPOSE_FILE="${ROOT_DIR}/compose.yaml"
|
|
export SCRIPT_DIR INIT_DIR ROOT_DIR ENV_FILE COMPOSE_FILE
|
|
}
|
|
|
|
# --- Logging ---
|
|
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
|
|
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
|
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
|
|
|
# --- State Management (init.ini) ---
|
|
write_state() {
|
|
local key="$1"
|
|
local value="$2"
|
|
local init_file="${INIT_DIR}/init.ini"
|
|
local upper_value
|
|
upper_value=$(echo "$value" | tr '[:lower:]' '[:upper:]')
|
|
echo "${key}=${upper_value}" >> "$init_file"
|
|
}
|
|
|
|
load_state() {
|
|
local init_file="${INIT_DIR}/init.ini"
|
|
if [[ -f "$init_file" ]]; then
|
|
source "$init_file"
|
|
else
|
|
log_warn "State file not found at ${init_file}. Using defaults."
|
|
fi
|
|
}
|
|
|
|
clear_state() {
|
|
local init_file="${INIT_DIR}/init.ini"
|
|
> "$init_file"
|
|
}
|
|
|
|
# --- Secrets ---
|
|
generate_secret() {
|
|
local length="${1:-32}"
|
|
if command -v openssl &> /dev/null; then
|
|
openssl rand -hex "$((length / 2))"
|
|
elif command -v pwgen &> /dev/null; then
|
|
pwgen -s "$length" 1
|
|
else
|
|
tr -dc 'A-Za-z0-9' < /dev/urandom | head -c "$length"
|
|
fi
|
|
}
|
|
|
|
# --- Interactive Prompts ---
|
|
prompt_var() {
|
|
local var_name="$1"
|
|
local prompt_text="$2"
|
|
local default_val="$3"
|
|
local is_password="$4"
|
|
local base_domain="${5:-}"
|
|
|
|
local input
|
|
local final_value
|
|
|
|
echo -n "$prompt_text [Default: $default_val]: "
|
|
read -r input
|
|
|
|
if [[ -z "$input" ]]; then
|
|
if [[ "$is_password" == "yes" ]]; then
|
|
input=$(generate_secret 32)
|
|
else
|
|
input="$default_val"
|
|
fi
|
|
fi
|
|
|
|
# Append base domain if provided
|
|
if [[ -n "$base_domain" ]]; then
|
|
final_value="${input}.${base_domain}"
|
|
else
|
|
final_value="$input"
|
|
fi
|
|
|
|
# Escape special characters for .env file
|
|
final_value="${final_value//\\/\\\\}"
|
|
final_value="${final_value//\"/\\\"}"
|
|
final_value="${final_value//\$/\\\$}"
|
|
final_value="${final_value//\`/\\\`}"
|
|
|
|
echo "${var_name}=\"${final_value}\"" >> "$ENV_FILE"
|
|
}
|
|
|
|
# --- File Permissions ---
|
|
fix_ownership() {
|
|
local target="$1"
|
|
local uid="${2:-${USER_ID:-1000}}"
|
|
local gid="${3:-${GROUP_ID:-1000}}"
|
|
|
|
if [[ -e "$target" ]] && [[ "$(stat -c '%U' "$target" 2>/dev/null)" != "$USER" ]]; then
|
|
log_warn "Fixing ownership on $target..."
|
|
sudo chown -R "${uid}:${gid}" "$target"
|
|
fi
|
|
}
|
|
|
|
# --- Dependency Checks ---
|
|
require_command() {
|
|
local cmd="$1"
|
|
if ! command -v "$cmd" &> /dev/null; then
|
|
log_error "Required command '${cmd}' not found. Install it and retry."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
require_docker() {
|
|
require_command "docker"
|
|
if ! docker compose version &> /dev/null; then
|
|
log_error "Docker Compose plugin not found. Install it and retry."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
require_file() {
|
|
local file="$1"
|
|
local description="${2:-File}"
|
|
if [[ ! -f "$file" ]]; then
|
|
log_error "${description} not found at ${file}"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
require_env() {
|
|
local file="${ENV_FILE:-${ROOT_DIR}/.env}"
|
|
|
|
if [[ ! -f "$file" ]]; then
|
|
log_error ".env file not found at ${file}. Run set_env.sh first."
|
|
exit 1
|
|
fi
|
|
|
|
# Source the file
|
|
source "$file"
|
|
|
|
# Verify critical variables exist
|
|
if [[ -z "${DOMAIN:-}" ]]; then
|
|
log_error "DOMAIN variable missing in .env. Re-run set_env.sh."
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
# --- Volume Path Resolution ---
|
|
resolve_volume_path() {
|
|
VOLUME_PATH="${VOLUME_PATH:-./matrix}"
|
|
if [[ "$VOLUME_PATH" != /* ]]; then
|
|
VOLUME_PATH="${ROOT_DIR}/${VOLUME_PATH}"
|
|
fi
|
|
export VOLUME_PATH
|
|
}
|
|
|
|
# Add to functions.sh
|
|
|
|
|
|
quiet_echo() {
|
|
[[ "${QUIET_MODE:-0}" == "1" ]] || echo "$1"
|
|
}
|