mirror of
https://github.com/uprightbass360/AzerothCore-RealmMaster.git
synced 2026-01-13 09:07:20 +00:00
refactor: reorganize scripts under bash/python
This commit is contained in:
621
scripts/bash/manage-modules.sh
Executable file
621
scripts/bash/manage-modules.sh
Executable file
@@ -0,0 +1,621 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Manifest-driven module management. Stages repositories, applies module
|
||||
# metadata hooks, manages configuration files, and flags rebuild requirements.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
MODULE_HELPER="$SCRIPT_DIR/modules.py"
|
||||
DEFAULT_ENV_PATH="$PROJECT_ROOT/.env"
|
||||
ENV_PATH="${MODULES_ENV_PATH:-$DEFAULT_ENV_PATH}"
|
||||
TEMPLATE_FILE="$PROJECT_ROOT/.env.template"
|
||||
source "$PROJECT_ROOT/scripts/bash/project_name.sh"
|
||||
|
||||
# Default project name (read from .env or template)
|
||||
DEFAULT_PROJECT_NAME="$(project_name::resolve "$ENV_PATH" "$TEMPLATE_FILE")"
|
||||
|
||||
BLUE='\033[0;34m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; NC='\033[0m'
|
||||
PLAYERBOTS_DB_UPDATE_LOGGED=0
|
||||
info(){ printf '%b\n' "${BLUE}ℹ️ $*${NC}"; }
|
||||
ok(){ printf '%b\n' "${GREEN}✅ $*${NC}"; }
|
||||
warn(){ printf '%b\n' "${YELLOW}⚠️ $*${NC}"; }
|
||||
err(){ printf '%b\n' "${RED}❌ $*${NC}"; exit 1; }
|
||||
|
||||
# Declare module metadata arrays globally at script level
|
||||
declare -A MODULE_NAME MODULE_REPO MODULE_REF MODULE_TYPE MODULE_ENABLED MODULE_NEEDS_BUILD MODULE_BLOCKED MODULE_POST_INSTALL MODULE_REQUIRES MODULE_CONFIG_CLEANUP MODULE_NOTES MODULE_STATUS MODULE_BLOCK_REASON
|
||||
declare -a MODULE_KEYS
|
||||
|
||||
read_env_value(){
|
||||
local key="$1" default="${2:-}" value="${!key:-}"
|
||||
if [ -n "$value" ]; then
|
||||
echo "$value"
|
||||
return
|
||||
fi
|
||||
if [ -f "$ENV_PATH" ]; then
|
||||
value="$(grep -E "^${key}=" "$ENV_PATH" 2>/dev/null | tail -n1 | cut -d'=' -f2- | tr -d '\r')"
|
||||
value="$(echo "$value" | sed 's/[[:space:]]*#.*//' | sed 's/[[:space:]]*$//')"
|
||||
if [[ "$value" == \"*\" && "$value" == *\" ]]; then
|
||||
value="${value:1:-1}"
|
||||
elif [[ "$value" == \'*\' && "$value" == *\' ]]; then
|
||||
value="${value:1:-1}"
|
||||
fi
|
||||
fi
|
||||
if [ -z "${value:-}" ]; then
|
||||
value="$default"
|
||||
fi
|
||||
printf '%s\n' "${value}"
|
||||
}
|
||||
|
||||
ensure_python(){
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
err "python3 is required but not installed in PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
resolve_manifest_path(){
|
||||
if [ -n "${MODULES_MANIFEST_PATH:-}" ] && [ -f "${MODULES_MANIFEST_PATH}" ]; then
|
||||
echo "${MODULES_MANIFEST_PATH}"
|
||||
return
|
||||
fi
|
||||
local candidate
|
||||
candidate="$PROJECT_ROOT/config/module-manifest.json"
|
||||
if [ -f "$candidate" ]; then
|
||||
echo "$candidate"
|
||||
return
|
||||
fi
|
||||
candidate="$SCRIPT_DIR/../config/module-manifest.json"
|
||||
if [ -f "$candidate" ]; then
|
||||
echo "$candidate"
|
||||
return
|
||||
fi
|
||||
candidate="/tmp/config/module-manifest.json"
|
||||
if [ -f "$candidate" ]; then
|
||||
echo "$candidate"
|
||||
return
|
||||
fi
|
||||
err "Unable to locate module manifest (set MODULES_MANIFEST_PATH or ensure config/module-manifest.json exists)"
|
||||
}
|
||||
|
||||
setup_git_config(){
|
||||
info "Configuring git identity"
|
||||
git config --global user.name "${GIT_USERNAME:-$DEFAULT_PROJECT_NAME}" >/dev/null 2>&1 || true
|
||||
git config --global user.email "${GIT_EMAIL:-noreply@azerothcore.org}" >/dev/null 2>&1 || true
|
||||
}
|
||||
|
||||
generate_module_state(){
|
||||
mkdir -p "$STATE_DIR"
|
||||
if ! python3 "$MODULE_HELPER" --env-path "$ENV_PATH" --manifest "$MANIFEST_PATH" generate --output-dir "$STATE_DIR"; then
|
||||
err "Module manifest validation failed"
|
||||
fi
|
||||
local env_file="$STATE_DIR/modules.env"
|
||||
if [ ! -f "$env_file" ]; then
|
||||
err "modules.env not produced at $env_file"
|
||||
fi
|
||||
# shellcheck disable=SC1090
|
||||
source "$env_file"
|
||||
|
||||
# Module arrays are already declared at script level
|
||||
if ! MODULE_SHELL_STATE="$(python3 "$MODULE_HELPER" --env-path "$ENV_PATH" --manifest "$MANIFEST_PATH" dump --format shell)"; then
|
||||
err "Unable to load manifest metadata"
|
||||
fi
|
||||
local eval_script
|
||||
# Remove the declare line since we already declared the arrays
|
||||
eval_script="$(echo "$MODULE_SHELL_STATE" | sed '/^declare -A /d')"
|
||||
eval "$eval_script"
|
||||
IFS=' ' read -r -a MODULES_COMPILE_LIST <<< "${MODULES_COMPILE:-}"
|
||||
if [ "${#MODULES_COMPILE_LIST[@]}" -eq 1 ] && [ -z "${MODULES_COMPILE_LIST[0]}" ]; then
|
||||
MODULES_COMPILE_LIST=()
|
||||
fi
|
||||
}
|
||||
|
||||
remove_disabled_modules(){
|
||||
for key in "${MODULE_KEYS[@]}"; do
|
||||
local dir
|
||||
dir="${MODULE_NAME[$key]:-}"
|
||||
[ -n "$dir" ] || continue
|
||||
if [ "${MODULE_ENABLED[$key]:-0}" != "1" ] && [ -d "$dir" ]; then
|
||||
info "Removing ${dir} (disabled)"
|
||||
rm -rf "$dir"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
run_post_install_hooks(){
|
||||
local key="$1"
|
||||
local dir="$2"
|
||||
local hooks_csv="${MODULE_POST_INSTALL[$key]:-}"
|
||||
|
||||
# Skip if no hooks defined
|
||||
[ -n "$hooks_csv" ] || return 0
|
||||
|
||||
IFS=',' read -r -a hooks <<< "$hooks_csv"
|
||||
local -a hook_search_paths=(
|
||||
"$SCRIPT_DIR/hooks"
|
||||
"/tmp/scripts/hooks"
|
||||
"/scripts/hooks"
|
||||
)
|
||||
|
||||
for hook in "${hooks[@]}"; do
|
||||
[ -n "$hook" ] || continue
|
||||
|
||||
# Trim whitespace
|
||||
hook="$(echo "$hook" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')"
|
||||
|
||||
local hook_script=""
|
||||
local candidate
|
||||
for candidate in "${hook_search_paths[@]}"; do
|
||||
if [ -x "$candidate/$hook" ]; then
|
||||
hook_script="$candidate/$hook"
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -n "$hook_script" ]; then
|
||||
info "Running post-install hook: $hook"
|
||||
|
||||
# Set hook environment variables
|
||||
export MODULE_KEY="$key"
|
||||
export MODULE_DIR="$dir"
|
||||
export MODULE_NAME="${MODULE_NAME[$key]:-$(basename "$dir")}"
|
||||
export MODULES_ROOT="${MODULES_ROOT:-/modules}"
|
||||
export LUA_SCRIPTS_TARGET="/azerothcore/lua_scripts"
|
||||
|
||||
# Execute the hook script
|
||||
if "$hook_script"; then
|
||||
ok "Hook '$hook' completed successfully"
|
||||
else
|
||||
local exit_code=$?
|
||||
case $exit_code in
|
||||
1) warn "Hook '$hook' completed with warnings" ;;
|
||||
*) err "Hook '$hook' failed with exit code $exit_code" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Clean up hook-specific environment (preserve MODULE_NAME array and script-level MODULES_ROOT)
|
||||
unset MODULE_KEY MODULE_DIR LUA_SCRIPTS_TARGET
|
||||
else
|
||||
err "Hook script not found for ${hook} (searched: ${hook_search_paths[*]})"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
install_enabled_modules(){
|
||||
for key in "${MODULE_KEYS[@]}"; do
|
||||
if [ "${MODULE_ENABLED[$key]:-0}" != "1" ]; then
|
||||
continue
|
||||
fi
|
||||
local dir repo ref
|
||||
dir="${MODULE_NAME[$key]:-}"
|
||||
repo="${MODULE_REPO[$key]:-}"
|
||||
ref="${MODULE_REF[$key]:-}"
|
||||
if [ -z "$dir" ] || [ -z "$repo" ]; then
|
||||
warn "Missing repository metadata for $key"
|
||||
continue
|
||||
fi
|
||||
if [ -d "$dir/.git" ]; then
|
||||
info "$dir already present; skipping clone"
|
||||
elif [ -d "$dir" ]; then
|
||||
warn "$dir exists but is not a git repository; leaving in place"
|
||||
else
|
||||
info "Cloning ${dir} from ${repo}"
|
||||
if ! git clone "$repo" "$dir"; then
|
||||
err "Failed to clone $repo"
|
||||
fi
|
||||
if [ -n "$ref" ]; then
|
||||
(cd "$dir" && git checkout "$ref") || warn "Unable to checkout ref $ref for $dir"
|
||||
fi
|
||||
fi
|
||||
run_post_install_hooks "$key" "$dir"
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
update_playerbots_db_info(){
|
||||
local target="$1"
|
||||
if [ ! -f "$target" ] && [ ! -L "$target" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
local env_file="${ENV_PATH:-}"
|
||||
local resolved
|
||||
|
||||
resolved="$(
|
||||
python3 - "$target" "${env_file}" <<'PY'
|
||||
import os
|
||||
import pathlib
|
||||
import sys
|
||||
import re
|
||||
|
||||
def load_env_file(path):
|
||||
data = {}
|
||||
if not path:
|
||||
return data
|
||||
candidate = pathlib.Path(path)
|
||||
if not candidate.is_file():
|
||||
return data
|
||||
for raw in candidate.read_text(encoding="utf-8", errors="ignore").splitlines():
|
||||
if not raw or raw.lstrip().startswith("#"):
|
||||
continue
|
||||
if "=" not in raw:
|
||||
continue
|
||||
key, val = raw.split("=", 1)
|
||||
key = key.strip()
|
||||
val = val.strip()
|
||||
if not key:
|
||||
continue
|
||||
if val and val[0] == val[-1] and val[0] in {"'", '"'}:
|
||||
val = val[1:-1]
|
||||
if "#" in val:
|
||||
# Strip inline comments
|
||||
val = val.split("#", 1)[0].rstrip()
|
||||
data[key] = val
|
||||
return data
|
||||
|
||||
def resolve_key(env_map, key, default=""):
|
||||
value = os.environ.get(key)
|
||||
if value:
|
||||
return value
|
||||
return env_map.get(key, default)
|
||||
|
||||
def parse_bool(value):
|
||||
if value is None:
|
||||
return None
|
||||
value = value.strip().lower()
|
||||
if value == "":
|
||||
return None
|
||||
if value in {"1", "true", "yes", "on"}:
|
||||
return True
|
||||
if value in {"0", "false", "no", "off"}:
|
||||
return False
|
||||
return None
|
||||
|
||||
def parse_int(value):
|
||||
if value is None:
|
||||
return None
|
||||
value = value.strip()
|
||||
if not value:
|
||||
return None
|
||||
if re.fullmatch(r"[+-]?\d+", value):
|
||||
return str(int(value))
|
||||
return None
|
||||
|
||||
def update_config(path_in, settings):
|
||||
if not (os.path.exists(path_in) or os.path.islink(path_in)):
|
||||
return False
|
||||
path = os.path.realpath(path_in)
|
||||
try:
|
||||
with open(path, "r", encoding="utf-8", errors="ignore") as fh:
|
||||
lines = fh.read().splitlines()
|
||||
except FileNotFoundError:
|
||||
lines = []
|
||||
|
||||
changed = False
|
||||
pending = dict(settings)
|
||||
|
||||
for idx, raw in enumerate(lines):
|
||||
stripped = raw.strip()
|
||||
for key, value in list(pending.items()):
|
||||
if re.match(rf"^\s*{re.escape(key)}\s*=", stripped):
|
||||
desired = f"{key} = {value}"
|
||||
if stripped != desired:
|
||||
leading = raw[: len(raw) - len(raw.lstrip())]
|
||||
trailing = ""
|
||||
if "#" in raw:
|
||||
before, comment = raw.split("#", 1)
|
||||
if before.strip():
|
||||
trailing = f" # {comment.strip()}"
|
||||
lines[idx] = f"{leading}{desired}{trailing}"
|
||||
changed = True
|
||||
pending.pop(key, None)
|
||||
break
|
||||
|
||||
if pending:
|
||||
if lines and lines[-1] and not lines[-1].endswith("\n"):
|
||||
lines[-1] = lines[-1] + "\n"
|
||||
if lines and lines[-1].strip():
|
||||
lines.append("\n")
|
||||
for key, value in pending.items():
|
||||
lines.append(f"{key} = {value}\n")
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
output = "\n".join(lines)
|
||||
if output and not output.endswith("\n"):
|
||||
output += "\n"
|
||||
with open(path, "w", encoding="utf-8") as fh:
|
||||
fh.write(output)
|
||||
|
||||
return True
|
||||
|
||||
target_path, env_path = sys.argv[1:3]
|
||||
env_map = load_env_file(env_path)
|
||||
|
||||
host = resolve_key(env_map, "CONTAINER_MYSQL") or resolve_key(env_map, "MYSQL_HOST", "ac-mysql") or "ac-mysql"
|
||||
port = resolve_key(env_map, "MYSQL_PORT", "3306") or "3306"
|
||||
user = resolve_key(env_map, "MYSQL_USER", "root") or "root"
|
||||
password = resolve_key(env_map, "MYSQL_ROOT_PASSWORD", "")
|
||||
database = resolve_key(env_map, "DB_PLAYERBOTS_NAME", "acore_playerbots") or "acore_playerbots"
|
||||
|
||||
value = ";".join([host, port, user, password, database])
|
||||
settings = {"PlayerbotsDatabaseInfo": f'"{value}"'}
|
||||
|
||||
enabled_setting = parse_bool(resolve_key(env_map, "PLAYERBOT_ENABLED"))
|
||||
if enabled_setting is not None:
|
||||
settings["AiPlayerbot.Enabled"] = "1" if enabled_setting else "0"
|
||||
|
||||
max_bots = parse_int(resolve_key(env_map, "PLAYERBOT_MAX_BOTS"))
|
||||
min_bots = parse_int(resolve_key(env_map, "PLAYERBOT_MIN_BOTS"))
|
||||
|
||||
if max_bots and not min_bots:
|
||||
min_bots = max_bots
|
||||
|
||||
if min_bots:
|
||||
settings["AiPlayerbot.MinRandomBots"] = min_bots
|
||||
if max_bots:
|
||||
settings["AiPlayerbot.MaxRandomBots"] = max_bots
|
||||
|
||||
update_config(target_path, settings)
|
||||
|
||||
print(value)
|
||||
PY
|
||||
)" || return 0
|
||||
|
||||
local host port
|
||||
host="${resolved%%;*}"
|
||||
port="${resolved#*;}"
|
||||
port="${port%%;*}"
|
||||
|
||||
if [ "$PLAYERBOTS_DB_UPDATE_LOGGED" = "0" ]; then
|
||||
info "Updated PlayerbotsDatabaseInfo to use host ${host}:${port}"
|
||||
PLAYERBOTS_DB_UPDATE_LOGGED=1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
manage_configuration_files(){
|
||||
echo 'Managing configuration files...'
|
||||
|
||||
local env_target="${MODULES_ENV_TARGET_DIR:-}"
|
||||
if [ -z "$env_target" ]; then
|
||||
if [ "${MODULES_LOCAL_RUN:-0}" = "1" ]; then
|
||||
env_target="${MODULES_ROOT}/env/dist/etc"
|
||||
else
|
||||
env_target="/azerothcore/env/dist/etc"
|
||||
fi
|
||||
fi
|
||||
|
||||
mkdir -p "$env_target"
|
||||
|
||||
local key patterns_csv enabled pattern
|
||||
for key in "${MODULE_KEYS[@]}"; do
|
||||
enabled="${MODULE_ENABLED[$key]:-0}"
|
||||
patterns_csv="${MODULE_CONFIG_CLEANUP[$key]:-}"
|
||||
IFS=',' read -r -a patterns <<< "$patterns_csv"
|
||||
if [ "${#patterns[@]}" -eq 1 ] && [ -z "${patterns[0]}" ]; then
|
||||
unset patterns
|
||||
continue
|
||||
fi
|
||||
for pattern in "${patterns[@]}"; do
|
||||
[ -n "$pattern" ] || continue
|
||||
if [ "$enabled" != "1" ]; then
|
||||
rm -f "$env_target"/$pattern 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
unset patterns
|
||||
done
|
||||
|
||||
local modules_conf_dir="${env_target%/}/modules"
|
||||
mkdir -p "$modules_conf_dir"
|
||||
rm -rf "${modules_conf_dir}.backup"
|
||||
rm -f "$modules_conf_dir"/*.conf "$modules_conf_dir"/*.conf.dist 2>/dev/null || true
|
||||
|
||||
local module_dir
|
||||
for key in "${MODULE_KEYS[@]}"; do
|
||||
module_dir="${MODULE_NAME[$key]:-}"
|
||||
[ -n "$module_dir" ] || continue
|
||||
[ -d "$module_dir" ] || continue
|
||||
while IFS= read -r conf_file; do
|
||||
[ -n "$conf_file" ] || continue
|
||||
base_name="$(basename "$conf_file")"
|
||||
# Ensure previous copies in root config are removed to keep modules/ canonical
|
||||
main_conf_path="${env_target}/${base_name}"
|
||||
if [ -f "$main_conf_path" ]; then
|
||||
rm -f "$main_conf_path"
|
||||
fi
|
||||
if [[ "$base_name" == *.conf.dist ]]; then
|
||||
root_conf="${env_target}/${base_name%.dist}"
|
||||
if [ -f "$root_conf" ]; then
|
||||
rm -f "$root_conf"
|
||||
fi
|
||||
fi
|
||||
|
||||
dest_path="${modules_conf_dir}/${base_name}"
|
||||
cp "$conf_file" "$dest_path"
|
||||
if [[ "$base_name" == *.conf.dist ]]; then
|
||||
dest_conf="${modules_conf_dir}/${base_name%.dist}"
|
||||
if [ ! -f "$dest_conf" ]; then
|
||||
cp "$conf_file" "$dest_conf"
|
||||
fi
|
||||
fi
|
||||
done < <(find "$module_dir" -path "*/conf/*" -type f \( -name "*.conf" -o -name "*.conf.dist" \) 2>/dev/null)
|
||||
done
|
||||
|
||||
local playerbots_enabled="${MODULE_PLAYERBOTS:-0}"
|
||||
if [ "${MODULE_ENABLED[MODULE_PLAYERBOTS]:-0}" = "1" ]; then
|
||||
playerbots_enabled=1
|
||||
fi
|
||||
|
||||
if [ "$playerbots_enabled" = "1" ]; then
|
||||
update_playerbots_db_info "$modules_conf_dir/playerbots.conf"
|
||||
update_playerbots_db_info "$modules_conf_dir/playerbots.conf.dist"
|
||||
fi
|
||||
|
||||
if [ "${MODULE_AUTOBALANCE:-0}" = "1" ] && [ -f "$env_target/AutoBalance.conf.dist" ]; then
|
||||
sed -i 's/^AutoBalance\.LevelScaling\.EndGameBoost.*/AutoBalance.LevelScaling.EndGameBoost = false # disabled pending proper implementation/' \
|
||||
"$env_target/AutoBalance.conf.dist" || true
|
||||
fi
|
||||
}
|
||||
|
||||
load_sql_helper(){
|
||||
local helper_paths=(
|
||||
"/scripts/bash/manage-modules-sql.sh"
|
||||
"/tmp/scripts/bash/manage-modules-sql.sh"
|
||||
)
|
||||
|
||||
if [ "${MODULES_LOCAL_RUN:-0}" = "1" ]; then
|
||||
helper_paths+=("$SCRIPT_DIR/manage-modules-sql.sh")
|
||||
fi
|
||||
|
||||
local helper_path=""
|
||||
for helper_path in "${helper_paths[@]}"; do
|
||||
if [ -f "$helper_path" ]; then
|
||||
# shellcheck disable=SC1090
|
||||
. "$helper_path"
|
||||
SQL_HELPER_PATH="$helper_path"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
err "SQL helper not found; expected manage-modules-sql.sh to be available"
|
||||
}
|
||||
|
||||
execute_module_sql(){
|
||||
SQL_EXECUTION_FAILED=0
|
||||
if declare -f execute_module_sql_scripts >/dev/null 2>&1; then
|
||||
echo 'Executing module SQL scripts...'
|
||||
if execute_module_sql_scripts; then
|
||||
echo 'SQL execution complete.'
|
||||
else
|
||||
echo '⚠️ Module SQL scripts reported errors'
|
||||
SQL_EXECUTION_FAILED=1
|
||||
fi
|
||||
else
|
||||
info "SQL helper did not expose execute_module_sql_scripts; skipping module SQL execution"
|
||||
fi
|
||||
}
|
||||
|
||||
track_module_state(){
|
||||
echo 'Checking for module changes that require rebuild...'
|
||||
|
||||
local modules_state_file
|
||||
if [ "${MODULES_LOCAL_RUN:-0}" = "1" ]; then
|
||||
modules_state_file="./.modules_state"
|
||||
else
|
||||
modules_state_file="/modules/.modules_state"
|
||||
fi
|
||||
|
||||
local current_state=""
|
||||
for key in "${MODULE_KEYS[@]}"; do
|
||||
current_state+="${key}=${MODULE_ENABLED[$key]:-0}|"
|
||||
done
|
||||
|
||||
local previous_state=""
|
||||
if [ -f "$modules_state_file" ]; then
|
||||
previous_state="$(cat "$modules_state_file")"
|
||||
fi
|
||||
|
||||
local rebuild_required=0
|
||||
if [ "$current_state" != "$previous_state" ]; then
|
||||
if [ -n "$previous_state" ]; then
|
||||
echo "🔄 Module configuration has changed - rebuild required"
|
||||
else
|
||||
echo "📝 First run - establishing module state baseline"
|
||||
fi
|
||||
rebuild_required=1
|
||||
else
|
||||
echo "✅ No module changes detected"
|
||||
fi
|
||||
|
||||
echo "$current_state" > "$modules_state_file"
|
||||
|
||||
if [ "${#MODULES_COMPILE_LIST[@]}" -gt 0 ]; then
|
||||
echo "🔧 Detected ${#MODULES_COMPILE_LIST[@]} enabled C++ modules requiring compilation:"
|
||||
for mod in "${MODULES_COMPILE_LIST[@]}"; do
|
||||
echo " • $mod"
|
||||
done
|
||||
else
|
||||
echo "✅ No C++ modules enabled - pre-built containers can be used"
|
||||
fi
|
||||
|
||||
local rebuild_sentinel
|
||||
if [ "${MODULES_LOCAL_RUN:-0}" = "1" ]; then
|
||||
if [ -n "${LOCAL_STORAGE_SENTINEL_PATH:-}" ]; then
|
||||
rebuild_sentinel="${LOCAL_STORAGE_SENTINEL_PATH}"
|
||||
else
|
||||
rebuild_sentinel="./.requires_rebuild"
|
||||
fi
|
||||
else
|
||||
rebuild_sentinel="/modules/.requires_rebuild"
|
||||
fi
|
||||
|
||||
local host_rebuild_sentinel=""
|
||||
if [ -n "${MODULES_HOST_DIR:-}" ]; then
|
||||
host_rebuild_sentinel="${MODULES_HOST_DIR%/}/.requires_rebuild"
|
||||
fi
|
||||
|
||||
if [ "$rebuild_required" = "1" ] && [ "${#MODULES_COMPILE_LIST[@]}" -gt 0 ]; then
|
||||
printf '%s\n' "${MODULES_COMPILE_LIST[@]}" > "$rebuild_sentinel"
|
||||
if [ -n "$host_rebuild_sentinel" ]; then
|
||||
printf '%s\n' "${MODULES_COMPILE_LIST[@]}" > "$host_rebuild_sentinel" 2>/dev/null || true
|
||||
fi
|
||||
echo "🚨 Module changes detected; run ./scripts/bash/rebuild-with-modules.sh to rebuild source images."
|
||||
else
|
||||
rm -f "$rebuild_sentinel" 2>/dev/null || true
|
||||
if [ -n "$host_rebuild_sentinel" ]; then
|
||||
rm -f "$host_rebuild_sentinel" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "${MODULES_LOCAL_RUN:-0}" = "1" ]; then
|
||||
local target_dir="${MODULES_HOST_DIR:-$(pwd)}"
|
||||
local desired_user
|
||||
desired_user="$(id -u):$(id -g)"
|
||||
if [ -d "$target_dir" ]; then
|
||||
chown -R "$desired_user" "$target_dir" >/dev/null 2>&1 || true
|
||||
chmod -R ug+rwX "$target_dir" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
main(){
|
||||
ensure_python
|
||||
|
||||
if [ "${MODULES_LOCAL_RUN:-0}" != "1" ]; then
|
||||
cd /modules || err "Modules directory /modules not found"
|
||||
fi
|
||||
MODULES_ROOT="$(pwd)"
|
||||
|
||||
MANIFEST_PATH="$(resolve_manifest_path)"
|
||||
STATE_DIR="${MODULES_HOST_DIR:-$MODULES_ROOT}"
|
||||
|
||||
setup_git_config
|
||||
generate_module_state
|
||||
remove_disabled_modules
|
||||
install_enabled_modules
|
||||
manage_configuration_files
|
||||
info "SQL execution gate: MODULES_SKIP_SQL=${MODULES_SKIP_SQL:-0}"
|
||||
if [ "${MODULES_SKIP_SQL:-0}" = "1" ]; then
|
||||
info "Skipping module SQL execution (MODULES_SKIP_SQL=1)"
|
||||
else
|
||||
info "Initiating module SQL helper"
|
||||
load_sql_helper
|
||||
info "SQL helper loaded from ${SQL_HELPER_PATH:-unknown}"
|
||||
execute_module_sql
|
||||
fi
|
||||
track_module_state
|
||||
|
||||
if [ "${SQL_EXECUTION_FAILED:-0}" = "1" ]; then
|
||||
warn "Module SQL execution reported issues; review logs above."
|
||||
fi
|
||||
|
||||
echo 'Module management complete.'
|
||||
|
||||
if [ "${MODULES_DEBUG_KEEPALIVE:-0}" = "1" ]; then
|
||||
tail -f /dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in New Issue
Block a user