From d2896943f5cfa7a90b0a080b27a36b358923c55f Mon Sep 17 00:00:00 2001 From: th33xitus Date: Mon, 31 Oct 2022 20:40:31 +0100 Subject: [PATCH] refactor(klipper): full refactor of klipper install part Signed-off-by: Dominik Willner --- resources/klipper.service | 2 +- scripts/klipper.sh | 407 ++++++++++++++++++++----------------- scripts/ui/install_menu.sh | 32 +-- 3 files changed, 225 insertions(+), 216 deletions(-) diff --git a/resources/klipper.service b/resources/klipper.service index 7b55917..8c74cd4 100644 --- a/resources/klipper.service +++ b/resources/klipper.service @@ -1,5 +1,5 @@ [Unit] -Description=Klipper 3D Printer Firmware SV1 %INST% +Description=Klipper 3D Printer Firmware SV1 Documentation=https://www.klipper3d.org/ After=network-online.target Wants=udev.target diff --git a/scripts/klipper.sh b/scripts/klipper.sh index 26fb5a5..f8bd2f9 100644 --- a/scripts/klipper.sh +++ b/scripts/klipper.sh @@ -11,21 +11,33 @@ set -e +#TODO: +# the current changes do not allow to display feedback to the user +# regarding the decisions that were made during input prompts (select_msg) + +#TODO (multi instance): +# if the klipper installer is started another time while other klipper +# instances are detected, ask if new instances should be added + #=================================================# #================ INSTALL KLIPPER ================# #=================================================# -function klipper_setup_dialog() { - status_msg "Initializing Klipper installation ..." - +function start_klipper_setup() { local klipper_initd_service local klipper_systemd_services - local python_version="${1}" user_input=() + local python_version + local instance_count + local instance_names local error + status_msg "Initializing Klipper installation ...\n" + + print_user_select_klipper_python_version + python_version=$(user_select_klipper_python_version) + klipper_initd_service=$(find_klipper_initd) klipper_systemd_services=$(find_klipper_systemd) - user_input+=("${python_version}") ### return early if klipper already exists if [[ -n ${klipper_initd_service} ]]; then @@ -45,6 +57,62 @@ function klipper_setup_dialog() { [[ -n ${error} ]] && print_error "${error}" && return ### ask for amount of instances to create + print_user_select_instance_count + instance_count=$(user_select_instance_count) + + ### ask for custom names + if (( instance_count > 1 )); then + print_user_select_instance_names + instance_names=$(user_select_instance_names "${instance_count}") + else + instance_names+=("printer") + fi + + (( instance_count > 1 )) && status_msg "Installing ${instance_count} Klipper instances ..." + (( instance_count == 1 )) && status_msg "Installing single Klipper instance ..." + + run_klipper_setup "${python_version}" "${instance_names[@]}" +} + +function print_user_select_klipper_python_version() { + top_border + echo -e "| Please select the preferred Python version. | " + echo -e "| The recommended version is Python 2.7. | " + blank_line + echo -e "| Installing Klipper with Python 3 is officially not | " + echo -e "| recommended and should be considered as experimental. | " + hr + echo -e "| 1) [Python 2.7] (recommended) | " + echo -e "| 2) [Python 3.x] ${yellow}(experimental)${white} | " + back_footer +} + +function user_select_klipper_python_version() { + local python_version + local option + + while true; do + read -p "${cyan}###### Select Python version:${white} " option + case "${option}" in + 1) + #select_msg "Python 2.7" + python_version=2 + break;; + 2) + #select_msg "Python 3.x" + python_version=3 + break;; + B|b) + clear; install_menu; break;; + *) + error_msg "Invalid Input!\n";; + esac + done + + echo "${python_version}" +} + +function print_user_select_instance_count() { top_border echo -e "| Please select the number of Klipper instances to set |" echo -e "| up. The number of Klipper instances will determine |" @@ -52,100 +120,107 @@ function klipper_setup_dialog() { blank_line echo -e "| ${yellow}WARNING:${white} |" echo -e "| ${yellow}Setting up too many instances may crash your system.${white} |" - bottom_border + back_footer +} - ### ask for amount of instances - local klipper_count re="^[1-9][0-9]*$" - while [[ ! ${klipper_count} =~ ${re} ]]; do - read -p "${cyan}###### Number of Klipper instances to set up:${white} " -i "1" -e klipper_count - ### break if input is valid - [[ ${klipper_count} =~ ${re} ]] && break - ### error messages on invalid input - error_msg "Input not a number" - done && select_msg "${klipper_count}" +function user_select_instance_count() { + local regex + local input + local instance_count - user_input+=("${klipper_count}") + regex="^[1-9][0-9]*$" + while [[ ! ${input} =~ ${regex} ]]; do + read -p "${cyan}###### Number of Klipper instances to set up:${white} " -i "1" -e input - ### confirm instance amount - local yn + if [[ ${input} =~ ${regex} ]]; then + instance_count="${input}" + break + else + error_msg "Input not a number" + fi + done + + echo "${instance_count}" +} + +function print_user_select_instance_names() { + top_border + echo -e "| You can now assign a custom name to each instance. |" + echo -e "| If skipped, each instance will get an index assigned |" + echo -e "| in ascending order, starting at index '1'. |" + blank_line + echo -e "| Info: |" + echo -e "| Only alphanumeric characters for names are allowed! |" + back_footer +} + +function user_select_instance_names() { + local instance_count=${1} + local use_custom_names + local instance_names + local input + local regex + local i + + use_custom_names="false" while true; do - read -p "${cyan}###### Install ${klipper_count} instance(s)? (Y/n):${white} " yn - case "${yn}" in - Y|y|Yes|yes|"") - select_msg "Yes" + read -p "${cyan}###### Assign custom names? (y/N):${white} " input + + case "${input}" in + Y|y|Yes|yes) + #select_msg "Yes" + use_custom_names="true" break;; - N|n|No|no) - select_msg "No" - abort_msg "Exiting Klipper setup ...\n" - return;; + N|n|No|no|"") + #select_msg "No" + break;; + B|b) + clear; install_menu; break;; *) error_msg "Invalid Input!";; esac done - ### ask for custom names - if (( klipper_count > 1 )); then - local custom_names="false" - top_border - echo -e "| You can give each instance a custom name or skip. |" - echo -e "| If skipped, KIAUH will automatically assign an index |" - echo -e "| to each instance in ascending order, starting at '1'. |" - blank_line - echo -e "| Info: |" - echo -e "| Only alphanumeric characters will be allowed. |" - bottom_border - while true; do - read -p "${cyan}###### Use custom names? (y/N):${white} " yn - case "${yn}" in - Y|y|Yes|yes) - select_msg "Yes" - custom_names="true" - break;; - N|n|No|no|"") - select_msg "No" - break;; - *) - error_msg "Invalid Input!";; - esac - done + if [[ ${use_custom_names} == "true" ]]; then + i=1 + regex="^[0-9a-zA-Z]+$" - ### get user input for custom names - if [[ ${custom_names} == "true" ]]; then - local i=1 name re="^[0-9a-zA-Z]+$" - while [[ ! ${name} =~ ${re} || ${i} -le ${klipper_count} ]]; do - read -p "${cyan}###### Name for instance #${i}:${white} " name - if [[ ${name} =~ ${re} ]]; then - select_msg "Name: ${name}" - user_input+=("${name}") - i=$(( i + 1 )) - else - error_msg "Invalid Input!" - fi - done - else - ### if no custom names are used, add the respective amount of indices to the user_input array - for (( i=1; i <= klipper_count; i++ )); do - user_input+=("${i}") - done - fi + while [[ ! ${input} =~ ${regex} || ${i} -le ${instance_count} ]]; do + read -p "${cyan}###### Name for instance #${i}:${white} " input + + if [[ ${input} =~ ${regex} ]]; then + #select_msg "Name: ${input}" + instance_names+=("${input}") + i=$(( i + 1 )) + else + error_msg "Invalid Input!" + fi + done + else + ### if no custom names are used, add the respective amount of indices to the user_input array + for (( i=1; i <= instance_count; i++ )); do + instance_names+=("printer_${i}") + done fi - - (( klipper_count > 1 )) && status_msg "Installing ${klipper_count} Klipper instances ..." - (( klipper_count == 1 )) && status_msg "Installing single Klipper instance ..." - - klipper_setup "${user_input[@]}" + echo "${instance_names[@]}" } -function klipper_setup() { +function run_klipper_setup() { read_kiauh_ini "${FUNCNAME[0]}" - ### index 0: python version, index 1: instance count, index 2-n: instance names (optional) - local user_input=("${@}") - local python_version="${user_input[0]}" && unset "user_input[0]" - local instance_arr=("${user_input[@]}") && unset "user_input[@]" - local custom_repo="${custom_klipper_repo}" - local custom_branch="${custom_klipper_repo_branch}" - local dep=(git) + + local python_version=${1} + local instance_names + read -r -a instance_names <<< "${2}" + + local confirm + local custom_repo + local custom_branch + local dep + + custom_repo="${custom_klipper_repo}" + custom_branch="${custom_klipper_repo_branch}" + dep=(git) ### checking dependencies dependency_check "${dep[@]}" @@ -158,7 +233,9 @@ function klipper_setup() { create_klipper_virtualenv "${python_version}" ### step 3: configure and create klipper instances - configure_klipper_service "${instance_arr[@]}" + for instance in "${instance_names[@]}"; do + configure_klipper_service "${instance}" + done ### step 4: enable and start all instances do_action_service "enable" "klipper" @@ -168,9 +245,8 @@ function klipper_setup() { check_usergroups ### confirm message - local confirm="" - (( instance_arr[0] == 1 )) && confirm="Klipper has been set up!" - (( instance_arr[0] > 1 )) && confirm="${instance_arr[0]} Klipper instances have been set up!" + (( ${#instance_names[@]} == 1 )) && confirm="Klipper has been set up!" + (( ${#instance_names[@]} > 1 )) && confirm="${#instance_names[@]} Klipper instances have been set up!" ### finalizing the setup with writing instance names to the kiauh.ini set_multi_instance_names @@ -204,37 +280,18 @@ function clone_klipper() { function create_klipper_virtualenv() { local python_version="${1}" - [[ ${python_version} == "python2" ]] && \ - status_msg "Installing $(python2 -V) virtual environment..." - - [[ ${python_version} == "python3" ]] && \ - status_msg "Installing $(python3 -V) virtual environment..." - - ### remove klippy-env if it already exists [[ -d ${KLIPPY_ENV} ]] && rm -rf "${KLIPPY_ENV}" - if [[ ${python_version} == "python2" ]]; then - if virtualenv -p python2 "${KLIPPY_ENV}"; then - "${KLIPPY_ENV}"/bin/pip install -r "${KLIPPER_DIR}"/scripts/klippy-requirements.txt - else - log_error "failure while creating python2 klippy-env" - error_msg "Creation of Klipper virtualenv failed!" - exit 1 - fi - fi + status_msg "Installing $("python${python_version}" -V) virtual environment..." - if [[ ${python_version} == "python3" ]]; then - if virtualenv -p python3 "${KLIPPY_ENV}"; then - "${KLIPPY_ENV}"/bin/pip install -U pip - "${KLIPPY_ENV}"/bin/pip install -r "${KLIPPER_DIR}"/scripts/klippy-requirements.txt - else - log_error "failure while creating python3 klippy-env" - error_msg "Creation of Klipper virtualenv failed!" - exit 1 - fi + if virtualenv -p "python${python_version}" "${KLIPPY_ENV}"; then + (( python_version == 3 )) && "${KLIPPY_ENV}"/bin/pip install -U pip + "${KLIPPY_ENV}"/bin/pip install -r "${KLIPPER_DIR}"/scripts/klippy-requirements.txt + else + log_error "failure while creating python3 klippy-env" + error_msg "Creation of Klipper virtualenv failed!" + exit 1 fi - - return } ### @@ -255,10 +312,10 @@ function install_klipper_packages() { ### add dbus requirement for DietPi distro [[ -e "/boot/dietpi/.version" ]] && packages+=" dbus" - if [[ ${python_version} == "python3" ]]; then + if (( python_version == 3 )); then ### replace python-dev with python3-dev if python3 was selected packages="${packages//python-dev/python3-dev}" - elif [[ ${python_version} == "python2" ]]; then + elif (( python_version == 2 )); then ### package name 'python-dev' is deprecated (-> no installation candidate) on more modern linux distros packages="${packages//python-dev/python2-dev}" else @@ -288,94 +345,76 @@ function install_klipper_packages() { } function configure_klipper_service() { - local input=("${@}") - local klipper_count=${input[0]} && unset "input[0]" - local names=("${input[@]}") && unset "input[@]" - local printer_data cfg_dir cfg log printer uds service env_file + local instance_name=${1} - if (( klipper_count == 1 )) && [[ ${#names[@]} -eq 0 ]]; then - printer_data="${HOME}/printer_data" - cfg_dir="${printer_data}/config" - cfg="${cfg_dir}/printer.cfg" - log="${printer_data}/logs/klippy.log" - printer="${printer_data}/comms/klippy.serial" - uds="${printer_data}/comms/klippy.sock" - service="${SYSTEMD}/klipper.service" - env_file="${printer_data}/systemd/klipper.env" + local printer_data + local cfg_dir + local cfg + local log + local printer + local uds + local env_file + local service + local suffix - ### create required folder structure - create_required_folders "${printer_data}" - - ### write single instance service - write_klipper_service "" "${cfg}" "${log}" "${printer}" "${uds}" "${service}" "${env_file}" - write_example_printer_cfg "${cfg_dir}" "${cfg}" - ok_msg "Klipper instance created!" - - elif (( klipper_count >= 1 )) && [[ ${#names[@]} -gt 0 ]]; then - local j=0 re="^[1-9][0-9]*$" - - for (( i=1; i <= klipper_count; i++ )); do - ### overwrite config folder if name is only a number - if [[ ${names[j]} =~ ${re} ]]; then - printer_data="${HOME}/printer_${names[${j}]}_data" - else - printer_data="${HOME}/${names[${j}]}_data" - fi - - cfg_dir="${printer_data}/config" - cfg="${cfg_dir}/printer.cfg" - log="${printer_data}/logs/klippy.log" - printer="${printer_data}/comms/klippy.serial" - uds="${printer_data}/comms/klippy.sock" - service="${SYSTEMD}/klipper-${names[${j}]}.service" - env_file="${printer_data}/systemd/klipper.env" - - ### create required folder structure - create_required_folders "${printer_data}" - - ### write multi instance service - write_klipper_service "${names[${j}]}" "${cfg}" "${log}" "${printer}" "${uds}" "${service}" "${env_file}" - write_example_printer_cfg "${cfg_dir}" "${cfg}" - ok_msg "Klipper instance 'klipper-${names[${j}]}' created!" - j=$(( j + 1 )) - done && unset j + printer_data="${HOME}/${instance_name}_data" + cfg_dir="${printer_data}/config" + cfg="${cfg_dir}/printer.cfg" + log="${printer_data}/logs/klippy.log" + printer="${printer_data}/comms/klippy.serial" + uds="${printer_data}/comms/klippy.sock" + env_file="${printer_data}/systemd/klipper.env" + if [[ ${instance_name} == "printer" ]]; then + suffix="${instance_name//printer/}" else - return 1 + suffix="-${instance_name//printer_/}" fi + + service="${SYSTEMD}/klipper${suffix}.service" + + create_required_folders "${printer_data}" + write_klipper_service "${cfg}" "${log}" "${printer}" "${uds}" "${service}" "${env_file}" + write_example_printer_cfg "${cfg}" } function write_klipper_service() { - local i=${1} cfg=${2} log=${3} printer=${4} uds=${5} service=${6} env_file=${7} - local service_template="${KIAUH_SRCDIR}/resources/klipper.service" - local env_template="${KIAUH_SRCDIR}/resources/klipper.env" + local cfg=${1} + local log=${2} + local printer=${3} + local uds=${4} + local service=${5} + local env_file=${6} + + local service_template + local env_template + + service_template="${KIAUH_SRCDIR}/resources/klipper.service" + env_template="${KIAUH_SRCDIR}/resources/klipper.env" - ### replace all placeholders if [[ ! -f ${service} ]]; then - status_msg "Creating Klipper Service ${i} ..." + status_msg "Write Klipper service file ..." + sudo cp "${service_template}" "${service}" sudo cp "${env_template}" "${env_file}" - [[ -z ${i} ]] && sudo sed -i "s| %INST%||" "${service}" - [[ -n ${i} ]] && sudo sed -i "s|%INST%|${i}|" "${service}" sudo sed -i "s|%USER%|${USER}|g; s|%ENV%|${KLIPPY_ENV}|; s|%ENV_FILE%|${env_file}|" "${service}" sudo sed -i "s|%USER%|${USER}|; s|%LOG%|${log}|; s|%CFG%|${cfg}|; s|%PRINTER%|${printer}|; s|%UDS%|${uds}|" "${env_file}" + + ok_msg "Klipper service file created!" fi } function write_example_printer_cfg() { - local cfg_dir=${1} cfg=${2} - local cfg_template="${KIAUH_SRCDIR}/resources/example.printer.cfg" + local cfg=${1} + local cfg_template - ### create a config directory if it doesn't exist - if [[ ! -d ${cfg_dir} ]]; then - status_msg "Creating '${cfg_dir}' ..." - mkdir -p "${cfg_dir}" - fi + cfg_template="${KIAUH_SRCDIR}/resources/example.printer.cfg" - ### create a minimal config if there is no printer.cfg - if [[ ! -f ${cfg} ]]; then - status_msg "Creating minimal example printer.cfg ..." - cp "${cfg_template}" "${cfg}" + status_msg "Creating minimal example printer.cfg ..." + if cp "${cfg_template}" "${cfg}"; then + ok_msg "Minimal example printer.cfg created!" + else + error_msg "Couldn't create minimal example printer.cfg!" fi } diff --git a/scripts/ui/install_menu.sh b/scripts/ui/install_menu.sh index 53656f1..78e4f03 100755 --- a/scripts/ui/install_menu.sh +++ b/scripts/ui/install_menu.sh @@ -47,7 +47,7 @@ function install_menu() { read -p "${cyan}####### Perform action:${white} " action case "${action}" in 1) - do_action "select_klipper_python_version" "install_ui";; + do_action "start_klipper_setup" "install_ui";; 2) do_action "moonraker_setup_dialog" "install_ui";; 3) @@ -77,33 +77,3 @@ function install_menu() { done install_menu } - -function select_klipper_python_version() { - top_border - echo -e "| Please select the preferred Python version. | " - echo -e "| The recommended version is Python 2.7. | " - blank_line - echo -e "| Installing Klipper with Python 3 is officially not | " - echo -e "| recommended and should be considered as experimental. | " - hr - echo -e "| 1) [Python 2.7] (recommended) | " - echo -e "| 2) [Python 3.x] ${yellow}(experimental)${white} | " - back_footer - while true; do - read -p "${cyan}###### Select Python version:${white} " action - case "${action}" in - 1) - select_msg "Python 2.7" - klipper_setup_dialog "python2" - break;; - 2) - select_msg "Python 3.x" - klipper_setup_dialog "python3" - break;; - B|b) - clear; install_menu; break;; - *) - error_msg "Invalid Input!\n";; - esac - done -}