mirror of
https://github.com/dw-0/kiauh.git
synced 2025-12-16 03:54:27 +05:00
feat: add SimplyPrint extension (#566)
* refactor: correctly sort extensions in extension menu Signed-off-by: Dominik Willner <th33xitus@gmail.com> * refactor: use different name for printer_data backup dir Signed-off-by: Dominik Willner <th33xitus@gmail.com> * refactor: change return type to List for moonraker_exists function Signed-off-by: Dominik Willner <th33xitus@gmail.com> * feat: add SimplyPrint extension Signed-off-by: Dominik Willner <th33xitus@gmail.com> --------- Signed-off-by: Dominik Willner <th33xitus@gmail.com>
This commit is contained in:
@@ -33,7 +33,7 @@ CURRENT_USER = pwd.getpwuid(os.getuid())[0]
|
||||
|
||||
# dirs
|
||||
SYSTEMD = Path("/etc/systemd/system")
|
||||
PRINTER_CFG_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("printer-cfg-backups")
|
||||
PRINTER_DATA_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("printer-data-backups")
|
||||
NGINX_SITES_AVAILABLE = Path("/etc/nginx/sites-available")
|
||||
NGINX_SITES_ENABLED = Path("/etc/nginx/sites-enabled")
|
||||
NGINX_CONFD = Path("/etc/nginx/conf.d")
|
||||
|
||||
@@ -58,12 +58,16 @@ class ExtensionsMenu(BaseMenu):
|
||||
module_path = f"kiauh.extensions.{ext.name}.{module_name}"
|
||||
|
||||
# get the class name of the extension
|
||||
ext_class: Type[BaseExtension] = inspect.getmembers(
|
||||
importlib.import_module(module_path),
|
||||
predicate=lambda o: inspect.isclass(o)
|
||||
and issubclass(o, BaseExtension)
|
||||
and o != BaseExtension,
|
||||
)[0][1]
|
||||
module = importlib.import_module(module_path)
|
||||
|
||||
def predicate(o):
|
||||
return (
|
||||
inspect.isclass(o)
|
||||
and issubclass(o, BaseExtension)
|
||||
and o != BaseExtension
|
||||
)
|
||||
|
||||
ext_class: type = inspect.getmembers(module, predicate)[0][1]
|
||||
|
||||
# instantiate the extension with its metadata and add to dict
|
||||
ext_instance: BaseExtension = ext_class(metadata)
|
||||
@@ -72,7 +76,7 @@ class ExtensionsMenu(BaseMenu):
|
||||
except (IOError, json.JSONDecodeError, ImportError) as e:
|
||||
print(f"Failed loading extension {ext}: {e}")
|
||||
|
||||
return dict(sorted(ext_dict.items()))
|
||||
return dict(sorted(ext_dict.items(), key=lambda x: int(x[0])))
|
||||
|
||||
def extension_submenu(self, **kwargs):
|
||||
ExtensionSubmenu(kwargs.get("opt_data"), self.__class__).run()
|
||||
|
||||
0
kiauh/extensions/simply_print/__init__.py
Normal file
0
kiauh/extensions/simply_print/__init__.py
Normal file
13
kiauh/extensions/simply_print/metadata.json
Normal file
13
kiauh/extensions/simply_print/metadata.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"metadata": {
|
||||
"index": 10,
|
||||
"module": "simply_print_extension",
|
||||
"maintained_by": "dw-0",
|
||||
"display_name": "SimplyPrint",
|
||||
"description": [
|
||||
"3D Printer Cloud Management Software.",
|
||||
"\n\n",
|
||||
"3D printing doesn't have to be a complicated, analog, SD card-filled experience; step into the future of modern 3D printing"
|
||||
]
|
||||
}
|
||||
}
|
||||
131
kiauh/extensions/simply_print/simply_print_extension.py
Normal file
131
kiauh/extensions/simply_print/simply_print_extension.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# ======================================================================= #
|
||||
# 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 typing import List
|
||||
|
||||
from components.moonraker.moonraker import Moonraker
|
||||
from core.instance_manager.instance_manager import InstanceManager
|
||||
from core.logger import DialogType, Logger
|
||||
from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import (
|
||||
SimpleConfigParser,
|
||||
)
|
||||
from extensions.base_extension import BaseExtension
|
||||
from utils.common import backup_printer_config_dir, moonraker_exists
|
||||
from utils.input_utils import get_confirm
|
||||
|
||||
|
||||
# noinspection PyMethodMayBeStatic
|
||||
class SimplyPrintExtension(BaseExtension):
|
||||
def install_extension(self, **kwargs) -> None:
|
||||
Logger.print_status("Installing SimplyPrint ...")
|
||||
|
||||
if not (mr_instances := moonraker_exists("SimplyPrint Installer")):
|
||||
return
|
||||
|
||||
Logger.print_dialog(
|
||||
DialogType.INFO,
|
||||
self._construct_dialog(mr_instances, True),
|
||||
)
|
||||
|
||||
if not get_confirm(
|
||||
"Continue SimplyPrint installation?",
|
||||
default_choice=True,
|
||||
allow_go_back=True,
|
||||
):
|
||||
Logger.print_info("Exiting SimplyPrint installation ...")
|
||||
return
|
||||
|
||||
try:
|
||||
self._patch_moonraker_confs(mr_instances, True)
|
||||
|
||||
except Exception as e:
|
||||
Logger.print_error(f"Error during SimplyPrint installation:\n{e}")
|
||||
|
||||
def remove_extension(self, **kwargs) -> None:
|
||||
Logger.print_status("Removing SimplyPrint ...")
|
||||
|
||||
if not (mr_instances := moonraker_exists("SimplyPrint Uninstaller")):
|
||||
return
|
||||
|
||||
Logger.print_dialog(
|
||||
DialogType.INFO,
|
||||
self._construct_dialog(mr_instances, False),
|
||||
)
|
||||
|
||||
if not get_confirm(
|
||||
"Do you really want to uninstall SimplyPrint?",
|
||||
default_choice=True,
|
||||
allow_go_back=True,
|
||||
):
|
||||
Logger.print_info("Exiting SimplyPrint uninstallation ...")
|
||||
return
|
||||
|
||||
try:
|
||||
self._patch_moonraker_confs(mr_instances, False)
|
||||
|
||||
except Exception as e:
|
||||
Logger.print_error(f"Error during SimplyPrint installation:\n{e}")
|
||||
|
||||
def _construct_dialog(
|
||||
self, mr_instances: List[Moonraker], is_install: bool
|
||||
) -> List[str]:
|
||||
mr_names = [f"● {m.service_file_path.name}" for m in mr_instances]
|
||||
_type = "install" if is_install else "uninstall"
|
||||
|
||||
return [
|
||||
"The following Moonraker instances were found:",
|
||||
*mr_names,
|
||||
"\n\n",
|
||||
f"The setup will {_type} SimplyPrint for all Moonraker instances. "
|
||||
f"After {_type}ation, all Moonraker services will be restarted!",
|
||||
]
|
||||
|
||||
def _patch_moonraker_confs(
|
||||
self, mr_instances: List[Moonraker], is_install: bool
|
||||
) -> None:
|
||||
section = "simplyprint"
|
||||
_type, _ft = ("Adding", "to") if is_install else ("Removing", "from")
|
||||
|
||||
patched_files = []
|
||||
for moonraker in mr_instances:
|
||||
Logger.print_status(
|
||||
f"{_type} section 'simplyprint' {_ft} {moonraker.cfg_file} ..."
|
||||
)
|
||||
scp = SimpleConfigParser()
|
||||
scp.read_file(moonraker.cfg_file)
|
||||
|
||||
install_and_has_section = is_install and scp.has_section(section)
|
||||
uninstall_and_has_no_section = not is_install and not scp.has_section(
|
||||
section
|
||||
)
|
||||
|
||||
if install_and_has_section or uninstall_and_has_no_section:
|
||||
status = "already" if is_install else "does not"
|
||||
Logger.print_info(
|
||||
f"Section 'simplyprint' {status} exists! Skipping ..."
|
||||
)
|
||||
continue
|
||||
|
||||
if is_install and not scp.has_section("simplyprint"):
|
||||
backup_printer_config_dir()
|
||||
scp.add_section(section)
|
||||
elif not is_install and scp.has_section("simplyprint"):
|
||||
backup_printer_config_dir()
|
||||
scp.remove_section(section)
|
||||
scp.write_file(moonraker.cfg_file)
|
||||
patched_files.append(moonraker.cfg_file)
|
||||
|
||||
if patched_files:
|
||||
InstanceManager.restart_all(mr_instances)
|
||||
|
||||
install_state = "successfully" if patched_files else "was already"
|
||||
Logger.print_dialog(
|
||||
DialogType.SUCCESS,
|
||||
[f"SimplyPrint {install_state} {'' if is_install else 'un'}installed!"],
|
||||
center_content=True,
|
||||
)
|
||||
@@ -14,10 +14,11 @@ from pathlib import Path
|
||||
from typing import Dict, List, Literal, Optional, Set
|
||||
|
||||
from components.klipper.klipper import Klipper
|
||||
from components.moonraker.moonraker import Moonraker
|
||||
from core.constants import (
|
||||
COLOR_CYAN,
|
||||
GLOBAL_DEPS,
|
||||
PRINTER_CFG_BACKUP_DIR,
|
||||
PRINTER_DATA_BACKUP_DIR,
|
||||
RESET_FORMAT,
|
||||
)
|
||||
from core.logger import DialogType, Logger
|
||||
@@ -142,23 +143,25 @@ def backup_printer_config_dir() -> None:
|
||||
instances: List[Klipper] = get_instances(Klipper)
|
||||
bm = BackupManager()
|
||||
|
||||
if not instances:
|
||||
Logger.print_info("Unable to find directory to backup!")
|
||||
Logger.print_info("Are there no Klipper instances installed?")
|
||||
return
|
||||
|
||||
for instance in instances:
|
||||
name = f"config-{instance.data_dir.name}"
|
||||
bm.backup_directory(
|
||||
name,
|
||||
instance.data_dir.name,
|
||||
source=instance.base.cfg_dir,
|
||||
target=PRINTER_CFG_BACKUP_DIR,
|
||||
target=PRINTER_DATA_BACKUP_DIR,
|
||||
)
|
||||
|
||||
|
||||
def moonraker_exists(name: str = "") -> bool:
|
||||
def moonraker_exists(name: str = "") -> List[Moonraker]:
|
||||
"""
|
||||
Helper method to check if a Moonraker instance exists
|
||||
:param name: Optional name of an installer where the check is performed
|
||||
:return: True if at least one Moonraker instance exists, False otherwise
|
||||
"""
|
||||
from components.moonraker.moonraker import Moonraker
|
||||
|
||||
mr_instances: List[Moonraker] = get_instances(Moonraker)
|
||||
|
||||
info = (
|
||||
@@ -175,8 +178,8 @@ def moonraker_exists(name: str = "") -> bool:
|
||||
f"{info}. Please install Moonraker first!",
|
||||
],
|
||||
)
|
||||
return False
|
||||
return True
|
||||
return []
|
||||
return mr_instances
|
||||
|
||||
|
||||
def trunc_string(input_str: str, length: int) -> str:
|
||||
|
||||
Reference in New Issue
Block a user