Files
ServerStack/lib/loader.sh
T
condor 679e0b4184 init
2026-07-24 18:54:53 +08:00

74 lines
3.3 KiB
Bash

#!/bin/bash
# lib/loader.sh - common header loading and module sourcing utilities.
#
# Centralises the "public header" that every entry script used to repeat, and
# provides guarded, consistent module sourcing so all modules are referenced by
# their project-root-relative path (e.g. "modules/web/nginx.sh", "lib/color.sh").
# Guard set of already-sourced modules (prevents double-sourcing side effects,
# e.g. init_*.sh which execute at top level).
# Resolve the project root from this file's own location. This makes every
# sourced path absolute and cwd-independent, fixing "No such file or directory"
# when the entry script is invoked from a directory other than the project root.
# readlink -f canonicalises to an absolute path (symlink/cwd safe); the fallback
# keeps it working on systems without readlink -f. loader.sh always lives at
# <root>/lib/loader.sh, so <root> = dirname(dirname(this_file)).
_ONEINSTACK_THIS="$(readlink -f "${BASH_SOURCE[0]}" 2>/dev/null || echo "${BASH_SOURCE[0]}")"
_ONEINSTACK_LIB_DIR="$(cd "$(dirname "${_ONEINSTACK_THIS}")" && pwd)"
oneinstack_dir="$(cd "${_ONEINSTACK_LIB_DIR}/.." && pwd)"
export oneinstack_dir
_LOADED_MODULES=""
# Source a module file exactly once.
# $1 = module path relative to the project root (e.g. "modules/web/nginx.sh")
source_module() {
local mod="$1"
local path="${oneinstack_dir:-.}/${mod}"
case ";${_LOADED_MODULES};" in
*";${mod};"*) return 0 ;;
esac
[ -f "${path}" ] || { echo "${CFAILURE}ERROR: module not found: ${mod}${CEND}" >&2; return 1; }
. "${path}" || return 1
_LOADED_MODULES="${_LOADED_MODULES};${mod}"
}
# Load the common header exactly as the legacy top of install.sh did:
# config/versions.txt, config/options.conf, color, check_os, check_dir, download, get_char
load_common() {
. "${oneinstack_dir}/config/versions.txt"
. "${oneinstack_dir}/config/options.conf"
. "${oneinstack_dir}/lib/color.sh"
. "${oneinstack_dir}/lib/check_os.sh"
. "${oneinstack_dir}/lib/check_dir.sh"
. "${oneinstack_dir}/lib/download.sh"
. "${oneinstack_dir}/lib/get_char.sh"
}
# Entry-point wrapper used by the workflow (see install.sh / workflow.sh).
load_configs() {
load_common
}
# Run a module's install function. Mirrors the legacy pattern
# . modules/X.sh; Func 2>&1 | tee -a runtime/install.log
# so every call site stays consistent (and is trivially de-duplicated).
#
# A visible "installing" banner is printed up front so the user always knows
# which component is being built/installed at any moment. This matters because
# the install runs many long compilations (nginx, php, mysql, ...) back-to-back;
# without a per-component header the screen just shows a wall of `make` output
# and it is impossible to tell what is currently running (or whether it hung).
# ${func} 2>&1 | tee -a ... keeps the real build output on screen AND in the log,
# so nothing is silent.
run_install() {
local module="$1" func="$2"
echo ""
echo "${CMSG}================================================================${CEND}"
echo "${CMSG}>> Installing: ${func}${CEND}"
echo "${CMSG} (module: ${module})${CEND}"
echo "${CMSG}================================================================${CEND}"
. "${module}" || { echo "${CFAILURE}ERROR: failed to load ${module}${CEND}" >&2; return 1; }
${func} 2>&1 | tee -a "${oneinstack_dir}/runtime/install.log"
}