LibrePortal/scripts/cli/commands/app/cli_app_header.sh
librelad ef60cce98a feat(app): portable .lpapp export and import — phase 4
`libreportal app export <app>` writes one app to a single file;
`libreportal app import <file>` installs it here. This is the thing the
original request described as "upload or navigate to the backup file" — a
restic repository is not a file, but the want behind the phrasing is real.

The format is deliberately boring: gzipped tar of the app directory with
its .libreportal-manifest.json at the root. That manifest already records
size, images, volumes, databases and storage location, so import reuses
the phase-3 checks for free — refusing an app this version no longer
ships, or one that will not fit, before unpacking anything.

Export stops the app first. A tar of a running Postgres is a corrupt
Postgres, and a file that looks fine until you restore it is worse than a
refusal. tar runs as the owning user with --numeric-owner so container
sub-UIDs survive the round trip instead of being remapped through this
machine's /etc/passwd.

Import re-runs the normal install pipeline after unpacking, because the
compose still carries the SOURCE machine's ports, IPs and domains — that
pipeline is what re-allocates them here, and migrateUrlRewrite fixes the
host-bound CFG_* fields.

Documented throughout as a courier format, not a backup: no history, no
retention, no encryption. Importing under a different name is refused
outright rather than half-working — the CFG_<APP>_* namespace and compose
identities would all need rewriting, and `instance create` already
answers "a second copy".

Fixes a bug this surfaced: _appDirIntended did an indirect expansion on
CFG_<SLUG>_STORAGE without checking <SLUG> can be a variable name, so a
hyphenated or mistyped app name emitted "invalid variable name" and then
reported the misleading "storage location is not mounted" for an app that
simply did not exist.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 09:08:41 +01:00

55 lines
3.8 KiB
Bash
Executable File

#!/bin/bash
# App Commands Header
# Shows available app commands and help information
cliShowAppHelp()
{
echo ""
echo "Available App Commands (* is required):"
echo ""
echo " libreportal app list [type*] - Display a list of applications"
echo " available - Show available apps to install"
echo " installed - Show installed apps"
echo ""
echo " libreportal app install [name*] [config] [--reset-network]"
echo " - Install / reinstall the specified app."
echo " On reinstall, IPs and ports are preserved by default."
echo " Pass --reset-network to re-randomize them."
echo " libreportal app add [name*] - Add an app definition from the signed registry"
echo " catalog (marketplace). It then installs like any"
echo " other app. Browse: libreportal artifact index"
echo " libreportal app uninstall [name*] - Uninstall the specified app"
echo " libreportal app export [name*] [file] - Write one app to a single .lpapp file"
echo " (stops it briefly). A copy you can hand"
echo " around — not a backup: no history, no"
echo " retention, not encrypted."
echo " libreportal app import [file*] - Install an app from a .lpapp file,"
echo " re-wiring its ports, IPs and domains"
echo " for this machine."
echo " libreportal app move [name*] [location*] - Move the app's data to another storage"
echo " location. Stops the app, snapshots it,"
echo " copies, verifies, then removes the source."
echo " See: libreportal storage list"
echo ""
echo " libreportal app start [name*] - Start the specified app (Must be installed)"
echo " libreportal app stop [name*] - Stop the specified app (Must be installed)"
echo " libreportal app restart [name*] [service] - Restart the specified app, or just one of its"
echo " compose services when [service] is given"
echo ""
echo " libreportal app up [name*] - Docker-Compose up (Rebuild app)"
echo " libreportal app down [name*] - Docker-Compose up (Uninstall app)"
echo " libreportal app reload [name*] - Docker-Compose up & down (Reinstall app)"
echo ""
echo " libreportal app backup [name*] [password] - Backup the specified app (password optional)"
echo " libreportal app restore [name*] [file|--latest] [password] - Restore from local/remote, prefers local"
echo " libreportal app restore [name*] [local|remote1|remote2] [file] [password]"
echo " - Restore from a specific location"
echo " libreportal app status [name*] - Show status of specified app"
echo " libreportal app tool [name*] [tool*] [args]"
echo " - Run a per-app tool (Tools tab actions)."
echo " [args] is pipe-encoded: key=value|key=value"
echo " libreportal app tool list [name] - List available tools (all apps, or just [name])"
echo ""
}