Files
pymc_console-dist/manage.sh
T
GitHub Actions Bot f4f761ad3c Release v0.9.394
Automated sync from private repository.
UI build published as release assets.
2026-09-17 21:04:15 +00:00

715 lines
28 KiB
Bash
Executable File

#!/bin/bash
# ═══════════════════════════════════════════════════════════════════════════════
# waev:outpost - Dashboard Manager
# ═══════════════════════════════════════════════════════════════════════════════
#
# SCOPE: Dashboard-only.
#
# This script manages the waev:outpost React dashboard overlay. It does NOT
# install, upgrade, or uninstall openHop Repeater itself — that is the Repeater
# repo's job (run openhop_repeater's own manage.sh for Repeater lifecycle).
#
# WHAT WE DO:
# • Download and install the waev:outpost dashboard into /opt/pymc_console
# • On fresh install, point the Repeater's web.web_path at our dashboard
# • On upgrade, refresh dashboard assets while preserving web_path
# • On uninstall, remove /opt/pymc_console and clear web.web_path when it
# still points at our dashboard (Repeater is otherwise left untouched)
#
# WHAT WE DO NOT DO (anymore):
# • Clone, install, upgrade, or uninstall openHop Repeater
# • Radio/GPIO configuration
# • systemd unit management (start/stop/restart/status/logs — use Repeater's
# manage.sh or systemctl/journalctl directly for the openhop-repeater service)
# • Any TUI (whiptail/dialog). All prompts are plain terminal I/O.
#
# REPEATER REFERENCES:
# • $INSTALL_DIR is referenced only to detect that Repeater is installed
# (we refuse to install waev:outpost without it)
# • The Repeater's config.yaml is patched (web.web_path) on fresh install:
# $CONFIG_DIR on openHop, or $LEGACY_CONFIG_DIR on a system upstream has
# not migrated. Detection and patching honour the same two layouts.
# • $REPEATER_USER:$REPEATER_GROUP is used for ownership of our files
#
# NON-INTERACTIVE MODE:
# Pass --yes (before the verb) or set ASSUME_YES=1 to auto-confirm prompts.
# ═══════════════════════════════════════════════════════════════════════════════
set -e
# ─────────────────────────────────────────────────────────────────────────────
# Configuration
# ─────────────────────────────────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# Repeater paths (read-only for us — used to locate config/user)
INSTALL_DIR="/opt/openhop_repeater"
CONFIG_DIR="/etc/openhop_repeater"
SERVICE_NAME="openhop-repeater"
REPEATER_USER="repeater"
REPEATER_GROUP="repeater"
# Legacy pyMC_Repeater paths remain detection fallbacks for older systems.
LEGACY_INSTALL_DIR="/opt/pymc_repeater"
LEGACY_CONFIG_DIR="/etc/pymc_repeater"
LEGACY_SERVICE_NAME="pymc-repeater"
# Console paths (we own these)
CONSOLE_DIR="/opt/pymc_console"
UI_DIR="$CONSOLE_DIR/web/html"
# Release artifacts
UI_REPO="Treehouse-00/pymc_console-dist"
UI_RELEASE_URL="https://github.com/${UI_REPO}/releases"
UI_TARBALL="pymc-ui-latest.tar.gz"
# Runtime flags (set by CLI parser). Exported so a re-exec preserves them.
export ASSUME_YES="${ASSUME_YES:-0}"
# ─────────────────────────────────────────────────────────────────────────────
# Terminal Output
# ─────────────────────────────────────────────────────────────────────────────
# Enable colors only when stdout is a TTY and NO_COLOR is unset.
if [[ -t 1 && -z "${NO_COLOR:-}" ]]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
DIM='\033[2m'
NC='\033[0m'
else
RED=''; GREEN=''; YELLOW=''; CYAN=''; BOLD=''; DIM=''; NC=''
fi
print_step() { echo -e "\n${BOLD}${CYAN}[$1/$2]${NC} ${BOLD}$3${NC}"; }
print_success() { echo -e " ${GREEN}✓${NC} $1"; }
print_error() { echo -e " ${RED}✗${NC} ${RED}$1${NC}" >&2; }
print_info() { echo -e " ${CYAN}➜${NC} $1"; }
print_warning() { echo -e " ${YELLOW}⚠${NC} $1"; }
print_banner() {
echo ""
echo -e "${BOLD}${CYAN}waev:outpost${NC}"
echo -e "${DIM}React Dashboard for openHop Repeater${NC}"
echo ""
}
# ─────────────────────────────────────────────────────────────────────────────
# Terminal Prompts (no TUI)
# ─────────────────────────────────────────────────────────────────────────────
#
# prompt_yes_no "question" [default]
# default: "y" or "n" (default "n"). Honors ASSUME_YES=1.
# Returns 0 on yes, 1 on no.
prompt_yes_no() {
local question="$1"
local default="${2:-n}"
local prompt_suffix
local reply
if [[ "$ASSUME_YES" == "1" ]]; then
return 0
fi
if [[ "$default" == "y" ]]; then
prompt_suffix="[Y/n]"
else
prompt_suffix="[y/N]"
fi
read -r -p "$(echo -e " ${CYAN}?${NC} ${question} ${prompt_suffix} ")" reply
reply="${reply:-$default}"
case "$reply" in
y|Y|yes|YES) return 0 ;;
*) return 1 ;;
esac
}
# ─────────────────────────────────────────────────────────────────────────────
# Status Helpers
# ─────────────────────────────────────────────────────────────────────────────
# Tiered Repeater-presence probe. Returns 0 when ANY of the following is true,
# in order of signal strength:
# 1. `pip3 show openhop_repeater` succeeds (the source of truth)
# 2. systemd knows about openhop-repeater.service (unit file present)
# 3. $INSTALL_DIR/pyproject.toml exists (edge-case layout fallback)
repeater_installed() {
if command -v pip3 &>/dev/null && { pip3 show openhop_repeater &>/dev/null || pip3 show pymc-repeater &>/dev/null; }; then
return 0
fi
if command -v systemctl &>/dev/null \
&& { [[ -n "$(systemctl list-unit-files --no-legend --no-pager "${SERVICE_NAME}.service" 2>/dev/null)" ]] \
|| [[ -n "$(systemctl list-unit-files --no-legend --no-pager "${LEGACY_SERVICE_NAME}.service" 2>/dev/null)" ]]; }; then
return 0
fi
[[ -d "$INSTALL_DIR" && -f "$INSTALL_DIR/pyproject.toml" ]] || [[ -d "$LEGACY_INSTALL_DIR" && -f "$LEGACY_INSTALL_DIR/pyproject.toml" ]]
}
console_installed() { [[ -d "$UI_DIR" ]]; }
pip_version() {
local pkg="$1"
command -v pip3 &>/dev/null || return 0
pip3 show "$pkg" 2>/dev/null | awk '/^Version:/ {print $2; exit}'
}
get_repeater_version() {
local v
v="$(pip_version openhop_repeater)"
[[ -n "$v" ]] || v="$(pip_version pymc-repeater)"
echo "${v:-unknown}"
}
get_console_version() {
if [[ -f "$UI_DIR/VERSION" ]]; then
local v
v=$(tr -d '[:space:]' < "$UI_DIR/VERSION")
echo "${v:-unknown}"
else
echo "unknown"
fi
}
# Read-only systemd probes (safe to call as non-root).
service_unit_exists() {
command -v systemctl &>/dev/null || return 1
[[ -n "$(systemctl list-unit-files --no-legend --no-pager "${SERVICE_NAME}.service" 2>/dev/null)" ]] \
|| [[ -n "$(systemctl list-unit-files --no-legend --no-pager "${LEGACY_SERVICE_NAME}.service" 2>/dev/null)" ]]
}
active_service_name() {
if command -v systemctl &>/dev/null && [[ -n "$(systemctl list-unit-files --no-legend --no-pager "${SERVICE_NAME}.service" 2>/dev/null)" ]]; then
echo "$SERVICE_NAME"
else
echo "$LEGACY_SERVICE_NAME"
fi
}
service_is_active() { command -v systemctl &>/dev/null && systemctl is-active "$(active_service_name)" &>/dev/null; }
service_is_enabled() { command -v systemctl &>/dev/null && systemctl is-enabled "$(active_service_name)" &>/dev/null; }
# Whether systemd knows a given unit by name.
unit_exists() {
command -v systemctl &>/dev/null || return 1
[[ -n "$(systemctl list-unit-files --no-legend --no-pager "${1}.service" 2>/dev/null)" ]]
}
# The Repeater's config file: openHop's path first, then the legacy pyMC path
# on a system upstream has not migrated. Detection honours both layouts, so
# the file we patch must too — otherwise an unmigrated system gets a
# dashboard that is installed but never wired in. Prints the path; returns 1
# when neither file exists.
resolve_config_file() {
if [[ -f "$CONFIG_DIR/config.yaml" ]]; then
echo "$CONFIG_DIR/config.yaml"
elif [[ -f "$LEGACY_CONFIG_DIR/config.yaml" ]]; then
echo "$LEGACY_CONFIG_DIR/config.yaml"
else
return 1
fi
}
# Where the config file is expected when none exists yet: beside whichever
# Repeater is actually installed, so a manual hint never names a file the
# running service would not read. Legacy only when the legacy unit is the
# one registered, or the legacy install dir is the only one present.
expected_config_file() {
local found
if found=$(resolve_config_file); then
echo "$found"
return 0
fi
if { unit_exists "$LEGACY_SERVICE_NAME" && ! unit_exists "$SERVICE_NAME"; } \
|| { [[ ! -d "$INSTALL_DIR" ]] && [[ -d "$LEGACY_INSTALL_DIR" ]]; }; then
echo "$LEGACY_CONFIG_DIR/config.yaml"
else
echo "$CONFIG_DIR/config.yaml"
fi
}
require_root() {
if [[ "$EUID" -ne 0 ]]; then
print_error "This command requires root. Run: sudo $0 $1"
return 1
fi
}
# ---------------------------------------------------------------------------
# Preflight + shared error messaging
# ---------------------------------------------------------------------------
# Print a non-mutating "Detected:" block summarising what we see. Returns 1
# iff Repeater is not installed (callers use this to decide whether to bail).
preflight_check() {
local repeater_ok=false
local config_ok=false
local yq_ok=false
local unit_state="not found"
local config_file
repeater_installed && repeater_ok=true
if config_file=$(resolve_config_file); then
config_ok=true
else
config_file=$(expected_config_file)
fi
command -v yq &>/dev/null && yq_ok=true
if service_unit_exists; then
local enabled="disabled"
service_is_enabled && enabled="enabled"
local active="inactive"
service_is_active && active="active"
unit_state="${enabled}, ${active}"
fi
local repeater_line
if [[ "$repeater_ok" == true ]]; then
repeater_line="${GREEN}found${NC} (v$(get_repeater_version))"
else
repeater_line="${RED}not found${NC}"
fi
local config_line
if [[ "$config_ok" == true ]]; then
config_line="${GREEN}present${NC} ($config_file)"
else
config_line="${YELLOW}missing${NC} ($config_file)"
fi
local yq_line
if [[ "$yq_ok" == true ]]; then
yq_line="${GREEN}present${NC}"
else
yq_line="${YELLOW}missing${NC} (web_path patch will be skipped)"
fi
local unit_line
if service_unit_exists; then
unit_line="${GREEN}${unit_state}${NC}"
else
unit_line="${YELLOW}not found${NC}"
fi
echo -e " ${DIM}Preflight:${NC}"
echo -e " Repeater: ${repeater_line}"
echo -e " Config file: ${config_line}"
echo -e " yq: ${yq_line}"
echo -e " Service unit: ${unit_line}"
echo ""
if [[ "$repeater_ok" != true ]]; then
return 1
fi
return 0
}
print_repeater_missing_help() {
print_error "openHop Repeater is not installed."
echo ""
echo " waev:outpost requires openHop Repeater to be installed first."
echo " Install it using the Repeater repo's manage.sh:"
echo ""
echo -e " ${CYAN}git clone https://github.com/openhop-dev/openhop_repeater.git${NC}"
echo -e " ${CYAN}cd openhop_repeater && sudo bash ./manage.sh install${NC}"
echo ""
}
print_service_hint() {
# Non-mutating post-op nudge. No action taken, just observability.
if ! service_unit_exists; then
print_warning "${SERVICE_NAME}.service is not registered with systemd."
echo " Install/repair openHop Repeater to register the service."
return
fi
if service_is_active; then
print_success "$(active_service_name).service is active."
else
print_warning "$(active_service_name).service is not running."
echo -e " Start it: ${CYAN}sudo systemctl start $(active_service_name)${NC}"
fi
if ! service_is_enabled; then
echo -e " Enable on boot: ${CYAN}sudo systemctl enable $(active_service_name)${NC}"
fi
}
# ─────────────────────────────────────────────────────────────────────────────
# Dashboard Installation (core)
# ─────────────────────────────────────────────────────────────────────────────
install_dashboard() {
local config_file
config_file=$(expected_config_file)
local temp_file="/tmp/pymc-ui-$$.tar.gz"
local is_fresh_install=true
if console_installed; then
is_fresh_install=false
fi
print_info "Downloading dashboard..."
if ! curl -fsSL -o "$temp_file" "${UI_RELEASE_URL}/latest/download/${UI_TARBALL}"; then
print_error "Download failed from ${UI_RELEASE_URL}/latest/download/${UI_TARBALL}"
rm -f "$temp_file"
return 1
fi
rm -rf "$UI_DIR"
mkdir -p "$UI_DIR"
tar -xzf "$temp_file" -C "$UI_DIR"
rm -f "$temp_file"
chown -R "$REPEATER_USER:$REPEATER_GROUP" "$CONSOLE_DIR" 2>/dev/null || true
if [[ -f "$config_file" ]] && command -v yq &>/dev/null; then
yq -i '.web //= {}' "$config_file" 2>/dev/null || true
if [[ "$is_fresh_install" == true ]]; then
yq -i ".web.web_path = \"$UI_DIR\"" "$config_file"
print_success "Dashboard installed (web_path configured)"
else
print_success "Dashboard updated (web_path preserved)"
fi
else
print_warning "Could not configure web_path automatically."
if [[ ! -f "$config_file" ]]; then
echo -e " Reason: ${YELLOW}$config_file not found${NC}."
elif ! command -v yq &>/dev/null; then
echo -e " Reason: ${YELLOW}yq is not installed${NC}."
fi
echo -e " Set it manually with:"
echo -e " ${CYAN}sudo yq -i '.web.web_path = \"$UI_DIR\"' $config_file${NC}"
echo -e " Then restart the service:"
echo -e " ${CYAN}sudo systemctl restart $(active_service_name)${NC}"
fi
local size
size=$(du -sh "$UI_DIR" 2>/dev/null | cut -f1)
print_info "Size: $size"
}
# ─────────────────────────────────────────────────────────────────────────────
# Install
# ─────────────────────────────────────────────────────────────────────────────
do_install() {
require_root "install" || return 1
print_banner
echo -e " ${DIM}Mode: Install waev:outpost${NC}"
echo ""
if ! preflight_check; then
print_repeater_missing_help
return 1
fi
if console_installed; then
if ! prompt_yes_no "waev:outpost already installed at $UI_DIR — reinstall?" "n"; then
print_info "Install cancelled."
return 0
fi
fi
print_step 1 1 "Installing dashboard"
install_dashboard
local ip
ip=$(hostname -I 2>/dev/null | awk '{print $1}')
echo ""
echo -e "${GREEN}${BOLD}waev:outpost installed!${NC}"
echo ""
echo -e " waev:outpost ${CYAN}v$(get_console_version)${NC}"
echo ""
echo -e " Dashboard: ${CYAN}http://${ip:-localhost}:8000/${NC}"
echo ""
print_service_hint
echo ""
}
# ─────────────────────────────────────────────────────────────────────────────
# Upgrade
# ─────────────────────────────────────────────────────────────────────────────
do_upgrade() {
require_root "upgrade" || return 1
print_banner
echo -e " ${DIM}Mode: Upgrade waev:outpost${NC}"
echo ""
# Self-update pymc_console repo and re-exec. This must run before any
# other checks: preflight_check() and console_installed() below are part
# of this same script, so if SCRIPT_DIR is stale, their results (and
# everything else in this run) can't be trusted until we're current.
# NOTE: this must run in the parent process (no subshell) so that `exec`
# replaces the running manage.sh instead of just a subshell.
if [[ -d "$SCRIPT_DIR/.git" ]]; then
print_info "Checking for waev:outpost updates..."
git config --global --add safe.directory "$SCRIPT_DIR" 2>/dev/null || true
local local_hash remote_hash
local_hash=$(git -C "$SCRIPT_DIR" rev-parse HEAD 2>/dev/null || echo "")
git -C "$SCRIPT_DIR" fetch origin 2>/dev/null || true
remote_hash=$(git -C "$SCRIPT_DIR" rev-parse origin/main 2>/dev/null || echo "")
if [[ -n "$remote_hash" && "$local_hash" != "$remote_hash" ]]; then
if git -C "$SCRIPT_DIR" pull --ff-only 2>/dev/null \
|| git -C "$SCRIPT_DIR" reset --hard origin/main 2>/dev/null; then
print_success "waev:outpost updated — restarting..."
exec "$SCRIPT_DIR/manage.sh" upgrade
fi
fi
fi
if ! preflight_check; then
print_repeater_missing_help
return 1
fi
if ! console_installed; then
print_error "waev:outpost is not installed. Run: sudo $0 install"
return 1
fi
local ui_before ui_after
ui_before=$(get_console_version)
print_step 1 1 "Updating dashboard"
install_dashboard
ui_after=$(get_console_version)
local ip
ip=$(hostname -I 2>/dev/null | awk '{print $1}')
echo ""
echo -e "${GREEN}${BOLD}Upgrade Complete!${NC}"
echo ""
if [[ "$ui_before" != "$ui_after" ]]; then
echo -e " waev:outpost ${DIM}v$ui_before${NC} → ${CYAN}v$ui_after${NC}"
else
echo -e " waev:outpost ${CYAN}v$ui_after${NC}"
fi
echo ""
echo -e " Dashboard: ${CYAN}http://${ip:-localhost}:8000/${NC}"
echo ""
print_service_hint
echo ""
}
# ─────────────────────────────────────────────────────────────────────────────
# Uninstall
# ─────────────────────────────────────────────────────────────────────────────
# After the dashboard is removed, a web_path that still points at it would
# leave the Repeater serving nothing. Clear it only when it is ours: a value
# someone set by hand is theirs to keep.
release_web_path() {
local config_file current
if ! config_file=$(resolve_config_file); then
print_info "No Repeater config file found; nothing to clear."
return 0
fi
if ! command -v yq &>/dev/null; then
print_warning "yq is not installed; could not check web.web_path in $config_file."
echo -e " If it still points at $UI_DIR, clear it with:"
echo -e " ${CYAN}sudo yq -i 'del(.web.web_path)' $config_file${NC}"
echo -e " Then restart the service:"
echo -e " ${CYAN}sudo systemctl restart $(active_service_name)${NC}"
return 0
fi
current=$(yq '.web.web_path // ""' "$config_file" 2>/dev/null || echo "")
if [[ "$current" == "$UI_DIR" ]]; then
yq -i 'del(.web.web_path)' "$config_file"
print_success "Cleared web.web_path in $config_file (Repeater falls back to its own dashboard)"
echo -e " Restart the service to apply:"
echo -e " ${CYAN}sudo systemctl restart $(active_service_name)${NC}"
elif [[ -z "$current" ]]; then
print_info "web.web_path is not set in $config_file; nothing to clear."
else
print_warning "web.web_path in $config_file is '$current', not ours; left unchanged."
fi
}
do_uninstall() {
require_root "uninstall" || return 1
local has_console=false
local has_repeater=false
console_installed && has_console=true
repeater_installed && has_repeater=true
print_banner
echo -e " ${DIM}Detected:${NC}"
local repeater_state
if [[ "$has_repeater" == true ]]; then
repeater_state="${DIM}present (v$(get_repeater_version)) — will NOT be touched${NC}"
else
repeater_state="${DIM}not found${NC}"
fi
echo -e " Repeater: ${repeater_state}"
echo -e " Console: $([[ "$has_console" == true ]] && echo "${GREEN}found${NC} ($CONSOLE_DIR)" || echo "${DIM}not found${NC}")"
echo -e " This repo: ${GREEN}$SCRIPT_DIR${NC}"
echo ""
if [[ "$has_console" == false ]]; then
print_info "Console is not installed; nothing to remove under $CONSOLE_DIR."
fi
local will_remove=""
[[ "$has_console" == true ]] && will_remove+=" • Console dashboard ($CONSOLE_DIR)\n"
will_remove+=" • web.web_path in the Repeater config, only if it still points at the dashboard\n"
will_remove+=" • waev:outpost checkout ($SCRIPT_DIR)"
echo -e " Will remove:\n${will_remove}"
echo ""
if ! prompt_yes_no "Continue with uninstall?" "n"; then
print_info "Uninstall cancelled."
return 0
fi
local step=1
local total=2
[[ "$has_console" == true ]] && ((total++))
if [[ "$has_console" == true ]]; then
print_step $step $total "Removing waev:outpost"
rm -rf "$CONSOLE_DIR"
print_success "Removed $CONSOLE_DIR"
((step++))
fi
print_step $step $total "Releasing web.web_path"
release_web_path
((step++))
print_step $step $total "Scheduling checkout removal"
# Sanity guard: only self-delete if the path is non-empty and looks like ours
if [[ -z "$SCRIPT_DIR" || "$SCRIPT_DIR" == "/" ]]; then
print_warning "Refusing to self-delete: SCRIPT_DIR is unsafe ($SCRIPT_DIR)"
elif [[ "$(basename "$SCRIPT_DIR")" != *pymc_console* ]]; then
print_warning "Refusing to self-delete: $SCRIPT_DIR does not look like a pymc_console checkout"
else
echo -e " ${YELLOW}Will remove $SCRIPT_DIR after script exits${NC}"
# SC2064: intentional expand-now — we want the current SCRIPT_DIR captured.
# shellcheck disable=SC2064
trap "rm -rf '$SCRIPT_DIR'" EXIT
print_success "Scheduled for removal"
fi
echo ""
echo -e "${GREEN}${BOLD}Uninstall Complete${NC}"
echo ""
}
# ─────────────────────────────────────────────────────────────────────────────
# Help / CLI
# ─────────────────────────────────────────────────────────────────────────────
show_help() {
cat << EOF
waev:outpost — Dashboard Manager
Usage: $0 [--yes] <command>
Commands:
install Install waev:outpost (requires openHop Repeater)
upgrade Refresh waev:outpost assets (preserves web_path)
uninstall Remove waev:outpost and this checkout
-h, --help Show this help
Flags:
--yes, -y Auto-confirm all prompts (also: ASSUME_YES=1)
Notes:
• This script manages waev:outpost only. openHop Repeater itself
(install, upgrade, uninstall, service control, logs, radio/GPIO) must
be managed using the Repeater repo's manage.sh:
https://github.com/openhop-dev/openhop_repeater
EOF
}
print_deprecated_subcommand() {
local cmd="$1"
local arg="$2"
print_error "\`$cmd $arg\` has been deprecated."
echo " The Full Stack / Console-only distinction no longer exists."
echo " This script now manages waev:outpost only."
echo " To install or manage openHop Repeater, use the Repeater repo's manage.sh."
echo ""
show_help
}
main() {
# Parse global flags (--yes / -y / --no-color) anywhere in the argument list.
local _args=()
local arg
for arg in "$@"; do
case "$arg" in
--yes|-y) ASSUME_YES=1 ;;
--no-color) ;; # already handled via NO_COLOR env if set; accept for symmetry
*) _args+=("$arg") ;;
esac
done
set -- "${_args[@]}"
case "${1:-}" in
-h|--help|"")
show_help
;;
install)
case "${2:-}" in
full|console)
print_deprecated_subcommand "install" "$2"
exit 1
;;
"")
do_install
;;
*)
print_error "Unknown argument: install $2"
show_help
exit 1
;;
esac
;;
upgrade)
case "${2:-}" in
full|console)
print_deprecated_subcommand "upgrade" "$2"
exit 1
;;
"")
do_upgrade
;;
*)
print_error "Unknown argument: upgrade $2"
show_help
exit 1
;;
esac
;;
uninstall) do_uninstall ;;
start|stop|restart|status|logs)
print_error "\`$1\` is not managed by the waev:outpost installer."
echo " Service control, status, and logs belong to openHop Repeater."
echo " Use the Repeater repo's manage.sh, or run systemctl/journalctl directly:"
echo ""
if [[ "$1" == "logs" ]]; then
echo -e " ${CYAN}sudo journalctl -u $(active_service_name) -f${NC}"
else
echo -e " ${CYAN}sudo systemctl $1 $(active_service_name)${NC}"
fi
echo ""
exit 1
;;
*)
print_error "Unknown command: $1"
show_help
exit 1
;;
esac
}
# Run only when executed. Sourced (as the test harness does), the file defines
# its functions and variables and does nothing else.
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
main "$@"
fi