#!/usr/bin/env bash set -euo pipefail UMBREL_ROOT="$(readlink -f $(dirname "${BASH_SOURCE[0]}")/..)" USER_FILE="${UMBREL_ROOT}/db/user.json" show_help() { cat << EOF app 0.0.1 CLI for managing Umbrel apps Usage: app [] Commands: install Pulls down images for an app and starts it uninstall Removes images and destroys all data for an app stop Stops an installed app start Starts an installed app compose Passes all arguments to docker-compose EOF } check_dependencies () { for cmd in "$@"; do if ! command -v $cmd >/dev/null 2>&1; then echo "This script requires \"${cmd}\" to be installed" exit 1 fi done } list_installed_apps() { cat "${USER_FILE}" | jq -r 'if has("installedApps") then .installedApps else [] end | join("\n")' || true } # Check dependencies check_dependencies docker-compose jq if [ -z ${1+x} ]; then command="" else command="$1" fi if [ -z ${2+x} ]; then show_help exit 1 else app="$2" app_dir="${UMBREL_ROOT}/apps/${app}" app_data_dir="${UMBREL_ROOT}/app-data/${app}" if [[ "${app}" == "installed" ]]; then list_installed_apps | while read app; do if [[ "${app}" != "" ]]; then "${0}" "${1}" "${app}" "${@:3}" || true fi done exit fi if [[ -z "${app}" ]] || [[ ! -d "${app_dir}" ]]; then echo "Error: \"${app}\" is not a valid app" exit 1 fi fi if [ -z ${3+x} ]; then args="" else args="${@:3}" fi compose() { local app="${1}" shift local env_file="${UMBREL_ROOT}/.env" local app_base_compose_file="${UMBREL_ROOT}/apps/docker-compose.common.yml" local app_compose_file="${app_dir}/docker-compose.yml" local app_hidden_servive_file="${UMBREL_ROOT}/tor/data/app-${app}/hostname" export BITCOIN_DATA_DIR="${UMBREL_ROOT}/bitcoin" export LND_DATA_DIR="${UMBREL_ROOT}/lnd" export APP_DATA_DIR="${app_data_dir}" export APP_HIDDEN_SERVICE="$(cat "${app_hidden_servive_file}" 2>/dev/null || echo "notyetset.onion")" docker-compose \ --env-file "${env_file}" \ --project-name "${app}" \ --file "${app_base_compose_file}" \ --file "${app_compose_file}" \ "${@}" } update_installed_apps() { local action="${1}" local app="${2}" [[ "${action}" == "add" ]] && operator="+" || operator="-" updated_json=$(cat "${USER_FILE}" | jq ".installedApps |= (. ${operator} [\"${app}\"] | unique)") echo "${updated_json}" > "${USER_FILE}" } # Pulls down images for an app and starts it if [[ "$command" = "install" ]]; then echo "Pulling images for ${app}..." compose "${app}" pull echo "Setting up data dir for ${app}..." mkdir -p "${app_data_dir}" cp -a "${app_dir}/." "${app_data_dir}" echo "Starting app ${app}..." compose "${app}" up --detach echo "Saving installed app in DB" update_installed_apps add "${app}" exit fi # Removes images and destroys all data for an app if [[ "$command" = "uninstall" ]]; then echo "Removing app images" compose "${app}" down --rmi all --remove-orphans echo "Deleting app data for ${app}..." if [[ -d "${app_data_dir}" ]]; then rm -rf "${app_data_dir}" fi echo "Removing installed app from DB" update_installed_apps remove "${app}" exit fi # Stops an installed app if [[ "$command" = "stop" ]]; then echo "Stopping app ${app}..." compose "${app}" rm --force --stop exit fi # Starts an installed app if [[ "$command" = "start" ]]; then if ! list_installed_apps | grep --quiet "^${app}$"; then echo "Error: \"${app}\" is not installed yet" exit 1 fi echo "Starting app ${app}..." compose "${app}" up --detach exit fi # Passes all arguments to docker-compose if [[ "$command" = "compose" ]]; then compose "${app}" ${args} exit fi # If we get here it means no valid command was supplied # Show help and exit show_help exit 1