#!/bin/bash dockerUninstallApp() { local app_name="$1" # Optional: delete the app's docker images too. Default false so a # plain `libreportal app uninstall ` keeps cached images for a # quick reinstall. The WebUI's Uninstall modal exposes this as the # "Also delete docker image" checkbox. local delete_images="${2:-false}" local delete_tasks="${3:-false}" local stored_app_name=$app_name if [[ "$stored_app_name" == "" ]]; then isError "No app_name provided, unable to continue..." else isHeader "Uninstalling $stored_app_name" initializeAppVariables $stored_app_name; ((menu_number++)) echo "" echo "---- $menu_number. Removing app where docker compose is installed" echo "" dockerComposeDownRemove $stored_app_name; # App-specific uninstall hook. Host-installed apps (and any app needing # teardown beyond the generic docker/DB cleanup) define an uninstall # function — it runs the app-specific bits (apt purge, systemd units, # cscli state, ...) while the shared compose/data/DB/WebUI teardown below # stays generic. The CLI and menu both route uninstalls through here, so # this is the single point every uninstall passes through. local app_name_ucfirst="$(tr '[:lower:]' '[:upper:]' <<< ${stored_app_name:0:1})${stored_app_name:1}" local uninstallFuncName="uninstall${app_name_ucfirst}" if declare -f "$uninstallFuncName" >/dev/null 2>&1; then ((menu_number++)) echo "" echo "---- $menu_number. Running $stored_app_name-specific uninstall steps" echo "" "$uninstallFuncName" fi ((menu_number++)) echo "" if [[ "$delete_images" == "true" ]]; then echo "---- $menu_number. Removing Docker images for the app" echo "" dockerRemoveAppImages $stored_app_name; else echo "---- $menu_number. Keeping Docker images (pass --delete-images to remove)" echo "" isNotice "Docker images for '$stored_app_name' left in place. A reinstall will reuse them." fi ((menu_number++)) echo "" echo "---- $menu_number. Deleting all app data from docker folder" echo "" dockerDeleteData $stored_app_name; ((menu_number++)) echo "" echo "---- $menu_number. Removing unused Docker networks." echo "" dockerPruneAppNetworks $stored_app_name; ((menu_number++)) echo "" echo "---- $menu_number. Removing app from the database" echo "" ipRemoveFromDatabase $stored_app_name; portsRemoveFromDatabase $stored_app_name; databaseUninstallApp $stored_app_name; ((menu_number++)) echo "" echo "---- $menu_number. Updating the WebUI config file." echo "" webuiContainerSetup $stored_app_name uninstall; if [[ $(dockerCheckAppInstalled "gluetun" "docker") == "installed" ]]; then tagsProcessorGluetunForwardedPorts fi if [[ "$delete_tasks" == "true" ]]; then ((menu_number++)) echo "" echo "---- $menu_number. Removing related task history" echo "" local _tasks_dir="${containers_dir}libreportal/frontend/data/tasks" local _removed=0 if [[ -d "$_tasks_dir" ]]; then for _tf in "$_tasks_dir"/task_*.json; do [[ ! -f "$_tf" ]] && continue # Skip in-flight tasks — that includes the uninstall task # we're currently inside, plus anything queued or running. if runFileOp grep -qE "\"status\"[[:space:]]*:[[:space:]]*\"(running|queued|pending)\"" "$_tf" 2>/dev/null; then continue fi if runFileOp grep -q "\"app\"[[:space:]]*:[[:space:]]*\"${stored_app_name}\"" "$_tf" 2>/dev/null; then local _id=$(basename "$_tf" .json) runFileOp rm -f "$_tf" "$_tasks_dir/${_id}.log" "$_tasks_dir/${_id}.cancel" 2>/dev/null _removed=$((_removed + 1)) fi done fi isSuccessful "Removed $_removed task record(s) for $stored_app_name (in-flight task left for the WebUI to clean up after completion)." fi ((menu_number++)) echo "" isSuccessful "$stored_app_name has been removed from your system!" echo "" menu_number=0 cd fi }