135 lines
No EOL
2.9 KiB
Bash
135 lines
No EOL
2.9 KiB
Bash
#!/usr/bin/env bash
|
|
# core/hook.sh
|
|
#
|
|
# Lifecycle hook runner.
|
|
#
|
|
# Hooks are shell scripts sourced in lexicographic order from:
|
|
# dxkit/hooks/<command>/<timing>/
|
|
#
|
|
# Timing:
|
|
# pre — runs before the command's main logic
|
|
# post — runs after the command's main logic
|
|
#
|
|
# Naming convention:
|
|
# NN-description.sh (e.g. 10-permissions.sh, 20-update-cron.sh)
|
|
# Numeric prefix controls execution order.
|
|
#
|
|
# Hooks are sourced (not executed) so they have full access to all
|
|
# loaded modules, functions, and environment variables.
|
|
#
|
|
# Usage:
|
|
# hook::run init pre
|
|
# hook::run init post
|
|
# hook::run build post
|
|
#
|
|
# Example structure:
|
|
# dxkit/hooks/
|
|
# init/
|
|
# pre/
|
|
# 10-something.sh
|
|
# post/
|
|
# 10-permissions.sh
|
|
# 20-update-cron.sh
|
|
# build/
|
|
# post/
|
|
# 10-something.sh
|
|
|
|
# ============================================
|
|
# Runner
|
|
# ============================================
|
|
|
|
function hook::run() {
|
|
local command="$1"
|
|
local timing="$2"
|
|
|
|
local hook_dir
|
|
hook_dir="$(ctx::dxkit)/hooks/${command}/${timing}"
|
|
|
|
[[ -d "$hook_dir" ]] || return 0
|
|
|
|
local hooks
|
|
hooks="$(hook::_list "$hook_dir")"
|
|
|
|
[[ -z "$hooks" ]] && return 0
|
|
|
|
log::info "Running ${timing}-${command} hooks..."
|
|
|
|
local hook
|
|
while IFS= read -r hook; do
|
|
[[ -f "$hook" ]] || continue
|
|
hook::_run_one "$hook"
|
|
done <<< "$hooks"
|
|
}
|
|
|
|
# ============================================
|
|
# Run a single hook
|
|
# ============================================
|
|
|
|
function hook::_run_one() {
|
|
local hook="$1"
|
|
local name
|
|
name="$(basename "$hook")"
|
|
|
|
log::info " → ${name}"
|
|
|
|
# shellcheck disable=SC1090
|
|
source "$hook" || {
|
|
log::error "Hook failed: ${name}"
|
|
return 1
|
|
}
|
|
}
|
|
|
|
# ============================================
|
|
# List hooks in a directory sorted by name
|
|
# ============================================
|
|
|
|
function hook::_list() {
|
|
local dir="$1"
|
|
|
|
find "$dir" -maxdepth 1 -name "*.sh" -type f | sort
|
|
}
|
|
|
|
# ============================================
|
|
# Predicates
|
|
# ============================================
|
|
|
|
function hook::has() {
|
|
local command="$1"
|
|
local timing="$2"
|
|
|
|
local hook_dir
|
|
hook_dir="$(ctx::dxkit)/hooks/${command}/${timing}"
|
|
|
|
[[ -d "$hook_dir" ]] && [[ -n "$(hook::_list "$hook_dir")" ]]
|
|
}
|
|
|
|
# ============================================
|
|
# Scaffold hook directory and example file
|
|
# ============================================
|
|
|
|
function hook::scaffold() {
|
|
local command="$1"
|
|
local timing="${2:-post}"
|
|
|
|
local hook_dir
|
|
hook_dir="$(ctx::dxkit)/hooks/${command}/${timing}"
|
|
|
|
mkdir -p "$hook_dir"
|
|
|
|
local example="${hook_dir}/10-example.sh"
|
|
[[ -f "$example" ]] && return 0
|
|
|
|
cat > "$example" <<EOF
|
|
#!/usr/bin/env bash
|
|
# ${timing}-${command} hook: 10-example.sh
|
|
#
|
|
# This hook runs ${timing} dx ${command}.
|
|
# All modules and environment variables are available.
|
|
#
|
|
# Remove or rename this file when adding real hooks.
|
|
|
|
# log::info "Running example ${timing}-${command} hook..."
|
|
EOF
|
|
|
|
log::info "Scaffolded hook: ${example}"
|
|
} |