mirror of
https://github.com/uprightbass360/AzerothCore-RealmMaster.git
synced 2026-01-13 00:58:34 +00:00
feat: add mysql exposure toggle and client data bind
This commit is contained in:
@@ -5,8 +5,9 @@
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.."
|
||||
COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
|
||||
DEFAULT_COMPOSE_FILE="$ROOT_DIR/docker-compose.yml"
|
||||
ENV_FILE="$ROOT_DIR/.env"
|
||||
declare -a COMPOSE_FILE_ARGS=()
|
||||
|
||||
BLUE='\033[0;34m'
|
||||
GREEN='\033[0;32m'
|
||||
@@ -44,8 +45,22 @@ resolve_project_name(){
|
||||
echo "$sanitized"
|
||||
}
|
||||
|
||||
init_compose_files(){
|
||||
COMPOSE_FILE_ARGS=(-f "$DEFAULT_COMPOSE_FILE")
|
||||
if [ "$(read_env MYSQL_EXPOSE_PORT "0")" = "1" ]; then
|
||||
local extra_file="$ROOT_DIR/docker-compose.mysql-expose.yml"
|
||||
if [ -f "$extra_file" ]; then
|
||||
COMPOSE_FILE_ARGS+=(-f "$extra_file")
|
||||
else
|
||||
warn "MYSQL_EXPOSE_PORT=1 but $extra_file missing; skipping port override."
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
init_compose_files
|
||||
|
||||
compose(){
|
||||
docker compose --project-name "$PROJECT_NAME" -f "$COMPOSE_FILE" "$@"
|
||||
docker compose --project-name "$PROJECT_NAME" "${COMPOSE_FILE_ARGS[@]}" "$@"
|
||||
}
|
||||
|
||||
show_header(){
|
||||
|
||||
85
scripts/detect-client-data-version.sh
Executable file
85
scripts/detect-client-data-version.sh
Executable file
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# Detect which wowgaming/client-data release an AzerothCore checkout expects.
|
||||
# Currently inspects apps/installer/includes/functions.sh for the
|
||||
# inst_download_client_data version marker, but can be extended with new
|
||||
# heuristics if needed.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
print_usage() {
|
||||
cat <<'EOF'
|
||||
Usage: scripts/detect-client-data-version.sh [--no-header] <repo-path> [...]
|
||||
|
||||
Outputs a tab-separated list of repository path, raw version token found in the
|
||||
source tree, and a normalized CLIENT_DATA_VERSION (e.g., v18).
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ "${1:-}" == "--help" ]]; then
|
||||
print_usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
show_header=1
|
||||
if [[ "${1:-}" == "--no-header" ]]; then
|
||||
show_header=0
|
||||
shift
|
||||
fi
|
||||
|
||||
if [[ $# -lt 1 ]]; then
|
||||
print_usage >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
normalize_version() {
|
||||
local token="$1"
|
||||
token="${token//$'\r'/}"
|
||||
token="${token//\"/}"
|
||||
token="${token//\'/}"
|
||||
token="${token// /}"
|
||||
token="${token%%#*}"
|
||||
token="${token%%;*}"
|
||||
token="${token%%\)*}"
|
||||
token="${token%%\}*}"
|
||||
echo "$token"
|
||||
}
|
||||
|
||||
detect_from_installer() {
|
||||
local repo_path="$1"
|
||||
local installer_file="$repo_path/apps/installer/includes/functions.sh"
|
||||
[[ -f "$installer_file" ]] || return 1
|
||||
local raw
|
||||
raw="$(grep -E 'local[[:space:]]+VERSION=' "$installer_file" | head -n1 | cut -d'=' -f2-)"
|
||||
[[ -n "$raw" ]] || return 1
|
||||
echo "$raw"
|
||||
}
|
||||
|
||||
detect_version() {
|
||||
local repo_path="$1"
|
||||
if [[ ! -d "$repo_path" ]]; then
|
||||
printf '%s\t%s\t%s\n' "$repo_path" "<missing>" "<unknown>"
|
||||
return
|
||||
fi
|
||||
|
||||
local raw=""
|
||||
if raw="$(detect_from_installer "$repo_path")"; then
|
||||
:
|
||||
elif [[ -f "$repo_path/.env" ]]; then
|
||||
raw="$(grep -E '^CLIENT_DATA_VERSION=' "$repo_path/.env" | head -n1 | cut -d'=' -f2-)"
|
||||
fi
|
||||
|
||||
if [[ -z "$raw" ]]; then
|
||||
printf '%s\t%s\t%s\n' "$repo_path" "<unknown>" "<unknown>"
|
||||
return
|
||||
fi
|
||||
|
||||
local normalized
|
||||
normalized="$(normalize_version "$raw")"
|
||||
printf '%s\t%s\t%s\n' "$repo_path" "$raw" "$normalized"
|
||||
}
|
||||
|
||||
[[ "$show_header" -eq 0 ]] || printf 'repo\traw\tclient_data_version\n'
|
||||
for repo in "$@"; do
|
||||
detect_version "$repo"
|
||||
done
|
||||
@@ -131,9 +131,10 @@ class ModuleCollectionState:
|
||||
def requires_playerbot_source(self) -> bool:
|
||||
module_map = {m.key: m for m in self.modules}
|
||||
playerbots_enabled = module_map.get("MODULE_PLAYERBOTS")
|
||||
playerbots = bool(playerbots_enabled and playerbots_enabled.enabled_effective)
|
||||
needs_cpp = any(module.needs_build and module.enabled_effective for module in self.modules)
|
||||
return playerbots or needs_cpp
|
||||
return bool(playerbots_enabled and playerbots_enabled.enabled_effective)
|
||||
|
||||
def requires_custom_build(self) -> bool:
|
||||
return any(module.needs_build and module.enabled_effective for module in self.modules)
|
||||
|
||||
|
||||
def build_state(env_path: Path, manifest_path: Path) -> ModuleCollectionState:
|
||||
@@ -150,8 +151,12 @@ def build_state(env_path: Path, manifest_path: Path) -> ModuleCollectionState:
|
||||
key = entry["key"]
|
||||
name = entry["name"]
|
||||
repo = entry["repo"]
|
||||
needs_build = bool(entry.get("needs_build", False))
|
||||
module_type = str(entry.get("type", "cpp"))
|
||||
needs_build_flag = entry.get("needs_build")
|
||||
if needs_build_flag is None:
|
||||
needs_build = module_type.lower() == "cpp"
|
||||
else:
|
||||
needs_build = bool(needs_build_flag)
|
||||
requires = entry.get("requires") or []
|
||||
if not isinstance(requires, list):
|
||||
raise ValueError(f"Manifest entry {key} has non-list 'requires'")
|
||||
@@ -263,20 +268,30 @@ def write_outputs(state: ModuleCollectionState, output_dir: Path) -> None:
|
||||
|
||||
enabled_names: List[str] = []
|
||||
compile_names: List[str] = []
|
||||
enabled_keys: List[str] = []
|
||||
compile_keys: List[str] = []
|
||||
|
||||
for module in state.modules:
|
||||
env_lines.append(f"export {module.key}={module.value}")
|
||||
if module.enabled_effective:
|
||||
enabled_names.append(module.name)
|
||||
enabled_keys.append(module.key)
|
||||
if module.enabled_effective and module.needs_build:
|
||||
compile_names.append(module.name)
|
||||
compile_keys.append(module.key)
|
||||
|
||||
env_lines.append(f'export MODULES_ENABLED="{ " ".join(enabled_names) }"'.rstrip())
|
||||
env_lines.append(f'export MODULES_COMPILE="{ " ".join(compile_names) }"'.rstrip())
|
||||
env_lines.append(f'export MODULES_ENABLED_LIST="{",".join(enabled_keys)}"')
|
||||
env_lines.append(f'export MODULES_CPP_LIST="{",".join(compile_keys)}"')
|
||||
env_lines.append(
|
||||
f"export MODULES_REQUIRES_PLAYERBOT_SOURCE="
|
||||
f'{"1" if state.requires_playerbot_source() else "0"}'
|
||||
)
|
||||
env_lines.append(
|
||||
f"export MODULES_REQUIRES_CUSTOM_BUILD="
|
||||
f'{"1" if state.requires_custom_build() else "0"}'
|
||||
)
|
||||
env_lines.append(f"export MODULES_WARNING_COUNT={len(state.warnings)}")
|
||||
env_lines.append(f"export MODULES_ERROR_COUNT={len(state.errors)}")
|
||||
|
||||
@@ -301,6 +316,7 @@ def write_outputs(state: ModuleCollectionState, output_dir: Path) -> None:
|
||||
"enabled_modules": [module.name for module in state.enabled_modules()],
|
||||
"compile_modules": [module.name for module in state.compile_modules()],
|
||||
"requires_playerbot_source": state.requires_playerbot_source(),
|
||||
"requires_custom_build": state.requires_custom_build(),
|
||||
}
|
||||
|
||||
modules_state_path = output_dir / "modules-state.json"
|
||||
@@ -342,6 +358,11 @@ def print_requires_playerbot(state: ModuleCollectionState) -> None:
|
||||
print("1" if state.requires_playerbot_source() else "0")
|
||||
|
||||
|
||||
|
||||
def print_requires_custom_build(state: ModuleCollectionState) -> None:
|
||||
print("1" if state.requires_custom_build() else "0")
|
||||
|
||||
|
||||
def print_state(state: ModuleCollectionState, fmt: str) -> None:
|
||||
payload = {
|
||||
"generated_at": state.generated_at.isoformat(),
|
||||
@@ -485,6 +506,18 @@ def configure_parser() -> argparse.ArgumentParser:
|
||||
|
||||
rps_parser.set_defaults(func=handle_requires_playerbot)
|
||||
|
||||
rcb_parser = subparsers.add_parser(
|
||||
"requires-custom-build",
|
||||
help="Print 1 if a custom source build is required else 0",
|
||||
)
|
||||
|
||||
def handle_requires_custom_build(args: argparse.Namespace) -> int:
|
||||
state = build_state(Path(args.env_path).resolve(), Path(args.manifest).resolve())
|
||||
print_requires_custom_build(state)
|
||||
return 1 if state.errors else 0
|
||||
|
||||
rcb_parser.set_defaults(func=handle_requires_custom_build)
|
||||
|
||||
dump_parser = subparsers.add_parser("dump", help="Dump module state (JSON format)")
|
||||
dump_parser.add_argument(
|
||||
"--format",
|
||||
|
||||
@@ -79,4 +79,18 @@ for path in /var/lib/mysql-runtime /var/lib/mysql /var/lib/mysql-persistent /bac
|
||||
fi
|
||||
done
|
||||
|
||||
disable_binlog="${MYSQL_DISABLE_BINLOG:-}"
|
||||
if [ "${disable_binlog}" = "1" ]; then
|
||||
add_skip_flag=1
|
||||
for arg in "$@"; do
|
||||
if [ "$arg" = "--skip-log-bin" ] || [[ "$arg" == --log-bin* ]]; then
|
||||
add_skip_flag=0
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ "$add_skip_flag" -eq 1 ]; then
|
||||
set -- "$@" --skip-log-bin
|
||||
fi
|
||||
fi
|
||||
|
||||
exec "$ORIGINAL_ENTRYPOINT" "$@"
|
||||
|
||||
@@ -14,36 +14,55 @@ PROJECT_ROOT="$(pwd)"
|
||||
|
||||
# Default values
|
||||
MODULE_PLAYERBOTS="${MODULE_PLAYERBOTS:-0}"
|
||||
NEEDS_CXX_REBUILD="${NEEDS_CXX_REBUILD:-0}"
|
||||
|
||||
COMPILE_MODULE_KEYS=(
|
||||
MODULE_AOE_LOOT MODULE_LEARN_SPELLS MODULE_FIREWORKS MODULE_INDIVIDUAL_PROGRESSION MODULE_AHBOT MODULE_AUTOBALANCE
|
||||
MODULE_TRANSMOG MODULE_NPC_BUFFER MODULE_DYNAMIC_XP MODULE_SOLO_LFG MODULE_1V1_ARENA MODULE_PHASED_DUELS
|
||||
MODULE_BREAKING_NEWS MODULE_BOSS_ANNOUNCER MODULE_ACCOUNT_ACHIEVEMENTS MODULE_AUTO_REVIVE MODULE_GAIN_HONOR_GUARD
|
||||
MODULE_TIME_IS_TIME MODULE_POCKET_PORTAL MODULE_RANDOM_ENCHANTS MODULE_SOLOCRAFT MODULE_PVP_TITLES MODULE_NPC_BEASTMASTER
|
||||
MODULE_NPC_ENCHANTER MODULE_INSTANCE_RESET MODULE_LEVEL_GRANT MODULE_ARAC MODULE_ASSISTANT MODULE_REAGENT_BANK
|
||||
MODULE_CHALLENGE_MODES MODULE_OLLAMA_CHAT MODULE_PLAYER_BOT_LEVEL_BRACKETS MODULE_STATBOOSTER MODULE_DUNGEON_RESPAWN
|
||||
MODULE_SKELETON_MODULE MODULE_BG_SLAVERYVALLEY MODULE_AZEROTHSHARD MODULE_WORGOBLIN
|
||||
)
|
||||
|
||||
if [ "$NEEDS_CXX_REBUILD" != "1" ]; then
|
||||
for key in "${COMPILE_MODULE_KEYS[@]}"; do
|
||||
if [ "${!key:-0}" = "1" ]; then
|
||||
NEEDS_CXX_REBUILD=1
|
||||
break
|
||||
PLAYERBOT_ENABLED="${PLAYERBOT_ENABLED:-0}"
|
||||
STACK_SOURCE_VARIANT="${STACK_SOURCE_VARIANT:-}"
|
||||
if [ -z "$STACK_SOURCE_VARIANT" ]; then
|
||||
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$PLAYERBOT_ENABLED" = "1" ]; then
|
||||
STACK_SOURCE_VARIANT="playerbots"
|
||||
else
|
||||
STACK_SOURCE_VARIANT="core"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
LOCAL_STORAGE_ROOT="${STORAGE_PATH_LOCAL:-./local-storage}"
|
||||
DEFAULT_STANDARD_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore"
|
||||
DEFAULT_PLAYERBOTS_PATH="${LOCAL_STORAGE_ROOT%/}/source/azerothcore-playerbots"
|
||||
|
||||
SOURCE_PATH_DEFAULT="$DEFAULT_STANDARD_PATH"
|
||||
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$NEEDS_CXX_REBUILD" = "1" ]; then
|
||||
if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
|
||||
SOURCE_PATH_DEFAULT="$DEFAULT_PLAYERBOTS_PATH"
|
||||
fi
|
||||
SOURCE_PATH="${MODULES_REBUILD_SOURCE_PATH:-$SOURCE_PATH_DEFAULT}"
|
||||
|
||||
show_client_data_requirement(){
|
||||
local repo_path="$1"
|
||||
local detector="$PROJECT_ROOT/scripts/detect-client-data-version.sh"
|
||||
if [ ! -x "$detector" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
local detection
|
||||
if ! detection="$("$detector" --no-header "$repo_path" 2>/dev/null | head -n1)"; then
|
||||
echo "⚠️ Could not detect client data version for $repo_path"
|
||||
return
|
||||
fi
|
||||
|
||||
local detected_repo raw_version normalized_version
|
||||
IFS=$'\t' read -r detected_repo raw_version normalized_version <<< "$detection"
|
||||
if [ -z "$normalized_version" ] || [ "$normalized_version" = "<unknown>" ]; then
|
||||
echo "⚠️ Could not detect client data version for $repo_path"
|
||||
return
|
||||
fi
|
||||
|
||||
local env_value="${CLIENT_DATA_VERSION:-}"
|
||||
if [ -n "$env_value" ] && [ "$env_value" != "$normalized_version" ]; then
|
||||
echo "⚠️ Source requires client data ${normalized_version} (raw ${raw_version}) but .env specifies ${env_value}. Update CLIENT_DATA_VERSION to avoid mismatched maps."
|
||||
elif [ -n "$env_value" ]; then
|
||||
echo "📦 Client data requirement satisfied: ${normalized_version} (raw ${raw_version})"
|
||||
else
|
||||
echo "ℹ️ Detected client data requirement: ${normalized_version} (raw ${raw_version}). Set CLIENT_DATA_VERSION in .env to avoid mismatches."
|
||||
fi
|
||||
}
|
||||
|
||||
STORAGE_PATH_VALUE="${STORAGE_PATH:-./storage}"
|
||||
if [[ "$STORAGE_PATH_VALUE" != /* ]]; then
|
||||
STORAGE_PATH_ABS="$PROJECT_ROOT/${STORAGE_PATH_VALUE#./}"
|
||||
@@ -72,8 +91,8 @@ ACORE_BRANCH_STANDARD="${ACORE_BRANCH_STANDARD:-master}"
|
||||
ACORE_REPO_PLAYERBOTS="${ACORE_REPO_PLAYERBOTS:-https://github.com/mod-playerbots/azerothcore-wotlk.git}"
|
||||
ACORE_BRANCH_PLAYERBOTS="${ACORE_BRANCH_PLAYERBOTS:-Playerbot}"
|
||||
|
||||
# Repository and branch selection based on playerbots mode
|
||||
if [ "$MODULE_PLAYERBOTS" = "1" ] || [ "$NEEDS_CXX_REBUILD" = "1" ]; then
|
||||
# Repository and branch selection based on source variant
|
||||
if [ "$STACK_SOURCE_VARIANT" = "playerbots" ]; then
|
||||
REPO_URL="$ACORE_REPO_PLAYERBOTS"
|
||||
BRANCH="$ACORE_BRANCH_PLAYERBOTS"
|
||||
echo "📌 Playerbots mode: Using $REPO_URL, branch $BRANCH"
|
||||
@@ -130,5 +149,6 @@ echo "📊 Current status:"
|
||||
echo " Branch: $CURRENT_BRANCH"
|
||||
echo " Commit: $CURRENT_COMMIT"
|
||||
echo " Last commit: $(git log -1 --pretty=format:'%s (%an, %ar)')"
|
||||
show_client_data_requirement "$SOURCE_PATH"
|
||||
|
||||
echo '🎉 Source repository setup complete!'
|
||||
|
||||
@@ -58,8 +58,13 @@ def cmd_metadata(manifest_path: str) -> None:
|
||||
for entry in iter_modules(manifest):
|
||||
key = entry["key"]
|
||||
name = clean(entry.get("name", key))
|
||||
needs_build = "1" if entry.get("needs_build") else "0"
|
||||
module_type = clean(entry.get("type", ""))
|
||||
module_type_raw = entry.get("type", "")
|
||||
module_type = clean(module_type_raw)
|
||||
needs_build_flag = entry.get("needs_build")
|
||||
if needs_build_flag is None:
|
||||
needs_build = "1" if str(module_type_raw).lower() == "cpp" else "0"
|
||||
else:
|
||||
needs_build = "1" if needs_build_flag else "0"
|
||||
status = clean(entry.get("status", "active"))
|
||||
block_reason = clean(entry.get("block_reason", ""))
|
||||
requires = unique_preserve_order(entry.get("requires") or [])
|
||||
|
||||
@@ -64,6 +64,8 @@ sync_local_staging(){
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
ENV_FILE="$PROJECT_DIR/.env"
|
||||
DEFAULT_COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
|
||||
EXTRA_COMPOSE_FILE="$PROJECT_DIR/docker-compose.mysql-expose.yml"
|
||||
|
||||
usage(){
|
||||
cat <<EOF
|
||||
@@ -112,6 +114,19 @@ resolve_project_name(){
|
||||
echo "$sanitized"
|
||||
}
|
||||
|
||||
if [ -z "${COMPOSE_FILE:-}" ]; then
|
||||
compose_files=("$DEFAULT_COMPOSE_FILE")
|
||||
if [ "$(read_env MYSQL_EXPOSE_PORT "0")" = "1" ]; then
|
||||
if [ -f "$EXTRA_COMPOSE_FILE" ]; then
|
||||
compose_files+=("$EXTRA_COMPOSE_FILE")
|
||||
else
|
||||
echo "⚠️ MYSQL_EXPOSE_PORT=1 but ${EXTRA_COMPOSE_FILE} not found; continuing without port exposure override."
|
||||
fi
|
||||
fi
|
||||
COMPOSE_FILE="$(IFS=:; echo "${compose_files[*]}")"
|
||||
export COMPOSE_FILE
|
||||
fi
|
||||
|
||||
resolve_project_image(){
|
||||
local tag="$1"
|
||||
local project_name
|
||||
|
||||
@@ -10,7 +10,8 @@ ok(){ echo -e "${GREEN}✅ $*${NC}"; }
|
||||
warn(){ echo -e "${YELLOW}⚠️ $*${NC}"; }
|
||||
err(){ echo -e "${RED}❌ $*${NC}"; }
|
||||
|
||||
COMPOSE_FILE="$(dirname "$0")/docker-compose.yml"
|
||||
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
COMPOSE_FILE="$PROJECT_DIR/docker-compose.yml"
|
||||
ENV_FILE=""
|
||||
PROFILES=(db services-standard client-data modules tools)
|
||||
SKIP_DEPLOY=false
|
||||
@@ -72,6 +73,15 @@ run_compose(){
|
||||
compose_args+=(--env-file "$ENV_FILE")
|
||||
fi
|
||||
compose_args+=(-f "$COMPOSE_FILE")
|
||||
if [ "$(read_env_value MYSQL_EXPOSE_PORT "0")" = "1" ]; then
|
||||
local extra_file
|
||||
extra_file="$(dirname "$COMPOSE_FILE")/docker-compose.mysql-expose.yml"
|
||||
if [ -f "$extra_file" ]; then
|
||||
compose_args+=(-f "$extra_file")
|
||||
else
|
||||
warn "MYSQL_EXPOSE_PORT=1 but ${extra_file} missing; skipping port exposure override."
|
||||
fi
|
||||
fi
|
||||
docker compose "${compose_args[@]}" "$@"
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user