122 lines
No EOL
2.8 KiB
Bash
122 lines
No EOL
2.8 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
function require_file() {
|
|
[[ -f "$1" ]]
|
|
}
|
|
function require_directory() {
|
|
[[ -d "$1" ]]
|
|
}
|
|
|
|
function load_file() {
|
|
local mode="required"
|
|
local file
|
|
|
|
# Check if first argument is a mode
|
|
if [[ "$1" == "required" || "$1" == "optional" ]]; then
|
|
mode="$1"
|
|
shift
|
|
fi
|
|
|
|
file="$1"
|
|
|
|
if [[ "$mode" == "required" && ! -f "$file" ]]; then
|
|
echo "❌ Missing file: $file" >&2
|
|
return 1
|
|
fi
|
|
|
|
# Source if file exists
|
|
if [[ -f "$file" ]]; then
|
|
source "$file"
|
|
fi
|
|
}
|
|
|
|
# ============================================
|
|
# load_module — Loads $(ctx::modules)/<name>.module.sh
|
|
# Always required.
|
|
# ============================================
|
|
function load_module() {
|
|
local name="$1"
|
|
|
|
# Wildcard: Load all submodules
|
|
if [[ "$name" == *"/*" ]]; then
|
|
local dir="${name%/*}"
|
|
local module_dir
|
|
module_dir="$(ctx::modules)/${dir}"
|
|
|
|
if [[ ! -d "$module_dir" ]]; then
|
|
log::error "Module directory not found: ${dir}"
|
|
return 1
|
|
fi
|
|
|
|
for file in "${module_dir}"/*.module.sh; do
|
|
[[ -f "$file" ]] || continue
|
|
local subname="${dir}/$(basename "${file%.module.sh}")"
|
|
load_module "$subname"
|
|
done
|
|
|
|
return 0
|
|
fi
|
|
|
|
# Normal single module load
|
|
local file
|
|
file="$(ctx::modules)/${name}.module.sh"
|
|
|
|
module::loaded "$name" && return 0
|
|
|
|
if [[ ! -f "$file" ]]; then
|
|
log::error "Module not found: ${name}"
|
|
return 1
|
|
fi
|
|
|
|
source "$file"
|
|
_LOADED_MODULES["$name"]=1
|
|
|
|
core::call_if_exists "$(module::to_namespace "$name")::on_load"
|
|
}
|
|
|
|
# ============================================
|
|
# load_command — Loads $(ctx::commands)/<name>.command.sh
|
|
#
|
|
# Returns:
|
|
# 0 — file found and sourced
|
|
# 1 — file not found (caller decides how to handle)
|
|
#
|
|
# After sourcing, does NOT validate ::run here —
|
|
# that's the dispatcher's job, keeping this function
|
|
# a clean "did the file exist?" predicate.
|
|
# ============================================
|
|
function load_command() {
|
|
local name="$1"
|
|
local file
|
|
file="$(ctx::commands)/${name}.command.sh"
|
|
|
|
if [[ ! -f "$file" ]]; then
|
|
return 1 # No command file, not an error by itself
|
|
fi
|
|
|
|
source "$file"
|
|
_LOADED_COMMANDS["$name"]=1
|
|
|
|
core::call_if_exists "$(command::fn "$name" on_load)"
|
|
# core::call_if_exists "$(command::to_namespace "$name")::on_load"
|
|
|
|
return 0
|
|
}
|
|
|
|
# ============================================
|
|
# load_command_strict — Load + assert ::run exists
|
|
# ============================================
|
|
function load_command_strict() {
|
|
local name="$1"
|
|
|
|
if ! load_command "$name"; then
|
|
echo "❌ No command file found for: '${name}'" >&2
|
|
return 1
|
|
fi
|
|
|
|
if ! core::function_exists "${name}::run"; then
|
|
echo "❌ Command '${name}' loaded but '${name}::run' is not defined" >&2
|
|
echo " Expected function: ${name}::run()" >&2
|
|
return 1
|
|
fi
|
|
} |