wgctl/core/framework/command.sh.bak
Nuno Duque Nunes 8ed491313d feat: command framework + logs migration
- core/framework/flag.sh: flag::define, flag::parse, accessors
- core/framework/hook.sh: hook::on, hook::fire, hook::off, hook::has
- core/framework/help.sh: help::section, command::help::auto
- core/framework/command.sh: command::define, command::route, lazy loading
- core restructure: framework/ + app/ separation
- load_command: directory-based command detection
- command::exists: accepts new-style commands
- command::run: routing for new-style, legacy fallback
- commands/logs/: migrated to new framework
  - logs.sh: router + command::define
  - show.sh: flag::define + flag::parse, no manual case blocks
  - clean.sh: flag::define + flag::parse
  - remove.sh: flag::define + flag::parse
  - rotate.sh: flag::define + flag::parse
- logs clean: fix dry_run bool to int conversion
- ctx::json_helper: fixed path after core restructure
- PYTHONPATH: exported in app/core.sh
2026-05-30 03:44:08 +00:00

130 lines
3.2 KiB
Bash

#!/usr/bin/env bash
# ============================================
# Command Registry
# ============================================
declare -A _LOADED_COMMANDS=()
readonly _COMMAND_NAMESPACE="cmd"
readonly _COMMAND_AUTO_LOAD_HOOK="on_load"
_CURRENT_LOADING_CMD=""
# ============================================
# Helpers
# ============================================
function command::loaded() { [[ -n "${_LOADED_COMMANDS["$1"]:-}" ]]; }
# Convert path-style name to namespace
# e.g. service/wireguard -> service::wireguard
function command::to_namespace() { echo "${1//\//:}"; }
# Build fully qualified function name
# e.g. command::fn "add" "run" -> cmd::add::run
# e.g. command::fn "service/wg" "run" -> cmd::service::wg::run
function command::fn() {
local name namespace
namespace=$(command::to_namespace "$1")
echo "${_COMMAND_NAMESPACE}::${namespace}::${2}"
}
function command::has_function() { declare -F "$(command::fn "$1" "$2")" >/dev/null 2>&1; }
function command::is_auto_load() { declare -F "$(command::fn "$1" on_load)" >/dev/null 2>&1; }
function command::exists() { command::has_function "$1" run; }
# ============================================
# Runner
# ============================================
# function command::run() {
# local cmd="$1"
# shift
# command::_reset_mixin_state # reset values only, keep _ACTIVE_MIXINS
# local -a args=("$@")
# command::_preprocess_flags args
# local fn
# fn=$(command::fn "$cmd" run)
# core::call_function "$fn" ${args[@]+"${args[@]}"}
# }
function command::run() {
local cmd="$1"
shift
command::_reset_mixin_state
# Build default args from config
local -a default_args=()
local defaults="${_COMMAND_DEFAULTS[$cmd]:-}"
if [[ -n "$defaults" ]]; then
read -ra default_args <<< "$defaults"
fi
local -a user_args=("$@")
[[ $# -gt 0 ]] && user_args=("$@")
# Resolve exclusive group conflicts — user args override defaults
local groups="${_FLAG_EXCLUSIVE_GROUPS[$cmd]:-}"
if [[ -n "$groups" && ${#default_args[@]} -gt 0 && ${#user_args[@]} -gt 0 ]]; then
command::_resolve_conflicts default_args user_args "$groups"
fi
local -a cleaned_defaults=()
for _d in "${default_args[@]:-}"; do
[[ -n "$_d" ]] && cleaned_defaults+=("$_d")
done
default_args=("${cleaned_defaults[@]:-}")
local -a args=()
for _d in "${default_args[@]:-}"; do
[[ -n "$_d" ]] && args+=("$_d")
done
for _u in "${user_args[@]:-}"; do
[[ -n "$_u" ]] && args+=("$_u")
done
# Preprocess mixin flags (--json, --no-color etc)
command::_preprocess_flags args
local fn
fn=$(command::fn "$cmd" run)
core::call_function "$fn" ${args[@]+"${args[@]}"}
}
function core::call_function() {
local fn="$1"
shift
"$fn" "$@"
}
# ============================================
# Loader
# ============================================
function load_command() {
local name="$1"
command::loaded "$name" && return 0
local path
path="$(ctx::commands)/${name}.command.sh"
if [[ ! -f "$path" ]]; then
log::error "Command not found: ${name} (${path})"
return 1
fi
source "$path"
_LOADED_COMMANDS["$name"]=1
_CURRENT_LOADING_CMD="$name"
core::call_if_exists "$(command::fn "$name" on_load)"
_CURRENT_LOADING_CMD=""
return 0
}