From 1e9493461c823c0e206aa4753d722f67413faad7 Mon Sep 17 00:00:00 2001 From: Quinn Damerell Date: Sun, 5 Mar 2023 08:19:20 -0800 Subject: [PATCH] feat: add OctoEverywhere for Klipper (#300) Co-authored-by: th33xitus --- README.md | 27 ++- scripts/globals.sh | 4 + scripts/octoeverywhere.sh | 339 +++++++++++++++++++++++++++++++++++++ scripts/ui/install_menu.sh | 11 +- scripts/ui/main_menu.sh | 31 ++-- scripts/ui/remove_menu.sh | 5 +- scripts/ui/update_menu.sh | 9 +- 7 files changed, 400 insertions(+), 26 deletions(-) create mode 100644 scripts/octoeverywhere.sh diff --git a/README.md b/README.md index 4e24255..f7a0efd 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ -
+

@@ -78,22 +78,43 @@ git clone https://github.com/th33xitus/kiauh.git by jordanruthe by OctoPrint + +

Moonraker-Telegram-Bot

PrettyGCode for Klipper

Obico for Klipper

- + nlef avatar Kragrathea avatar Obico logo - + by nlef by Kragrathea by Obico + + +

+

OctoEverywhere For Klipper

+

+ + + + +OctoEverywhere Logo + + + + + +by Quinn Damerell + + + ## **Credits** diff --git a/scripts/globals.sh b/scripts/globals.sh index 81629d6..6ca19fc 100644 --- a/scripts/globals.sh +++ b/scripts/globals.sh @@ -69,6 +69,10 @@ function set_globals() { MOONRAKER_OBICO_DIR="${HOME}/moonraker-obico" MOONRAKER_OBICO_REPO="https://github.com/TheSpaghettiDetective/moonraker-obico.git" + #=============== OCTOEVERYWHERE ================# + OCTOEVERYWHERE_DIR="${HOME}/octoeverywhere" + OCTOEVERYWHERE_REPO="https://github.com/QuinnDamerell/OctoPrint-OctoEverywhere.git" + #=============== Crowsnest ================# CROWSNEST_DIR="${HOME}/crowsnest" CROWSNEST_REPO="https://github.com/mainsail-crew/crowsnest.git" diff --git a/scripts/octoeverywhere.sh b/scripts/octoeverywhere.sh new file mode 100644 index 0000000..6a2eb0f --- /dev/null +++ b/scripts/octoeverywhere.sh @@ -0,0 +1,339 @@ +#!/usr/bin/env bash + +#=======================================================================# +# Copyright (C) 2020 - 2022 Dominik Willner # +# # +# This file is part of KIAUH - Klipper Installation And Update Helper # +# https://github.com/th33xitus/kiauh # +# # +# This file may be distributed under the terms of the GNU GPLv3 license # +#=======================================================================# + +# +# This file is written and maintained by Quinn Damerell from OctoEverywhere +# Please contact our support team if you need any help! +# https://octoeverywhere.com/support +# + +set -e + +#===================================================# +#============== Install ============# +#===================================================# + +function octoeverywhere_systemd() { + local services + services=$(find "${SYSTEMD}" -maxdepth 1 -regextype posix-extended -regex "${SYSTEMD}/octoeverywhere(-[0-9a-zA-Z]+)?.service") + echo "${services}" +} + +function octoeverywhere_setup_dialog() { + status_msg "Initializing OctoEverywhere for Klipper installation ..." + + # First, check for moonraker service instances. + local moonraker_count + local moonraker_names + moonraker_count=$(moonraker_systemd | wc -w) + if (( moonraker_count == 0 )); then + ### return early if moonraker is not installed + local error="Moonraker not installed! Please install Moonraker first!" + log_error "OctoEverywhere setup started without Moonraker being installed. Aborting setup." + print_error "${error}" && return + elif (( moonraker_count > 1 )); then + # moonraker_names is valid only in case of multi-instance + read -r -a moonraker_names <<< "$(get_multi_instance_names)" + fi + + # Next, check for any existing OctoEverywhere services. + local octoeverywhere_services + local existing_octoeverywhere_count + octoeverywhere_services=$(octoeverywhere_systemd) + existing_octoeverywhere_count=$(echo "${octoeverywhere_services}" | wc -w ) + + # We need to make the moonraker instance count to the OctoEverywhere service count. + local allowed_octoeverywhere_count=$(( moonraker_count - existing_octoeverywhere_count )) + if (( allowed_octoeverywhere_count > 0 )); then + local new_octoeverywhere_count + + ### Step 1: Ask for the number of OctoEverywhere instances to install + if (( moonraker_count == 1 )); then + ok_msg "Moonraker installation found!\n" + new_octoeverywhere_count=1 + elif (( moonraker_count > 1 )); then + top_border + printf "|${green}%-55s${white}|\n" " ${moonraker_count} Moonraker instances found!" + for name in "${moonraker_names[@]}"; do + printf "|${cyan}%-57s${white}|\n" " ● moonraker-${name}" + done + blank_line + if (( existing_octoeverywhere_count > 0 )); then + printf "|${green}%-55s${white}|\n" " ${existing_octoeverywhere_count} OctoEverywhere instances already installed!" + for svc in ${octoeverywhere_services}; do + printf "|${cyan}%-57s${white}|\n" " ● octoeverywhere-$(get_instance_name "${svc}")" + done + fi + blank_line + echo -e "| The setup will apply the same names to |" + echo -e "| OctoEverywhere |" + blank_line + echo -e "| Please select the number of OctoEverywhere instances |" + echo -e "| to install. Usually one OctoEverywhere instance per |" + echo -e "| Moonraker instance is required, but you may not |" + echo -e "| install more OctoEverywhere instances than available |" + echo -e "| Moonraker instances. |" + bottom_border + + ### ask for amount of instances + local re="^[1-9][0-9]*$" + while [[ ! ${new_octoeverywhere_count} =~ ${re} || ${new_octoeverywhere_count} -gt ${allowed_octoeverywhere_count} ]]; do + read -p "${cyan}###### Number of new OctoEverywhere instances to set up:${white} " -i "${allowed_octoeverywhere_count}" -e new_octoeverywhere_count + ### break if input is valid + [[ ${new_octoeverywhere_count} =~ ${re} && ${new_octoeverywhere_count} -le ${allowed_octoeverywhere_count} ]] && break + ### conditional error messages + [[ ! ${new_octoeverywhere_count} =~ ${re} ]] && error_msg "Input not a number" + (( new_octoeverywhere_count > allowed_octoeverywhere_count )) && error_msg "Number of OctoEverywhere instances larger than installed Moonraker instances" + done && select_msg "${new_octoeverywhere_count}" + else + log_error "Internal error. moonraker_count of '${moonraker_count}' not equal or grater than one!" + return 1 + fi # (( moonraker_count == 1 )) + fi # (( allowed_octoeverywhere_count > 0 )) + + # Special case for one moonraker instance with OctoEverywhere already installed. + # If the user selects the install option again, they might be trying to recover the install + # or complete a printer link they didn't finish in the past. + # So in this case, we will allow them to run the install script again, since it's safe to run + # if the service is already installed, it will repair any missing issues. + if (( allowed_octoeverywhere_count == 0 && moonraker_count == 1 )); then + local yn + while true; do + echo "${yellow}OctoEverywhere is already installed.${white}" + echo "It is safe to run the install again to repair any issues or if the printer isn't linked, run the printer linking logic again." + echo "" + local question="Do you want to run the OctoEverywhere recovery or linking logic again?" + read -p "${cyan}###### ${question} (Y/n):${white} " yn + case "${yn}" in + Y|y|Yes|yes|"") + select_msg "Yes" + break;; + N|n|No|no) + select_msg "No" + abort_msg "Exiting OctoEverywhere setup ...\n" + return;; + *) + error_msg "Invalid Input!";; + esac + done + # The user responded yes, allow the install to run again. + allowed_octoeverywhere_count=1 + fi + + # If there's something to install, do it! + if (( allowed_octoeverywhere_count > 0 )); then + + (( new_octoeverywhere_count > 1 )) && status_msg "Installing ${new_octoeverywhere_count} OctoEverywhere instances ..." + (( new_octoeverywhere_count == 1 )) && status_msg "Installing OctoEverywhere ..." + + # Ensure the basic system dependencies are installed. + local dep=(git dfu-util virtualenv python3 python3-pip python3-venv) + dependency_check "${dep[@]}" + + # Close the repo + clone_octoeverywhere "${OCTOEVERYWHERE_REPO}" + + # Call install with the correct args. + local instance_cfg_dirs + read -r -a instance_cfg_dirs <<< "$(get_instance_folder_path "config")" + echo instance_cfg_dirs[0] + + if (( moonraker_count == 1 )); then + "${OCTOEVERYWHERE_DIR}/install.sh" "${instance_cfg_dirs[0]}/moonraker.conf" + elif (( moonraker_count > 1 )); then + local j=${existing_octoeverywhere_count} + + for (( i=1; i <= new_octoeverywhere_count; i++ )); do + "${OCTOEVERYWHERE_DIR}/install.sh" "${instance_cfg_dirs[${j}]}/moonraker.conf" + j=$(( j + 1 )) + done && unset j + fi # (( moonraker_count == 1 )) + fi # (( allowed_octoeverywhere_count > 0 )) +} + +function clone_octoeverywhere() { + local repo=${1} + + status_msg "Cloning OctoEverywhere..." + ### force remove existing repos + [[ -d "${OCTOEVERYWHERE_DIR}" ]] && rm -rf "${OCTOEVERYWHERE_DIR}" + + cd "${HOME}" || exit 1 + if ! git clone "${repo}" "${OCTOEVERYWHERE_DIR}"; then + print_error "Cloning OctoEverywhere from\n ${repo}\n failed!" + exit 1 + fi +} + +function octoeverywhere_install() { + "${OCTOEVERYWHERE_DIR}/install.sh" "$@" +} + +#===================================================# +#============= Remove ==============# +#===================================================# + +function remove_octoeverywhere_systemd() { + [[ -z $(octoeverywhere_systemd) ]] && return + status_msg "Removing OctoEverywhere Systemd Services ..." + + for service in $(octoeverywhere_systemd | cut -d"/" -f5); do + status_msg "Removing ${service} ..." + sudo systemctl stop "${service}" + sudo systemctl disable "${service}" + sudo rm -f "${SYSTEMD}/${service}" + ok_msg "Done!" + done + + ### reloading units + sudo systemctl daemon-reload + sudo systemctl reset-failed + ok_msg "OctoEverywhere Services removed!" +} + +function remove_octoeverywhere_logs() { + local files regex="${HOME//\//\\/}\/([A-Za-z0-9_]+)\/logs\/octoeverywhere(-[0-9a-zA-Z]+)?\.log(.*)?" + files=$(find "${HOME}" -maxdepth 3 -regextype posix-extended -regex "${regex}" | sort) + + if [[ -n ${files} ]]; then + for file in ${files}; do + status_msg "Removing ${file} ..." + rm -f "${file}" + ok_msg "${file} removed!" + done + fi +} + +function remove_octoeverywhere_dir() { + [[ ! -d ${OCTOEVERYWHERE_DIR} ]] && return + + status_msg "Removing OctoEverywhere directory ..." + rm -rf "${OCTOEVERYWHERE_DIR}" + ok_msg "Directory removed!" +} + +function remove_octoeverywhere_config() { + # Remove the system config but not the main config, so the printer id doesn't get lost. + local files regex="${HOME//\//\\/}\/([A-Za-z0-9_]+)\/config\/octoeverywhere-system(-[0-9a-zA-Z]+)?\.cfg(.*)?" + files=$(find "${HOME}" -maxdepth 4 -regextype posix-extended -regex "${regex}" | sort) + + if [[ -n ${files} ]]; then + for file in ${files}; do + status_msg "Removing ${file} ..." + rm -f "${file}" + ok_msg "${file} removed!" + done + fi +} + +function remove_octoeverywhere_store_dir() { + local files regex="${HOME//\//\\/}\/([A-Za-z0-9_]+)\/octoeverywhere-store" + files=$(find "${HOME}" -maxdepth 2 -type d -regextype posix-extended -regex "${regex}" | sort) + + if [[ -n ${files} ]]; then + for file in ${files}; do + status_msg "Removing ${file} ..." + rm -rf "${file}" + ok_msg "${file} removed!" + done + fi +} + +function remove_octoeverywhere_env() { + [[ ! -d "${HOME}/octoeverywhere-env" ]] && return + + status_msg "Removing octoeverywhere-env directory ..." + rm -rf "${HOME}/octoeverywhere-env" + ok_msg "Directory removed!" +} + +function remove_octoeverywhere() +{ + remove_octoeverywhere_systemd + remove_octoeverywhere_logs + remove_octoeverywhere_dir + remove_octoeverywhere_env + remove_octoeverywhere_config + remove_octoeverywhere_store_dir + + print_confirm "OctoEverywhere was successfully removed!" + return +} + +#===================================================# +#============= UPDATE ==============# +#===================================================# + +function update_octoeverywhere() { + # Since our update might require new python packages or system packages, ask the user to use the + # moonraker update manager to do it, since that takes care of it. + print_error "Please use the Moonraker Update Manager from the Mainsail or Fluidd UI to update OctoEverywhere.\n Contact our support team if you need help! support@octoeverywhere.com" +} + +#===================================================# +#============= STATUS ==============# +#===================================================# + +function get_octoeverywhere_status() { + local status + local service_count + local octoeverywhere_services + + octoeverywhere_services=$(octoeverywhere_systemd) + service_count=$(echo "${octoeverywhere_services}" | wc -w ) + + if (( service_count == 0 )); then + status="Not installed!" + elif [[ ! -d "${OCTOEVERYWHERE_DIR}" ]]; then + status="Incomplete!" + else + status="Installed!" + fi + + echo "${status}" +} + +function get_local_octoeverywhere_commit() { + [[ ! -d ${OCTOEVERYWHERE_DIR} || ! -d "${OCTOEVERYWHERE_DIR}/.git" ]] && return + + local commit + cd "${OCTOEVERYWHERE_DIR}" + commit="$(git describe HEAD --always --tags | cut -d "-" -f 1,2)" + echo "${commit}" +} + +function get_remote_octoeverywhere_commit() { + [[ ! -d ${OCTOEVERYWHERE_DIR} || ! -d "${OCTOEVERYWHERE_DIR}/.git" ]] && return + + local commit + cd "${OCTOEVERYWHERE_DIR}" && git fetch origin -q + commit=$(git describe origin/master --always --tags | cut -d "-" -f 1,2) + echo "${commit}" +} + +function compare_octoeverywhere_versions() { + local versions local_ver remote_ver + local_ver="$(get_local_octoeverywhere_commit)" + remote_ver="$(get_remote_octoeverywhere_commit)" + + if [[ ${local_ver} != "${remote_ver}" ]]; then + versions="${yellow}$(printf " %-14s" "${local_ver}")${white}" + versions+="|${green}$(printf " %-13s" "${remote_ver}")${white}" + # Don't do this, since we don't want Kiauh to update us, since we might need package updates. + # add moonraker to application_updates_available in kiauh.ini + # add_to_application_updates "octoeverywhere" + else + versions="${green}$(printf " %-14s" "${local_ver}")${white}" + versions+="|${green}$(printf " %-13s" "${remote_ver}")${white}" + fi + + echo "${versions}" +} diff --git a/scripts/ui/install_menu.sh b/scripts/ui/install_menu.sh index c17942f..c4a5820 100755 --- a/scripts/ui/install_menu.sh +++ b/scripts/ui/install_menu.sh @@ -26,9 +26,10 @@ function install_ui() { echo -e "| Klipper Webinterface: | 7) [PrettyGCode] |" echo -e "| 3) [Mainsail] | 8) [Telegram Bot] |" echo -e "| 4) [Fluidd] | 9) $(obico_install_title) |" - echo -e "| | |" - echo -e "| Touchscreen GUI: | Webcam Streamer: |" - echo -e "| 5) [KlipperScreen] | 10) [Crowsnest] |" + echo -e "| | 10) [OctoEverywhere] |" + echo -e "| Touchscreen GUI: | |" + echo -e "| 5) [KlipperScreen] | Webcam Streamer: |" + echo -e "| | 11) [Crowsnest] |" back_footer } @@ -64,7 +65,9 @@ function install_menu() { do_action "telegram_bot_setup_dialog" "install_ui";; 9) do_action "moonraker_obico_setup_dialog" "install_ui";; - 10) + 10) + do_action "octoeverywhere_setup_dialog" "install_ui";; + 11) do_action "install_crowsnest" "install_ui";; B|b) clear; main_menu; break;; diff --git a/scripts/ui/main_menu.sh b/scripts/ui/main_menu.sh index 42e9a06..d9f3b38 100755 --- a/scripts/ui/main_menu.sh +++ b/scripts/ui/main_menu.sh @@ -19,20 +19,21 @@ function main_ui() { top_border echo -e "| $(title_msg "~~~~~~~~~~~~~~~ [ Main Menu ] ~~~~~~~~~~~~~~~") |" hr - echo -e "| 0) [Log-Upload] | Klipper: $(print_status "klipper")|" - echo -e "| | Repo: $(print_klipper_repo)|" - echo -e "| 1) [Install] | |" - echo -e "| 2) [Update] | Moonraker: $(print_status "moonraker")|" - echo -e "| 3) [Remove] | |" - echo -e "| 4) [Advanced] | Mainsail: $(print_status "mainsail")|" -# echo -e "| 5) [Backup] | Fluidd: $(print_status "fluidd")|" - echo -e "| | Fluidd: $(print_status "fluidd")|" - echo -e "| | KlipperScreen: $(print_status "klipperscreen")|" - echo -e "| 6) [Settings] | Telegram Bot: $(print_status "telegram_bot")|" - echo -e "| | Crowsnest: $(print_status "crowsnest")|" - echo -e "| | Obico: $(print_status "moonraker_obico")|" - echo -e "| | |" - echo -e "| $(print_kiauh_version)| Octoprint: $(print_status "octoprint")|" + echo -e "| 0) [Log-Upload] | Klipper: $(print_status "klipper")|" + echo -e "| | Repo: $(print_klipper_repo)|" + echo -e "| 1) [Install] | |" + echo -e "| 2) [Update] | Moonraker: $(print_status "moonraker")|" + echo -e "| 3) [Remove] | |" + echo -e "| 4) [Advanced] | Mainsail: $(print_status "mainsail")|" +# echo -e "| 5) [Backup] | Fluidd: $(print_status "fluidd")|" + echo -e "| | Fluidd: $(print_status "fluidd")|" + echo -e "| | KlipperScreen: $(print_status "klipperscreen")|" + echo -e "| 6) [Settings] | Telegram Bot: $(print_status "telegram_bot")|" + echo -e "| | Crowsnest: $(print_status "crowsnest")|" + echo -e "| | Obico: $(print_status "moonraker_obico")|" + echo -e "| | OctoEverywhere: $(print_status "octoeverywhere")|" + echo -e "| | |" + echo -e "| $(print_kiauh_version)| Octoprint: $(print_status "octoprint")|" quit_footer } @@ -45,7 +46,7 @@ function get_kiauh_version() { function print_kiauh_version() { local version - version="$(printf "%-18s" "$(get_kiauh_version)")" + version="$(printf "%-16s" "$(get_kiauh_version)")" echo "${cyan}${version}${white}" } diff --git a/scripts/ui/remove_menu.sh b/scripts/ui/remove_menu.sh index d7408d0..79fec90 100755 --- a/scripts/ui/remove_menu.sh +++ b/scripts/ui/remove_menu.sh @@ -28,7 +28,8 @@ function remove_ui() { echo -e "| 6) [Fluidd-Config] | 11) [PrettyGCode] |" echo -e "| | 12) [Telegram Bot] |" echo -e "| Touchscreen GUI: | 13) [Obico for Klipper] |" - echo -e "| 7) [KlipperScreen] | 14) [NGINX] |" + echo -e "| 7) [KlipperScreen] | 14) [OctoEverywhere] |" + echo -e "| | 15) [NGINX] |" back_footer } @@ -66,6 +67,8 @@ function remove_menu() { 13) do_action "remove_moonraker_obico" "remove_ui";; 14) + do_action "remove_octoeverywhere" "remove_ui";; + 15) do_action "remove_nginx" "remove_ui";; B|b) clear; main_menu; break;; diff --git a/scripts/ui/update_menu.sh b/scripts/ui/update_menu.sh index 8e7f7a9..26a51e8 100755 --- a/scripts/ui/update_menu.sh +++ b/scripts/ui/update_menu.sh @@ -32,9 +32,10 @@ function update_ui() { echo -e "| 6) [PrettyGCode] |$(compare_prettygcode_versions)|" echo -e "| 7) [Telegram Bot] |$(compare_telegram_bot_versions)|" echo -e "| 8) [Obico for Klipper]|$(compare_moonraker_obico_versions)|" - echo -e "| 9) [Crowsnest] |$(compare_crowsnest_versions)|" + echo -e "| 9) [OctoEverywhere] |$(compare_octoeverywhere_versions)|" + echo -e "| 10) [Crowsnest] |$(compare_crowsnest_versions)|" echo -e "| |------------------------------|" - echo -e "| 10)[System] | $(check_system_updates) |" + echo -e "| 11) [System] | $(check_system_updates) |" back_footer } @@ -64,8 +65,10 @@ function update_menu() { 8) do_action "update_moonraker_obico" "update_ui";; 9) - do_action "update_crowsnest" "update_ui";; + do_action "update_octoeverywhere" "update_ui";; 10) + do_action "update_crowsnest" "update_ui";; + 11) do_action "update_system" "update_ui";; a) do_action "update_all" "update_ui";;