Compare commits

..

9 Commits

Author SHA1 Message Date
dw-0
243ea6582a Release v6.0.0-alpha.10
Merge develop into master (Release v6.0.0-alpha.10)
2024-11-23 21:17:51 +01:00
dw-0
a63cf8c9d9 Release v6.0.0-alpha.9
Merge develop into master (Release v6.0.0-alpha.9)
2024-10-24 12:29:24 +02:00
dw-0
425d86a12f Release v6.0.0-alpha.8
Merge develop into master (Release v6.0.0-alpha.8)
2024-10-21 19:45:55 +02:00
dw-0
1b5691f2f5 Release v6.0.0-alpha.7
Merge develop into master (v6.0.0-alpha.7)

fixes #561
fixes #564
fixes #565
2024-10-13 11:51:19 +02:00
dw-0
dc026a7a2b Release v6.0.0-alpha.6
Merge develop into master (v6.0.0-alpha.6)

fixes #545
fixes #553
fixes #557
2024-10-05 08:29:40 +02:00
dw-0
a8a73249a5 Release v6.0.0-alpha.5
Merge develop into master (v6.0.0-alpha.5)
2024-09-26 20:55:22 +02:00
dw-0
ec3f93eeda Release v6.0.0-alpha.4
Merge develop into master (v6.0.0-alpha.4)
2024-09-22 09:43:04 +02:00
dw-0
4cf523a758 Merge pull request #524 from dw-0/develop
Merge develop into master
2024-09-08 19:04:19 +02:00
dw-0
1d06bf76f3 Merge pull request #511 from dw-0/develop
Merge develop into master
2024-09-01 19:02:48 +02:00
14 changed files with 106 additions and 153 deletions

View File

@@ -46,14 +46,11 @@ def run_klipper_removal(
Logger.print_info("No Klipper Services installed! Skipped ...")
if (remove_dir or remove_env) and unit_file_exists("klipper", suffix="service"):
completion_msg.text.extend(
[
"\n\n",
"Some Klipper services are still installed:",
f"'{KLIPPER_DIR}' was not removed.",
f"'{KLIPPER_ENV_DIR}' was not removed.",
]
)
completion_msg.text = [
"Some Klipper services are still installed:",
f"'{KLIPPER_DIR}' was not removed, even though selected for removal.",
f"'{KLIPPER_ENV_DIR}' was not removed, even though selected for removal.",
]
else:
if remove_dir:
Logger.print_status("Removing Klipper local repository ...")

View File

@@ -36,9 +36,7 @@ from components.webui_client.client_utils import (
)
from core.instance_manager.instance_manager import InstanceManager
from core.logger import DialogType, Logger
from core.services.message_service import Message
from core.settings.kiauh_settings import KiauhSettings
from core.types.color import Color
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
@@ -52,15 +50,9 @@ from utils.sys_utils import (
)
def install_klipper() -> Message:
def install_klipper() -> None:
Logger.print_status("Installing Klipper ...")
completion_msg = Message(
title="Klipper Installation Process completed",
text=["Klipper installation canceled by the user!"],
color=Color.YELLOW,
)
klipper_list: List[Klipper] = get_instances(Klipper)
moonraker_list: List[Moonraker] = get_instances(Moonraker)
match_moonraker: bool = False
@@ -68,21 +60,28 @@ def install_klipper() -> Message:
# 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):
if not match_moonraker_instances(moonraker_list):
return completion_msg
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:
return completion_msg
Logger.print_status(EXIT_KLIPPER_SETUP)
return
handle_instance_names(install_count, name_dict, custom_names)
@@ -92,10 +91,8 @@ def install_klipper() -> Message:
run_klipper_setup(klipper_list, name_dict, create_example_cfg)
except Exception as e:
Logger.print_error(e)
completion_msg.color = Color.RED
completion_msg.text = ["Klipper installation failed!"]
return completion_msg
Logger.print_error("Klipper installation failed!")
return
def run_klipper_setup(
@@ -158,7 +155,7 @@ def get_install_count_and_name_dict(
return install_count, name_dict
def setup_klipper_prerequesites() -> bool:
def setup_klipper_prerequesites() -> None:
settings = KiauhSettings()
repo = settings.klipper.repo_url
branch = settings.klipper.branch
@@ -174,8 +171,6 @@ def setup_klipper_prerequesites() -> bool:
Logger.print_error("Error during installation of Klipper requirements!")
raise
return True
def install_klipper_packages() -> None:
script = KLIPPER_INSTALL_SCRIPT
@@ -228,7 +223,7 @@ def use_custom_names_or_go_back() -> bool | None:
return _input
def match_moonraker_instances(moonraker_list: List[Moonraker]) -> bool:
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,

View File

@@ -14,7 +14,6 @@ from typing import Type
from components.klipper import klipper_remove
from core.menus import FooterType, Option
from core.menus.base_menu import BaseMenu
from core.menus.utils.menu_utils import get_checkbox_state
from core.types.color import Color
@@ -48,9 +47,11 @@ class KlipperRemoveMenu(BaseMenu):
}
def print_menu(self) -> None:
o1 = get_checkbox_state(self.remove_klipper_service)
o2 = get_checkbox_state(self.remove_klipper_dir)
o3 = get_checkbox_state(self.remove_klipper_env)
checked = f"[{Color.apply('x', Color.CYAN)}]"
unchecked = "[ ]"
o1 = checked if self.remove_klipper_service else unchecked
o2 = checked if self.remove_klipper_dir else unchecked
o3 = checked if self.remove_klipper_env else unchecked
sel_state = f"{'Select'if not self.select_state else 'Deselect'} everything"
menu = textwrap.dedent(
f"""

View File

@@ -12,9 +12,8 @@ import textwrap
from typing import Type
from components.moonraker import moonraker_remove
from core.menus import FooterType, Option
from core.menus import Option
from core.menus.base_menu import BaseMenu
from core.menus.utils.menu_utils import get_checkbox_state
from core.types.color import Color
@@ -22,17 +21,14 @@ from core.types.color import Color
class MoonrakerRemoveMenu(BaseMenu):
def __init__(self, previous_menu: Type[BaseMenu] | None = None):
super().__init__()
self.title = "Remove Moonraker"
self.title_color = Color.RED
self.previous_menu: Type[BaseMenu] | None = previous_menu
self.footer_type = FooterType.BACK
self.remove_moonraker_service = False
self.remove_moonraker_dir = False
self.remove_moonraker_env = False
self.remove_moonraker_polkit = False
self.select_state = False
self.selection_state = False
def set_previous_menu(self, previous_menu: Type[BaseMenu] | None) -> None:
from core.menus.remove_menu import RemoveMenu
@@ -50,18 +46,19 @@ class MoonrakerRemoveMenu(BaseMenu):
}
def print_menu(self) -> None:
o1 = get_checkbox_state(self.remove_moonraker_service)
o2 = get_checkbox_state(self.remove_moonraker_dir)
o3 = get_checkbox_state(self.remove_moonraker_env)
o4 = get_checkbox_state(self.remove_moonraker_polkit)
sel_state = f"{'Select'if not self.select_state else 'Deselect'} everything"
checked = f"[{Color.apply('x', Color.CYAN)}]"
unchecked = "[ ]"
o1 = checked if self.remove_moonraker_service else unchecked
o2 = checked if self.remove_moonraker_dir else unchecked
o3 = checked if self.remove_moonraker_env else unchecked
o4 = checked if self.remove_moonraker_polkit else unchecked
menu = textwrap.dedent(
f"""
╟───────────────────────────────────────────────────────╢
║ Enter a number and hit enter to select / deselect ║
║ the specific option for removal. ║
╟───────────────────────────────────────────────────────╢
║ a) {sel_state:49}
║ a) {self._get_selection_state_str():37}
╟───────────────────────────────────────────────────────╢
║ 1) {o1} Remove Service ║
║ 2) {o2} Remove Local Repository ║
@@ -75,11 +72,11 @@ class MoonrakerRemoveMenu(BaseMenu):
print(menu, end="")
def toggle_all(self, **kwargs) -> None:
self.select_state = not self.select_state
self.remove_moonraker_service = self.select_state
self.remove_moonraker_dir = self.select_state
self.remove_moonraker_env = self.select_state
self.remove_moonraker_polkit = self.select_state
self.selection_state = not self.selection_state
self.remove_moonraker_service = self.selection_state
self.remove_moonraker_dir = self.selection_state
self.remove_moonraker_env = self.selection_state
self.remove_moonraker_polkit = self.selection_state
def toggle_remove_moonraker_service(self, **kwargs) -> None:
self.remove_moonraker_service = not self.remove_moonraker_service
@@ -100,20 +97,32 @@ class MoonrakerRemoveMenu(BaseMenu):
and not self.remove_moonraker_env
and not self.remove_moonraker_polkit
):
msg = "Nothing selected! Select options to remove first."
print(Color.apply(msg, Color.RED))
print(
Color.apply(
"Nothing selected! Select options to remove first.", Color.RED
)
)
return
completion_msg = moonraker_remove.run_moonraker_removal(
moonraker_remove.run_moonraker_removal(
self.remove_moonraker_service,
self.remove_moonraker_dir,
self.remove_moonraker_env,
self.remove_moonraker_polkit,
)
self.message_service.set_message(completion_msg)
self.remove_moonraker_service = False
self.remove_moonraker_dir = False
self.remove_moonraker_env = False
self.remove_moonraker_polkit = False
self.select_state = False
self._go_back()
def _get_selection_state_str(self) -> str:
return (
"Select everything" if not self.selection_state else "Deselect everything"
)
def _go_back(self, **kwargs) -> None:
if self.previous_menu is not None:
self.previous_menu().run()

View File

@@ -16,8 +16,6 @@ from components.moonraker import MOONRAKER_DIR, MOONRAKER_ENV_DIR
from components.moonraker.moonraker import Moonraker
from core.instance_manager.instance_manager import InstanceManager
from core.logger import Logger
from core.services.message_service import Message
from core.types.color import Color
from utils.fs_utils import run_remove_routines
from utils.input_utils import get_selection_input
from utils.instance_utils import get_instances
@@ -29,12 +27,7 @@ def run_moonraker_removal(
remove_dir: bool,
remove_env: bool,
remove_polkit: bool,
) -> Message:
completion_msg = Message(
title="Moonraker Removal Process completed",
color=Color.GREEN,
)
) -> None:
instances = get_instances(Moonraker)
if remove_service:
@@ -42,45 +35,27 @@ def run_moonraker_removal(
if instances:
instances_to_remove = select_instances_to_remove(instances)
remove_instances(instances_to_remove)
instance_names = [i.service_file_path.stem for i in instances_to_remove]
txt = f"● Moonraker instances removed: {', '.join(instance_names)}"
completion_msg.text.append(txt)
else:
Logger.print_info("No Moonraker Services installed! Skipped ...")
delete_remaining: bool = remove_polkit or remove_dir or remove_env
if delete_remaining and unit_file_exists("moonraker", suffix="service"):
completion_msg.text.extend(
[
"\n\n",
"Some Moonraker services are still installed:",
"● Moonraker PolicyKit rules were not removed.",
f"'{MOONRAKER_DIR}' was not removed.",
f"'{MOONRAKER_ENV_DIR}' was not removed.",
]
Logger.print_info("There are still other Moonraker services installed")
Logger.print_info(
"● Moonraker PolicyKit rules were not removed.", prefix=False
)
Logger.print_info(f"'{MOONRAKER_DIR}' was not removed.", prefix=False)
Logger.print_info(f"'{MOONRAKER_ENV_DIR}' was not removed.", prefix=False)
else:
if remove_polkit:
Logger.print_status("Removing all Moonraker policykit rules ...")
if remove_polkit_rules():
completion_msg.text.append("● Moonraker PolicyKit rules removed")
remove_polkit_rules()
if remove_dir:
Logger.print_status("Removing Moonraker local repository ...")
if run_remove_routines(MOONRAKER_DIR):
completion_msg.text.append("● Moonraker local repository removed")
run_remove_routines(MOONRAKER_DIR)
if remove_env:
Logger.print_status("Removing Moonraker Python environment ...")
if run_remove_routines(MOONRAKER_ENV_DIR):
completion_msg.text.append("● Moonraker Python environment removed")
if completion_msg.text:
completion_msg.text.insert(0, "The following actions were performed:")
else:
completion_msg.color = Color.YELLOW
completion_msg.centered = True
completion_msg.text = ["Nothing to remove."]
return completion_msg
run_remove_routines(MOONRAKER_ENV_DIR)
def select_instances_to_remove(
@@ -122,23 +97,19 @@ def remove_instances(
delete_moonraker_env_file(instance)
def remove_polkit_rules() -> bool:
def remove_polkit_rules() -> None:
if not MOONRAKER_DIR.exists():
log = "Cannot remove policykit rules. Moonraker directory not found."
Logger.print_warn(log)
return False
return
try:
cmd = [f"{MOONRAKER_DIR}/scripts/set-policykit-rules.sh", "--clear"]
result = run(cmd, stderr=PIPE, stdout=DEVNULL, check=True)
if result.returncode != 0:
raise CalledProcessError(result.returncode, cmd)
run(cmd, stderr=PIPE, stdout=DEVNULL, check=True)
except CalledProcessError as e:
Logger.print_error(f"Error while removing policykit rules: {e}")
return False
Logger.print_ok("Policykit rules successfully removed!")
return True
def delete_moonraker_env_file(instance: Moonraker):

View File

@@ -37,7 +37,6 @@ from components.webui_client.client_utils import (
)
from core.instance_manager.instance_manager import InstanceManager
from core.logger import DialogType, Logger
from core.services.message_service import Message
from core.settings.kiauh_settings import KiauhSettings
from core.types.color import Color
from utils.common import backup_printer_config_dir, check_install_dependencies
@@ -56,21 +55,14 @@ def install_client(
client: BaseWebClient,
settings: KiauhSettings,
reinstall: bool = False,
) -> Message:
completion_msg = Message(
title=f"{client.display_name} Installation Process completed",
color=Color.GREEN,
)
) -> None:
mr_instances: List[Moonraker] = get_instances(Moonraker)
enable_remotemode = False
if not mr_instances:
print_moonraker_not_found_dialog(client.display_name)
if not get_confirm(f"Continue {client.display_name} installation?"):
completion_msg.color = Color.YELLOW
completion_msg.title = f"{client.display_name} Installation Process aborted"
completion_msg.text.append("Installation was aborted by the user!")
return completion_msg
return
# if moonraker is not installed or multiple instances
# are installed we enable mainsails remote mode
@@ -98,9 +90,9 @@ def install_client(
default_port if reinstall else get_client_port_selection(client, settings)
)
try:
check_install_dependencies({"nginx"})
check_install_dependencies({"nginx"})
try:
download_client(client)
if enable_remotemode and client.client == WebClientType.MAINSAIL:
enable_mainsail_remotemode()
@@ -138,17 +130,23 @@ def install_client(
except Exception as e:
Logger.print_error(e)
completion_msg.color = Color.RED
completion_msg.title = f"{client.display_name} Installation Process failed!"
completion_msg.text.append(
f"An unexpected error occured. Please see the output above. {client.display_name} installation failed!")
return completion_msg
Logger.print_dialog(
DialogType.ERROR,
center_content=True,
content=[f"{client.display_name} installation failed!"],
)
return
# noinspection HttpUrlsUsage
completion_msg.text.append(
f"Open {client.display_name} now on: http://{get_ipv4_addr()}:{port}")
return completion_msg
Logger.print_dialog(
DialogType.CUSTOM,
custom_title=f"{client.display_name} installation complete!",
custom_color=Color.GREEN,
center_content=True,
content=[
f"Open {client.display_name} now on: http://{get_ipv4_addr()}:{port}",
],
)
def download_client(client: BaseWebClient) -> None:

View File

@@ -65,8 +65,7 @@ class ClientInstallMenu(BaseMenu):
print(menu, end="")
def reinstall_client(self, **kwargs) -> None:
completion_msg = install_client(self.client, settings=self.settings, reinstall=True)
self.message_service.set_message(completion_msg)
install_client(self.client, settings=self.settings, reinstall=True)
def change_listen_port(self, **kwargs) -> None:
curr_port = self._get_current_port()

View File

@@ -79,14 +79,14 @@ class BackupManager:
if source is None or not Path(source).exists():
Logger.print_info("Source directory does not exist! Skipping ...")
return None
return
target = self.backup_root_dir if target is None else target
try:
date = get_current_date().get("date")
time = get_current_date().get("time")
backup_target = target.joinpath(f"{name.lower()}-{date}-{time}")
shutil.copytree(source, backup_target, ignore=self.ignore_folders_func, ignore_dangling_symlinks=True)
shutil.copytree(source, backup_target, ignore=self.ignore_folders_func)
Logger.print_ok("Backup successful!")
return backup_target

View File

@@ -75,20 +75,27 @@ class InstallMenu(BaseMenu):
print(menu, end="")
def install_klipper(self, **kwargs) -> None:
completion_msg = klipper_setup.install_klipper()
self.message_service.set_message(completion_msg)
klipper_setup.install_klipper()
def install_moonraker(self, **kwargs) -> None:
moonraker_setup.install_moonraker()
def install_mainsail(self, **kwargs) -> None:
self._install_client(MainsailData())
client: MainsailData = MainsailData()
if client.client_dir.exists():
ClientInstallMenu(client, self.__class__).run()
else:
install_client(client, settings=KiauhSettings())
def install_mainsail_config(self, **kwargs) -> None:
install_client_config(MainsailData())
def install_fluidd(self, **kwargs) -> None:
self._install_client(FluiddData())
client: FluiddData = FluiddData()
if client.client_dir.exists():
ClientInstallMenu(client, self.__class__).run()
else:
install_client(client, settings=KiauhSettings())
def install_fluidd_config(self, **kwargs) -> None:
install_client_config(FluiddData())
@@ -98,10 +105,3 @@ class InstallMenu(BaseMenu):
def install_crowsnest(self, **kwargs) -> None:
install_crowsnest()
def _install_client(self, client: MainsailData | FluiddData) -> None:
if client.client_dir.exists():
ClientInstallMenu(client, self.__class__).run()
else:
completion_msg = install_client(client, settings=KiauhSettings())
self.message_service.set_message(completion_msg)

View File

@@ -1,13 +0,0 @@
# ======================================================================= #
# 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 core.types.color import Color
def get_checkbox_state(checked: bool) -> str:
return f"[{Color.apply('x', Color.CYAN)}]" if checked else "[ ]"

View File

@@ -118,7 +118,7 @@ class MoonrakerTelegramBot:
)
env_file_content = env_file_content.replace(
"%CFG%",
self.cfg_file.as_posix()
f"{self.base.cfg_dir}/printer.cfg",
)
env_file_content = env_file_content.replace(
"%LOG%",

View File

@@ -43,8 +43,7 @@ def get_kiauh_version() -> str:
Helper method to get the current KIAUH version by reading the latest tag
:return: string of the latest tag
"""
lastest_tag: str = get_local_tags(Path(__file__).parent.parent)[-1]
return lastest_tag
return get_local_tags(Path(__file__).parent.parent)[-1]
def convert_camelcase_to_kebabcase(name: str) -> str:

View File

@@ -1,7 +1,6 @@
from __future__ import annotations
import json
import re
import shutil
import urllib.request
from http.client import HTTPResponse
@@ -119,7 +118,7 @@ def get_local_tags(repo_path: Path, _filter: str | None = None) -> List[str]:
:return: List of tags
"""
try:
cmd: List[str] = ["git", "tag", "-l"]
cmd = ["git", "tag", "-l"]
if _filter is not None:
cmd.append(f"'${_filter}'")
@@ -130,10 +129,8 @@ def get_local_tags(repo_path: Path, _filter: str | None = None) -> List[str]:
cwd=repo_path.as_posix(),
).decode(encoding="utf-8")
tags: List[str] = result.split("\n")[:-1]
return sorted(tags, key=lambda x: [int(i) if i.isdigit() else i for i in
re.split(r'(\d+)', x)])
tags = result.split("\n")
return tags[:-1]
except CalledProcessError:
return []