Each app now carries everything under containers/<app>/: Tools-tab actions in tools/ (declaration <app>.tools.json + function <app>_<tool_id>.sh) and logic helpers in scripts/ (e.g. <app>_auth.sh). The container scan live-sources every .sh under the app (maxdepth 3, prunes only resources/) and webui_tools.sh auto-merges the .tools.json, so an app is a true drop-in — no central edit, no array regen. - Empty the central webui_tools.sh heredoc; all 34 tools across 11 apps now come from per-app declarations (verified byte-identical to the old output). - Retire the orphaned mattermost tool scripts to scripts/unused (there is no containers/mattermost; its install fn already lived in unused). - Update the dispatch comment/error path, the auth-adapter doc, and DEVELOPMENT.md to the new convention. - Regenerate static arrays (files_app.sh no longer lists app/containers/*). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> Signed-off-by: librelad <librelad@digitalangels.vip>
76 lines
2.4 KiB
Bash
76 lines
2.4 KiB
Bash
#!/bin/bash
|
|
|
|
# Per-app "tools" dispatcher.
|
|
#
|
|
# Each container/<app>/<app>.sh that exposes Tools-tab actions defines a
|
|
# function named `<app>Tool` (e.g. `gluetunTool`) that takes two args:
|
|
# $1 = tool id (matches an entry in <app>/<app>.tools.json)
|
|
# $2 = pipe-encoded args string from the modal, e.g. "duration=5|mode=fast"
|
|
#
|
|
# Tool args parsing helper: see toolArgsGet below.
|
|
|
|
dockerAppRunTool()
|
|
{
|
|
local app_name="$1"
|
|
local tool_name="$2"
|
|
local tool_args="$3"
|
|
|
|
# One-file-per-tool convention: tool id `<verb>_<noun>` resolves to
|
|
# function `app<AppName><PascalCaseToolId>`. Each tool lives at
|
|
# containers/<app>/tools/<app>_<tool_id>.sh (live-sourced by the container scan).
|
|
#
|
|
# Examples:
|
|
# gluetun + refresh_providers → appGluetunRefreshProviders
|
|
# nextcloud + reset_password → appNextcloudResetPassword
|
|
local app_name_ucfirst="$(tr '[:lower:]' '[:upper:]' <<< ${app_name:0:1})${app_name:1}"
|
|
|
|
local tool_pascal=""
|
|
local _word
|
|
local IFS='_'
|
|
for _word in $tool_name; do
|
|
tool_pascal+="$(tr '[:lower:]' '[:upper:]' <<< ${_word:0:1})${_word:1}"
|
|
done
|
|
unset IFS
|
|
|
|
local toolFuncName="app${app_name_ucfirst}${tool_pascal}"
|
|
|
|
if ! declare -f "$toolFuncName" >/dev/null 2>&1; then
|
|
isError "App '$app_name' has no tool '$tool_name' (missing function $toolFuncName — expected in containers/$app_name/tools/${app_name}_${tool_name}.sh)."
|
|
return 1
|
|
fi
|
|
|
|
initializeAppVariables "$app_name"
|
|
|
|
isHeader "Running tool '$tool_name' for $app_name"
|
|
"$toolFuncName" "$tool_args"
|
|
local tool_rc=$?
|
|
|
|
# Refresh apps.json so the WebUI sees any CFG_* the tool just wrote.
|
|
# Targeted patch (jq) instead of full regen — ~30x faster.
|
|
if declare -F webuiPatchAppConfigJson >/dev/null 2>&1; then
|
|
webuiPatchAppConfigJson "$app_name" >/dev/null 2>&1 || true
|
|
elif declare -F webuiGenerateLibrePortalConfig >/dev/null 2>&1; then
|
|
webuiGenerateLibrePortalConfig >/dev/null 2>&1 || true
|
|
fi
|
|
return $tool_rc
|
|
}
|
|
|
|
# Read a single value out of the pipe-encoded args string. Usage:
|
|
# local val
|
|
# val=$(toolArgsGet "$tool_args" "duration")
|
|
toolArgsGet()
|
|
{
|
|
local args="$1"
|
|
local key="$2"
|
|
local pair value
|
|
IFS='|' read -ra _pairs <<< "$args"
|
|
for pair in "${_pairs[@]}"; do
|
|
if [[ "$pair" == "$key="* ]]; then
|
|
value="${pair#${key}=}"
|
|
printf '%s' "$value"
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|