mirror of
https://github.com/dw-0/kiauh.git
synced 2025-12-14 19:14:27 +05:00
240 lines
7.8 KiB
Python
240 lines
7.8 KiB
Python
# ======================================================================= #
|
|
# Copyright (C) 2020 - 2024 Dominik Willner <th33xitus@gmail.com> #
|
|
# #
|
|
# This file is part of KIAUH - Klipper Installation And Update Helper #
|
|
# https://github.com/dw-0/kiauh #
|
|
# #
|
|
# This file may be distributed under the terms of the GNU GPLv3 license #
|
|
# ======================================================================= #
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
from typing import Dict, List, Tuple
|
|
|
|
from components.klipper import (
|
|
EXIT_KLIPPER_SETUP,
|
|
KLIPPER_DIR,
|
|
KLIPPER_ENV_DIR,
|
|
KLIPPER_INSTALL_SCRIPT,
|
|
KLIPPER_REQ_FILE,
|
|
)
|
|
from components.klipper.klipper import Klipper
|
|
from components.klipper.klipper_dialogs import (
|
|
print_select_custom_name_dialog,
|
|
)
|
|
from components.klipper.klipper_utils import (
|
|
assign_custom_name,
|
|
backup_klipper_dir,
|
|
check_user_groups,
|
|
create_example_printer_cfg,
|
|
get_install_count,
|
|
handle_disruptive_system_packages,
|
|
)
|
|
from components.moonraker.moonraker import Moonraker
|
|
from components.webui_client.client_utils import (
|
|
get_existing_clients,
|
|
)
|
|
from core.instance_manager.instance_manager import InstanceManager
|
|
from core.logger import DialogType, Logger
|
|
from core.settings.kiauh_settings import KiauhSettings
|
|
from utils.common import check_install_dependencies
|
|
from utils.git_utils import git_clone_wrapper, git_pull_wrapper
|
|
from utils.input_utils import get_confirm
|
|
from utils.instance_utils import get_instances
|
|
from utils.sys_utils import (
|
|
cmd_sysctl_manage,
|
|
cmd_sysctl_service,
|
|
create_python_venv,
|
|
install_python_requirements,
|
|
parse_packages_from_file,
|
|
)
|
|
|
|
|
|
def install_klipper() -> None:
|
|
Logger.print_status("Installing Klipper ...")
|
|
|
|
klipper_list: List[Klipper] = get_instances(Klipper)
|
|
moonraker_list: List[Moonraker] = get_instances(Moonraker)
|
|
match_moonraker: bool = False
|
|
|
|
# if there are more moonraker instances than klipper instances, ask the user to
|
|
# match the klipper instance count to the count of moonraker instances with the same suffix
|
|
if len(moonraker_list) > len(klipper_list):
|
|
is_confirmed = display_moonraker_info(moonraker_list)
|
|
if not is_confirmed:
|
|
Logger.print_status(EXIT_KLIPPER_SETUP)
|
|
return
|
|
match_moonraker = True
|
|
|
|
install_count, name_dict = get_install_count_and_name_dict(
|
|
klipper_list, moonraker_list
|
|
)
|
|
|
|
if install_count == 0:
|
|
Logger.print_status(EXIT_KLIPPER_SETUP)
|
|
return
|
|
|
|
is_multi_install = install_count > 1 or (len(name_dict) >= 1 and install_count >= 1)
|
|
if not name_dict and install_count == 1:
|
|
name_dict = {0: ""}
|
|
elif is_multi_install and not match_moonraker:
|
|
custom_names = use_custom_names_or_go_back()
|
|
if custom_names is None:
|
|
Logger.print_status(EXIT_KLIPPER_SETUP)
|
|
return
|
|
|
|
handle_instance_names(install_count, name_dict, custom_names)
|
|
|
|
create_example_cfg = get_confirm("Create example printer.cfg?")
|
|
# run the actual installation
|
|
try:
|
|
run_klipper_setup(klipper_list, name_dict, create_example_cfg)
|
|
except Exception as e:
|
|
Logger.print_error(e)
|
|
Logger.print_error("Klipper installation failed!")
|
|
return
|
|
|
|
|
|
def run_klipper_setup(
|
|
klipper_list: List[Klipper], name_dict: Dict[int, str], create_example_cfg: bool
|
|
) -> None:
|
|
if not klipper_list:
|
|
setup_klipper_prerequesites()
|
|
|
|
for i in name_dict:
|
|
# skip this iteration if there is already an instance with the name
|
|
if name_dict[i] in [n.suffix for n in klipper_list]:
|
|
continue
|
|
|
|
instance = Klipper(suffix=name_dict[i])
|
|
instance.create()
|
|
cmd_sysctl_service(instance.service_file_path.name, "enable")
|
|
|
|
if create_example_cfg:
|
|
# if a client-config is installed, include it in the new example cfg
|
|
clients = get_existing_clients()
|
|
create_example_printer_cfg(instance, clients)
|
|
|
|
cmd_sysctl_service(instance.service_file_path.name, "start")
|
|
|
|
cmd_sysctl_manage("daemon-reload")
|
|
|
|
# step 4: check/handle conflicting packages/services
|
|
handle_disruptive_system_packages()
|
|
|
|
# step 5: check for required group membership
|
|
check_user_groups()
|
|
|
|
|
|
def handle_instance_names(
|
|
install_count: int, name_dict: Dict[int, str], custom_names: bool
|
|
) -> None:
|
|
for i in range(install_count): # 3
|
|
key: int = len(name_dict.keys()) + 1
|
|
if custom_names:
|
|
assign_custom_name(key, name_dict)
|
|
else:
|
|
name_dict[key] = str(len(name_dict) + 1)
|
|
|
|
|
|
def get_install_count_and_name_dict(
|
|
klipper_list: List[Klipper], moonraker_list: List[Moonraker]
|
|
) -> Tuple[int, Dict[int, str]]:
|
|
install_count: int | None
|
|
if len(moonraker_list) > len(klipper_list):
|
|
install_count = len(moonraker_list)
|
|
name_dict = {i: moonraker.suffix for i, moonraker in enumerate(moonraker_list)}
|
|
else:
|
|
install_count = get_install_count()
|
|
name_dict = {i: klipper.suffix for i, klipper in enumerate(klipper_list)}
|
|
|
|
if install_count is None:
|
|
Logger.print_status(EXIT_KLIPPER_SETUP)
|
|
return 0, {}
|
|
|
|
return install_count, name_dict
|
|
|
|
|
|
def setup_klipper_prerequesites() -> None:
|
|
settings = KiauhSettings()
|
|
repo = settings.klipper.repo_url
|
|
branch = settings.klipper.branch
|
|
|
|
git_clone_wrapper(repo, KLIPPER_DIR, branch)
|
|
|
|
# install klipper dependencies and create python virtualenv
|
|
try:
|
|
install_klipper_packages()
|
|
if create_python_venv(KLIPPER_ENV_DIR):
|
|
install_python_requirements(KLIPPER_ENV_DIR, KLIPPER_REQ_FILE)
|
|
except Exception:
|
|
Logger.print_error("Error during installation of Klipper requirements!")
|
|
raise
|
|
|
|
|
|
def install_klipper_packages() -> None:
|
|
script = KLIPPER_INSTALL_SCRIPT
|
|
packages = parse_packages_from_file(script)
|
|
|
|
# Add dbus requirement for DietPi distro
|
|
if Path("/boot/dietpi/.version").exists():
|
|
packages.append("dbus")
|
|
|
|
check_install_dependencies({*packages})
|
|
|
|
|
|
def update_klipper() -> None:
|
|
Logger.print_dialog(
|
|
DialogType.WARNING,
|
|
[
|
|
"Do NOT continue if there are ongoing prints running!",
|
|
"All Klipper instances will be restarted during the update process and "
|
|
"ongoing prints WILL FAIL.",
|
|
],
|
|
)
|
|
|
|
if not get_confirm("Update Klipper now?"):
|
|
return
|
|
|
|
settings = KiauhSettings()
|
|
if settings.kiauh.backup_before_update:
|
|
backup_klipper_dir()
|
|
|
|
instances = get_instances(Klipper)
|
|
InstanceManager.stop_all(instances)
|
|
|
|
git_pull_wrapper(repo=settings.klipper.repo_url, target_dir=KLIPPER_DIR)
|
|
|
|
# install possible new system packages
|
|
install_klipper_packages()
|
|
# install possible new python dependencies
|
|
install_python_requirements(KLIPPER_ENV_DIR, KLIPPER_REQ_FILE)
|
|
|
|
InstanceManager.start_all(instances)
|
|
|
|
|
|
def use_custom_names_or_go_back() -> bool | None:
|
|
print_select_custom_name_dialog()
|
|
_input: bool | None = get_confirm(
|
|
"Assign custom names?",
|
|
False,
|
|
allow_go_back=True,
|
|
)
|
|
return _input
|
|
|
|
|
|
def display_moonraker_info(moonraker_list: List[Moonraker]) -> bool:
|
|
# todo: only show the klipper instances that are not already installed
|
|
Logger.print_dialog(
|
|
DialogType.INFO,
|
|
[
|
|
"Existing Moonraker instances detected:",
|
|
*[f"● {m.service_file_path.stem}" for m in moonraker_list],
|
|
"\n\n",
|
|
"The following Klipper instances will be installed:",
|
|
*[f"● klipper-{m.suffix}" for m in moonraker_list],
|
|
],
|
|
)
|
|
_input: bool = get_confirm("Proceed with installation?")
|
|
return _input
|