Compare commits

..

6 Commits

Author SHA1 Message Date
dw-0
8f793bbfd8 Merge 5ace920d3e into 099d47df2f 2024-02-09 15:47:46 +01:00
dw-0
5ace920d3e feat(extensions): implement initial extension feature and first extension
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-02-09 15:47:13 +01:00
dw-0
2f34253bad refactor(kiauh): handle menus based on if they need instantiation or not
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-02-08 22:41:52 +01:00
dw-0
0447bc4405 refactor(kiauh): allow menus to link options to letters
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-02-05 21:57:19 +01:00
dw-0
7cb2231584 chore(kiauh): rename "res" to "assets"
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-01-29 21:28:01 +01:00
dw-0
5a3d21c40b chore(kiauh): rename "modules" to "components"
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-01-29 21:20:26 +01:00
52 changed files with 596 additions and 170 deletions

View File

@@ -14,7 +14,7 @@ from pathlib import Path
from typing import List from typing import List
from kiauh.core.instance_manager.base_instance import BaseInstance from kiauh.core.instance_manager.base_instance import BaseInstance
from kiauh.modules.klipper import KLIPPER_DIR, KLIPPER_ENV_DIR, MODULE_PATH from kiauh.components.klipper import KLIPPER_DIR, KLIPPER_ENV_DIR, MODULE_PATH
from kiauh.utils.constants import SYSTEMD from kiauh.utils.constants import SYSTEMD
from kiauh.utils.logger import Logger from kiauh.utils.logger import Logger
@@ -52,10 +52,10 @@ class Klipper(BaseInstance):
def create(self) -> None: def create(self) -> None:
Logger.print_status("Creating new Klipper Instance ...") Logger.print_status("Creating new Klipper Instance ...")
service_template_path = MODULE_PATH.joinpath("res/klipper.service") service_template_path = MODULE_PATH.joinpath("assets/klipper.service")
service_file_name = self.get_service_file_name(extension=True) service_file_name = self.get_service_file_name(extension=True)
service_file_target = SYSTEMD.joinpath(service_file_name) service_file_target = SYSTEMD.joinpath(service_file_name)
env_template_file_path = MODULE_PATH.joinpath("res/klipper.env") env_template_file_path = MODULE_PATH.joinpath("assets/klipper.env")
env_file_target = self.sysd_dir.joinpath("klipper.env") env_file_target = self.sysd_dir.joinpath("klipper.env")
try: try:

View File

@@ -13,9 +13,9 @@ import shutil
from typing import List, Union from typing import List, Union
from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.core.instance_manager.instance_manager import InstanceManager
from kiauh.modules.klipper import KLIPPER_DIR, KLIPPER_ENV_DIR from kiauh.components.klipper import KLIPPER_DIR, KLIPPER_ENV_DIR
from kiauh.modules.klipper.klipper import Klipper from kiauh.components.klipper.klipper import Klipper
from kiauh.modules.klipper.klipper_dialogs import print_instance_overview from kiauh.components.klipper.klipper_dialogs import print_instance_overview
from kiauh.utils.filesystem_utils import remove_file from kiauh.utils.filesystem_utils import remove_file
from kiauh.utils.input_utils import get_selection_input from kiauh.utils.input_utils import get_selection_input
from kiauh.utils.logger import Logger from kiauh.utils.logger import Logger

View File

@@ -15,16 +15,16 @@ from kiauh import KIAUH_CFG
from kiauh.core.backup_manager.backup_manager import BackupManager from kiauh.core.backup_manager.backup_manager import BackupManager
from kiauh.core.config_manager.config_manager import ConfigManager from kiauh.core.config_manager.config_manager import ConfigManager
from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.core.instance_manager.instance_manager import InstanceManager
from kiauh.modules.klipper import ( from kiauh.components.klipper import (
EXIT_KLIPPER_SETUP, EXIT_KLIPPER_SETUP,
DEFAULT_KLIPPER_REPO_URL, DEFAULT_KLIPPER_REPO_URL,
KLIPPER_DIR, KLIPPER_DIR,
KLIPPER_ENV_DIR, KLIPPER_ENV_DIR,
KLIPPER_REQUIREMENTS_TXT, KLIPPER_REQUIREMENTS_TXT,
) )
from kiauh.modules.klipper.klipper import Klipper from kiauh.components.klipper.klipper import Klipper
from kiauh.modules.klipper.klipper_dialogs import print_update_warn_dialog from kiauh.components.klipper.klipper_dialogs import print_update_warn_dialog
from kiauh.modules.klipper.klipper_utils import ( from kiauh.components.klipper.klipper_utils import (
handle_disruptive_system_packages, handle_disruptive_system_packages,
check_user_groups, check_user_groups,
handle_to_multi_instance_conversion, handle_to_multi_instance_conversion,
@@ -37,7 +37,7 @@ from kiauh.modules.klipper.klipper_utils import (
handle_instance_naming, handle_instance_naming,
) )
from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.core.repo_manager.repo_manager import RepoManager
from kiauh.modules.moonraker.moonraker import Moonraker from kiauh.components.moonraker.moonraker import Moonraker
from kiauh.utils.input_utils import get_confirm from kiauh.utils.input_utils import get_confirm
from kiauh.utils.logger import Logger from kiauh.utils.logger import Logger
from kiauh.utils.system_utils import ( from kiauh.utils.system_utils import (

View File

@@ -24,16 +24,16 @@ from kiauh.core.instance_manager.base_instance import BaseInstance
from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.core.instance_manager.instance_manager import InstanceManager
from kiauh.core.instance_manager.name_scheme import NameScheme from kiauh.core.instance_manager.name_scheme import NameScheme
from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.core.repo_manager.repo_manager import RepoManager
from kiauh.modules.klipper import MODULE_PATH, KLIPPER_DIR, KLIPPER_ENV_DIR from kiauh.components.klipper import MODULE_PATH, KLIPPER_DIR, KLIPPER_ENV_DIR
from kiauh.modules.klipper.klipper import Klipper from kiauh.components.klipper.klipper import Klipper
from kiauh.modules.klipper.klipper_dialogs import ( from kiauh.components.klipper.klipper_dialogs import (
print_missing_usergroup_dialog, print_missing_usergroup_dialog,
print_instance_overview, print_instance_overview,
print_select_instance_count_dialog, print_select_instance_count_dialog,
print_select_custom_name_dialog, print_select_custom_name_dialog,
) )
from kiauh.modules.moonraker.moonraker import Moonraker from kiauh.components.moonraker.moonraker import Moonraker
from kiauh.modules.moonraker.moonraker_utils import moonraker_to_multi_conversion from kiauh.components.moonraker.moonraker_utils import moonraker_to_multi_conversion
from kiauh.utils.common import get_install_status_common from kiauh.utils.common import get_install_status_common
from kiauh.utils.constants import CURRENT_USER from kiauh.utils.constants import CURRENT_USER
from kiauh.utils.input_utils import get_confirm, get_string_input, get_number_input from kiauh.utils.input_utils import get_confirm, get_string_input, get_number_input
@@ -264,7 +264,7 @@ def create_example_printer_cfg(instance: Klipper) -> None:
Logger.print_info(f"'{instance.cfg_file}' already exists.") Logger.print_info(f"'{instance.cfg_file}' already exists.")
return return
source = MODULE_PATH.joinpath("res/printer.cfg") source = MODULE_PATH.joinpath("assets/printer.cfg")
target = instance.cfg_file target = instance.cfg_file
try: try:
shutil.copy(source, target) shutil.copy(source, target)

View File

@@ -13,8 +13,7 @@ import textwrap
from kiauh.core.menus import BACK_HELP_FOOTER from kiauh.core.menus import BACK_HELP_FOOTER
from kiauh.core.menus.base_menu import BaseMenu from kiauh.core.menus.base_menu import BaseMenu
from kiauh.modules.klipper import klipper_remove from kiauh.components.klipper import klipper_remove
from kiauh.modules.moonraker import moonraker_remove
from kiauh.utils.constants import RESET_FORMAT, COLOR_RED, COLOR_CYAN from kiauh.utils.constants import RESET_FORMAT, COLOR_RED, COLOR_CYAN
@@ -24,12 +23,12 @@ class KlipperRemoveMenu(BaseMenu):
super().__init__( super().__init__(
header=False, header=False,
options={ options={
0: self.toggle_all, "0": self.toggle_all,
1: self.toggle_remove_klipper_service, "1": self.toggle_remove_klipper_service,
2: self.toggle_remove_klipper_dir, "2": self.toggle_remove_klipper_dir,
3: self.toggle_remove_klipper_env, "3": self.toggle_remove_klipper_env,
4: self.toggle_delete_klipper_logs, "4": self.toggle_delete_klipper_logs,
5: self.run_removal_process, "5": self.run_removal_process,
}, },
footer_type=BACK_HELP_FOOTER, footer_type=BACK_HELP_FOOTER,
) )

View File

@@ -15,8 +15,8 @@ from pathlib import Path
import urllib.request import urllib.request
from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.core.instance_manager.instance_manager import InstanceManager
from kiauh.modules.klipper.klipper import Klipper from kiauh.components.klipper.klipper import Klipper
from kiauh.modules.log_uploads import LogFile from kiauh.components.log_uploads import LogFile
from kiauh.utils.logger import Logger from kiauh.utils.logger import Logger

View File

@@ -13,8 +13,8 @@ import textwrap
from kiauh.core.menus import BACK_FOOTER from kiauh.core.menus import BACK_FOOTER
from kiauh.core.menus.base_menu import BaseMenu from kiauh.core.menus.base_menu import BaseMenu
from kiauh.modules.log_uploads.log_upload_utils import upload_logfile from kiauh.components.log_uploads.log_upload_utils import upload_logfile
from kiauh.modules.log_uploads.log_upload_utils import get_logfile_list from kiauh.components.log_uploads.log_upload_utils import get_logfile_list
from kiauh.utils.constants import RESET_FORMAT, COLOR_YELLOW from kiauh.utils.constants import RESET_FORMAT, COLOR_YELLOW

View File

@@ -17,10 +17,10 @@ from typing import List
from kiauh.core.config_manager.config_manager import ConfigManager from kiauh.core.config_manager.config_manager import ConfigManager
from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.core.instance_manager.instance_manager import InstanceManager
from kiauh.modules.klipper.klipper import Klipper from kiauh.components.klipper.klipper import Klipper
from kiauh.modules.mainsail import MAINSAIL_DIR, MAINSAIL_CONFIG_DIR from kiauh.components.mainsail import MAINSAIL_DIR, MAINSAIL_CONFIG_DIR
from kiauh.modules.mainsail.mainsail_utils import backup_config_json from kiauh.components.mainsail.mainsail_utils import backup_config_json
from kiauh.modules.moonraker.moonraker import Moonraker from kiauh.components.moonraker.moonraker import Moonraker
from kiauh.utils import NGINX_SITES_AVAILABLE, NGINX_SITES_ENABLED from kiauh.utils import NGINX_SITES_AVAILABLE, NGINX_SITES_ENABLED
from kiauh.utils.filesystem_utils import remove_file from kiauh.utils.filesystem_utils import remove_file
from kiauh.utils.logger import Logger from kiauh.utils.logger import Logger

View File

@@ -17,27 +17,27 @@ from kiauh import KIAUH_CFG
from kiauh.core.config_manager.config_manager import ConfigManager from kiauh.core.config_manager.config_manager import ConfigManager
from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.core.instance_manager.instance_manager import InstanceManager
from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.core.repo_manager.repo_manager import RepoManager
from kiauh.modules.klipper.klipper import Klipper from kiauh.components.klipper.klipper import Klipper
from kiauh.modules.mainsail import ( from kiauh.components.mainsail import (
MAINSAIL_URL, MAINSAIL_URL,
MAINSAIL_DIR, MAINSAIL_DIR,
MAINSAIL_CONFIG_DIR, MAINSAIL_CONFIG_DIR,
MAINSAIL_CONFIG_REPO_URL, MAINSAIL_CONFIG_REPO_URL,
MODULE_PATH, MODULE_PATH,
) )
from kiauh.modules.mainsail.mainsail_dialogs import ( from kiauh.components.mainsail.mainsail_dialogs import (
print_moonraker_not_found_dialog, print_moonraker_not_found_dialog,
print_mainsail_already_installed_dialog, print_mainsail_already_installed_dialog,
print_install_mainsail_config_dialog, print_install_mainsail_config_dialog,
print_mainsail_port_select_dialog, print_mainsail_port_select_dialog,
) )
from kiauh.modules.mainsail.mainsail_utils import ( from kiauh.components.mainsail.mainsail_utils import (
restore_config_json, restore_config_json,
enable_mainsail_remotemode, enable_mainsail_remotemode,
backup_config_json, backup_config_json,
symlink_webui_nginx_log, symlink_webui_nginx_log,
) )
from kiauh.modules.moonraker.moonraker import Moonraker from kiauh.components.moonraker.moonraker import Moonraker
from kiauh.utils import NGINX_SITES_AVAILABLE, NGINX_SITES_ENABLED from kiauh.utils import NGINX_SITES_AVAILABLE, NGINX_SITES_ENABLED
from kiauh.utils.common import check_install_dependencies from kiauh.utils.common import check_install_dependencies
from kiauh.utils.filesystem_utils import ( from kiauh.utils.filesystem_utils import (
@@ -229,7 +229,7 @@ def patch_moonraker_conf(
Logger.print_info("Section already exist. Skipped ...") Logger.print_info("Section already exist. Skipped ...")
return return
template = MODULE_PATH.joinpath("res", template_file) template = MODULE_PATH.joinpath("assets", template_file)
with open(template, "r") as t: with open(template, "r") as t:
template_content = "\n" template_content = "\n"
template_content += t.read() template_content += t.read()

View File

@@ -16,8 +16,8 @@ from pathlib import Path
from typing import List from typing import List
from kiauh.core.backup_manager.backup_manager import BackupManager from kiauh.core.backup_manager.backup_manager import BackupManager
from kiauh.modules.klipper.klipper import Klipper from kiauh.components.klipper.klipper import Klipper
from kiauh.modules.mainsail import MAINSAIL_CONFIG_JSON, MAINSAIL_DIR from kiauh.components.mainsail import MAINSAIL_CONFIG_JSON, MAINSAIL_DIR
from kiauh.utils import NGINX_SITES_AVAILABLE, NGINX_CONFD from kiauh.utils import NGINX_SITES_AVAILABLE, NGINX_CONFD
from kiauh.utils.common import get_install_status_webui from kiauh.utils.common import get_install_status_webui
from kiauh.utils.logger import Logger from kiauh.utils.logger import Logger

View File

@@ -13,7 +13,7 @@ import textwrap
from kiauh.core.menus import BACK_HELP_FOOTER from kiauh.core.menus import BACK_HELP_FOOTER
from kiauh.core.menus.base_menu import BaseMenu from kiauh.core.menus.base_menu import BaseMenu
from kiauh.modules.mainsail import mainsail_remove from kiauh.components.mainsail import mainsail_remove
from kiauh.utils.constants import RESET_FORMAT, COLOR_RED, COLOR_CYAN from kiauh.utils.constants import RESET_FORMAT, COLOR_RED, COLOR_CYAN
@@ -23,13 +23,13 @@ class MainsailRemoveMenu(BaseMenu):
super().__init__( super().__init__(
header=False, header=False,
options={ options={
0: self.toggle_all, "0": self.toggle_all,
1: self.toggle_remove_mainsail, "1": self.toggle_remove_mainsail,
2: self.toggle_remove_ms_config, "2": self.toggle_remove_ms_config,
3: self.toggle_backup_config_json, "3": self.toggle_backup_config_json,
4: self.toggle_remove_updater_section, "4": self.toggle_remove_updater_section,
5: self.toggle_remove_printer_cfg_include, "5": self.toggle_remove_printer_cfg_include,
6: self.run_removal_process, "6": self.run_removal_process,
}, },
footer_type=BACK_HELP_FOOTER, footer_type=BACK_HELP_FOOTER,
) )

View File

@@ -13,7 +13,7 @@ import textwrap
from kiauh.core.menus import BACK_HELP_FOOTER from kiauh.core.menus import BACK_HELP_FOOTER
from kiauh.core.menus.base_menu import BaseMenu from kiauh.core.menus.base_menu import BaseMenu
from kiauh.modules.moonraker import moonraker_remove from kiauh.components.moonraker import moonraker_remove
from kiauh.utils.constants import RESET_FORMAT, COLOR_RED, COLOR_CYAN from kiauh.utils.constants import RESET_FORMAT, COLOR_RED, COLOR_CYAN
@@ -23,13 +23,13 @@ class MoonrakerRemoveMenu(BaseMenu):
super().__init__( super().__init__(
header=False, header=False,
options={ options={
0: self.toggle_all, "0": self.toggle_all,
1: self.toggle_remove_moonraker_service, "1": self.toggle_remove_moonraker_service,
2: self.toggle_remove_moonraker_dir, "2": self.toggle_remove_moonraker_dir,
3: self.toggle_remove_moonraker_env, "3": self.toggle_remove_moonraker_env,
4: self.toggle_remove_moonraker_polkit, "4": self.toggle_remove_moonraker_polkit,
5: self.toggle_delete_moonraker_logs, "5": self.toggle_delete_moonraker_logs,
6: self.run_removal_process, "6": self.run_removal_process,
}, },
footer_type=BACK_HELP_FOOTER, footer_type=BACK_HELP_FOOTER,
) )

View File

@@ -15,7 +15,7 @@ from typing import List, Union
from kiauh.core.config_manager.config_manager import ConfigManager from kiauh.core.config_manager.config_manager import ConfigManager
from kiauh.core.instance_manager.base_instance import BaseInstance from kiauh.core.instance_manager.base_instance import BaseInstance
from kiauh.modules.moonraker import MOONRAKER_DIR, MOONRAKER_ENV_DIR, MODULE_PATH from kiauh.components.moonraker import MOONRAKER_DIR, MOONRAKER_ENV_DIR, MODULE_PATH
from kiauh.utils.constants import SYSTEMD from kiauh.utils.constants import SYSTEMD
from kiauh.utils.logger import Logger from kiauh.utils.logger import Logger
@@ -39,8 +39,8 @@ class Moonraker(BaseInstance):
def create(self, create_example_cfg: bool = False) -> None: def create(self, create_example_cfg: bool = False) -> None:
Logger.print_status("Creating new Moonraker Instance ...") Logger.print_status("Creating new Moonraker Instance ...")
service_template_path = MODULE_PATH.joinpath("res/moonraker.service") service_template_path = MODULE_PATH.joinpath("assets/moonraker.service")
env_template_file_path = MODULE_PATH.joinpath("res/moonraker.env") env_template_file_path = MODULE_PATH.joinpath("assets/moonraker.env")
service_file_name = self.get_service_file_name(extension=True) service_file_name = self.get_service_file_name(extension=True)
service_file_target = SYSTEMD.joinpath(service_file_name) service_file_target = SYSTEMD.joinpath(service_file_name)
env_file_target = self.sysd_dir.joinpath("moonraker.env") env_file_target = self.sysd_dir.joinpath("moonraker.env")

View File

@@ -13,8 +13,8 @@ import textwrap
from typing import List from typing import List
from kiauh.core.menus.base_menu import print_back_footer from kiauh.core.menus.base_menu import print_back_footer
from kiauh.modules.klipper.klipper import Klipper from kiauh.components.klipper.klipper import Klipper
from kiauh.modules.moonraker.moonraker import Moonraker from kiauh.components.moonraker.moonraker import Moonraker
from kiauh.utils.constants import COLOR_GREEN, RESET_FORMAT, COLOR_YELLOW, COLOR_CYAN from kiauh.utils.constants import COLOR_GREEN, RESET_FORMAT, COLOR_YELLOW, COLOR_CYAN

View File

@@ -14,9 +14,9 @@ import subprocess
from typing import List, Union from typing import List, Union
from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.core.instance_manager.instance_manager import InstanceManager
from kiauh.modules.klipper.klipper_dialogs import print_instance_overview from kiauh.components.klipper.klipper_dialogs import print_instance_overview
from kiauh.modules.moonraker import MOONRAKER_DIR, MOONRAKER_ENV_DIR from kiauh.components.moonraker import MOONRAKER_DIR, MOONRAKER_ENV_DIR
from kiauh.modules.moonraker.moonraker import Moonraker from kiauh.components.moonraker.moonraker import Moonraker
from kiauh.utils.filesystem_utils import remove_file from kiauh.utils.filesystem_utils import remove_file
from kiauh.utils.input_utils import get_selection_input from kiauh.utils.input_utils import get_selection_input
from kiauh.utils.logger import Logger from kiauh.utils.logger import Logger

View File

@@ -18,12 +18,12 @@ from kiauh import KIAUH_CFG
from kiauh.core.backup_manager.backup_manager import BackupManager from kiauh.core.backup_manager.backup_manager import BackupManager
from kiauh.core.config_manager.config_manager import ConfigManager from kiauh.core.config_manager.config_manager import ConfigManager
from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.core.instance_manager.instance_manager import InstanceManager
from kiauh.modules.klipper.klipper import Klipper from kiauh.components.klipper.klipper import Klipper
from kiauh.modules.klipper.klipper_dialogs import print_instance_overview from kiauh.components.klipper.klipper_dialogs import print_instance_overview
from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.core.repo_manager.repo_manager import RepoManager
from kiauh.modules.mainsail import MAINSAIL_DIR from kiauh.components.mainsail import MAINSAIL_DIR
from kiauh.modules.mainsail.mainsail_utils import enable_mainsail_remotemode from kiauh.components.mainsail.mainsail_utils import enable_mainsail_remotemode
from kiauh.modules.moonraker import ( from kiauh.components.moonraker import (
EXIT_MOONRAKER_SETUP, EXIT_MOONRAKER_SETUP,
DEFAULT_MOONRAKER_REPO_URL, DEFAULT_MOONRAKER_REPO_URL,
MOONRAKER_DIR, MOONRAKER_DIR,
@@ -34,9 +34,9 @@ from kiauh.modules.moonraker import (
POLKIT_USR_FILE, POLKIT_USR_FILE,
POLKIT_SCRIPT, POLKIT_SCRIPT,
) )
from kiauh.modules.moonraker.moonraker import Moonraker from kiauh.components.moonraker.moonraker import Moonraker
from kiauh.modules.moonraker.moonraker_dialogs import print_moonraker_overview from kiauh.components.moonraker.moonraker_dialogs import print_moonraker_overview
from kiauh.modules.moonraker.moonraker_utils import create_example_moonraker_conf from kiauh.components.moonraker.moonraker_utils import create_example_moonraker_conf
from kiauh.utils.filesystem_utils import check_file_exist from kiauh.utils.filesystem_utils import check_file_exist
from kiauh.utils.input_utils import ( from kiauh.utils.input_utils import (
get_confirm, get_confirm,

View File

@@ -15,15 +15,15 @@ from typing import Dict, Literal, List, Union
from kiauh.core.config_manager.config_manager import ConfigManager from kiauh.core.config_manager.config_manager import ConfigManager
from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.core.instance_manager.instance_manager import InstanceManager
from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.core.repo_manager.repo_manager import RepoManager
from kiauh.modules.mainsail import MAINSAIL_DIR from kiauh.components.mainsail import MAINSAIL_DIR
from kiauh.modules.mainsail.mainsail_utils import enable_mainsail_remotemode from kiauh.components.mainsail.mainsail_utils import enable_mainsail_remotemode
from kiauh.modules.moonraker import ( from kiauh.components.moonraker import (
DEFAULT_MOONRAKER_PORT, DEFAULT_MOONRAKER_PORT,
MODULE_PATH, MODULE_PATH,
MOONRAKER_DIR, MOONRAKER_DIR,
MOONRAKER_ENV_DIR, MOONRAKER_ENV_DIR,
) )
from kiauh.modules.moonraker.moonraker import Moonraker from kiauh.components.moonraker.moonraker import Moonraker
from kiauh.utils.common import get_install_status_common from kiauh.utils.common import get_install_status_common
from kiauh.utils.logger import Logger from kiauh.utils.logger import Logger
from kiauh.utils.system_utils import ( from kiauh.utils.system_utils import (
@@ -56,7 +56,7 @@ def create_example_moonraker_conf(
Logger.print_info(f"'{instance.cfg_file}' already exists.") Logger.print_info(f"'{instance.cfg_file}' already exists.")
return return
source = MODULE_PATH.joinpath("res/moonraker.conf") source = MODULE_PATH.joinpath("assets/moonraker.conf")
target = instance.cfg_file target = instance.cfg_file
try: try:
shutil.copy(source, target) shutil.copy(source, target)

View File

@@ -0,0 +1,32 @@
#!/usr/bin/env python3
# ======================================================================= #
# 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 abc import abstractmethod, ABC
from typing import Dict
# noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic
class BaseExtension(ABC):
def __init__(self, metadata: Dict[str, str]):
self.metadata = metadata
@abstractmethod
def install_extension(self, **kwargs) -> None:
raise NotImplementedError(
"Subclasses must implement the install_extension method"
)
@abstractmethod
def remove_extension(self, **kwargs) -> None:
raise NotImplementedError(
"Subclasses must implement the remove_extension method"
)

View File

@@ -13,7 +13,7 @@ import subprocess
import sys import sys
import textwrap import textwrap
from abc import abstractmethod, ABC from abc import abstractmethod, ABC
from typing import Dict, Any, Literal from typing import Dict, Any, Literal, Union, Callable, Type
from kiauh.core.menus import QUIT_FOOTER, BACK_FOOTER, BACK_HELP_FOOTER from kiauh.core.menus import QUIT_FOOTER, BACK_FOOTER, BACK_HELP_FOOTER
from kiauh.utils.constants import ( from kiauh.utils.constants import (
@@ -97,23 +97,24 @@ class BaseMenu(ABC):
def __init__( def __init__(
self, self,
options: Dict[int, Any], options: Dict[str, Union[Callable, Any]],
options_offset: int = 0, options_offset: int = 0,
header: bool = True, header: bool = True,
footer_type: Literal[ footer_type: Literal[
"QUIT_FOOTER", "BACK_FOOTER", "BACK_HELP_FOOTER" "QUIT_FOOTER", "BACK_FOOTER", "BACK_HELP_FOOTER"
] = QUIT_FOOTER, ] = QUIT_FOOTER,
): ):
self.previous_menu = None
self.options = options self.options = options
self.options_offset = options_offset self.options_offset = options_offset
self.header = header self.header = header
self.footer_type = footer_type self.footer_type = footer_type
@abstractmethod @abstractmethod
def print_menu(self): def print_menu(self) -> None:
raise NotImplementedError("Subclasses must implement the print_menu method") raise NotImplementedError("Subclasses must implement the print_menu method")
def print_footer(self): def print_footer(self) -> None:
footer_type_map = { footer_type_map = {
QUIT_FOOTER: print_quit_footer, QUIT_FOOTER: print_quit_footer,
BACK_FOOTER: print_back_footer, BACK_FOOTER: print_back_footer,
@@ -122,33 +123,29 @@ class BaseMenu(ABC):
footer_function = footer_type_map.get(self.footer_type, print_quit_footer) footer_function = footer_type_map.get(self.footer_type, print_quit_footer)
footer_function() footer_function()
def display(self): def display(self) -> None:
# clear() # clear()
if self.header: if self.header:
print_header() print_header()
self.print_menu() self.print_menu()
self.print_footer() self.print_footer()
def handle_user_input(self): def handle_user_input(self) -> str:
while True: while True:
choice = input(f"{COLOR_CYAN}###### Perform action: {RESET_FORMAT}") choice = input(f"{COLOR_CYAN}###### Perform action: {RESET_FORMAT}").lower()
option = self.options.get(choice, None)
if choice.isdigit() and 0 <= int(choice) < len(self.options): has_navi_option = self.footer_type in self.NAVI_OPTIONS
user_navigated = choice in self.NAVI_OPTIONS[self.footer_type]
if has_navi_option and user_navigated:
return choice return choice
elif choice.isalpha() and (
self.footer_type in self.NAVI_OPTIONS if option is not None:
and choice.lower() in self.NAVI_OPTIONS[self.footer_type]
):
return choice return choice
else: else:
error_msg = ( Logger.print_error("Invalid input!", False)
"Invalid input!"
if choice.isalpha() or (not self.options and len(self.options) < 1)
else f"Invalid input! Select a number between {min(self.options)} and {max(self.options)}."
)
Logger.print_error(error_msg, False)
def start(self): def start(self) -> None:
while True: while True:
self.display() self.display()
choice = self.handle_user_input() choice = self.handle_user_input()
@@ -158,16 +155,18 @@ class BaseMenu(ABC):
sys.exit(0) sys.exit(0)
elif choice == "b": elif choice == "b":
return return
elif choice == "p": elif choice == "h":
print("help!") print("help!")
else: else:
self.execute_option(int(choice)) self.execute_option(choice)
def execute_option(self, choice): def execute_option(self, choice: str) -> None:
option = self.options.get(choice, None) option = self.options.get(choice, None)
if isinstance(option, type) and issubclass(option, BaseMenu): if isinstance(option, type) and issubclass(option, BaseMenu):
self.navigate_to_submenu(option) self.navigate_to_menu(option, True)
elif isinstance(option, BaseMenu):
self.navigate_to_menu(option, False)
elif callable(option): elif callable(option):
option(opt_index=choice) option(opt_index=choice)
elif option is None: elif option is None:
@@ -177,7 +176,14 @@ class BaseMenu(ABC):
f"Type {type(option)} of option {choice} not of type BaseMenu or Method" f"Type {type(option)} of option {choice} not of type BaseMenu or Method"
) )
def navigate_to_submenu(self, submenu_class): def navigate_to_menu(self, menu, instantiate: bool) -> None:
submenu = submenu_class() """
submenu.previous_menu = self Method for handling the actual menu switch. Can either take in a menu type or an already
submenu.start() instantiated menu class. Use instantiated menu classes only if the menu requires specific input parameters
:param menu: A menu type or menu instance
:param instantiate: Specify if the menu requires instantiation
:return: None
"""
menu = menu() if instantiate else menu
menu.previous_menu = self
menu.start()

View File

@@ -0,0 +1,135 @@
#!/usr/bin/env python3
# ======================================================================= #
# 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 #
# ======================================================================= #
import json
import textwrap
import importlib
import inspect
from pathlib import Path
from typing import List, Dict
from kiauh.core.base_extension import BaseExtension
from kiauh.core.menus import BACK_FOOTER
from kiauh.core.menus.base_menu import BaseMenu
from kiauh.utils.constants import RESET_FORMAT, COLOR_CYAN, COLOR_YELLOW
# noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic
class ExtensionsMenu(BaseMenu):
def __init__(self):
self.extensions = self.discover_extensions()
super().__init__(
header=True,
options=self.get_options(),
footer_type=BACK_FOOTER,
)
def discover_extensions(self) -> List[BaseExtension]:
extensions = []
extensions_dir = Path(__file__).resolve().parents[2].joinpath("extensions")
for extension in extensions_dir.iterdir():
metadata_json = Path(extension).joinpath("metadata.json")
if not metadata_json.exists():
continue
try:
with open(metadata_json, "r") as m:
metadata = json.load(m).get("metadata")
module_name = (
f"kiauh.extensions.{extension.name}.{metadata.get('module')}"
)
name, extension = inspect.getmembers(
importlib.import_module(module_name),
predicate=lambda o: inspect.isclass(o)
and issubclass(o, BaseExtension)
and o != BaseExtension,
)[0]
extensions.append(extension(metadata))
except (IOError, json.JSONDecodeError, ImportError) as e:
print(f"Failed loading extension {extension}: {e}")
return sorted(extensions, key=lambda ex: ex.metadata.get("index"))
def get_options(self) -> Dict[str, BaseMenu]:
options = {}
for extension in self.extensions:
index = extension.metadata.get("index")
options[f"{index}"] = ExtensionSubmenu(extension)
return options
def print_menu(self):
header = " [ Extensions Menu ] "
color = COLOR_CYAN
line1 = f"{COLOR_YELLOW}Available Extensions:{RESET_FORMAT}"
count = 62 - len(color) - len(RESET_FORMAT)
menu = textwrap.dedent(
f"""
/=======================================================\\
| {color}{header:~^{count}}{RESET_FORMAT} |
|-------------------------------------------------------|
| {line1:<62} |
| |
"""
)[1:]
print(menu, end="")
for extension in self.extensions:
index = extension.metadata.get("index")
name = extension.metadata.get("display_name")
row = f"{index}) {name}"
print(f"| {row:<53} |")
# noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic
class ExtensionSubmenu(BaseMenu):
def __init__(self, extension: BaseExtension):
self.extension = extension
self.extension_name = extension.metadata.get("display_name")
self.extension_desc = extension.metadata.get("description")
super().__init__(
header=False,
options={
"1": extension.install_extension,
"2": extension.remove_extension,
},
footer_type=BACK_FOOTER,
)
def print_menu(self) -> None:
header = f" [ {self.extension_name} ] "
color = COLOR_YELLOW
count = 62 - len(color) - len(RESET_FORMAT)
wrapper = textwrap.TextWrapper(55, initial_indent="| ", subsequent_indent="| ")
lines = wrapper.wrap(self.extension_desc)
formatted_lines = [f"{line:<55} |" for line in lines]
description_text = "\n".join(formatted_lines)
menu = textwrap.dedent(
f"""
/=======================================================\\
| {color}{header:~^{count}}{RESET_FORMAT} |
|-------------------------------------------------------|
"""
)[1:]
menu += f"{description_text}\n"
menu += textwrap.dedent(
"""
|-------------------------------------------------------|
| 1) Install |
| 2) Remove |
"""
)[1:]
print(menu, end="")

View File

@@ -13,9 +13,9 @@ import textwrap
from kiauh.core.menus import BACK_FOOTER from kiauh.core.menus import BACK_FOOTER
from kiauh.core.menus.base_menu import BaseMenu from kiauh.core.menus.base_menu import BaseMenu
from kiauh.modules.klipper import klipper_setup from kiauh.components.klipper import klipper_setup
from kiauh.modules.mainsail import mainsail_setup from kiauh.components.mainsail import mainsail_setup
from kiauh.modules.moonraker import moonraker_setup from kiauh.components.moonraker import moonraker_setup
from kiauh.utils.constants import COLOR_GREEN, RESET_FORMAT from kiauh.utils.constants import COLOR_GREEN, RESET_FORMAT
@@ -26,17 +26,17 @@ class InstallMenu(BaseMenu):
super().__init__( super().__init__(
header=True, header=True,
options={ options={
1: self.install_klipper, "1": self.install_klipper,
2: self.install_moonraker, "2": self.install_moonraker,
3: self.install_mainsail, "3": self.install_mainsail,
4: self.install_fluidd, "4": self.install_fluidd,
5: self.install_klipperscreen, "5": self.install_klipperscreen,
6: self.install_pretty_gcode, "6": self.install_pretty_gcode,
7: self.install_telegram_bot, "7": self.install_telegram_bot,
8: self.install_obico, "8": self.install_obico,
9: self.install_octoeverywhere, "9": self.install_octoeverywhere,
10: self.install_mobileraker, "10": self.install_mobileraker,
11: self.install_crowsnest, "11": self.install_crowsnest,
}, },
footer_type=BACK_FOOTER, footer_type=BACK_FOOTER,
) )

View File

@@ -14,14 +14,15 @@ import textwrap
from kiauh.core.menus import QUIT_FOOTER from kiauh.core.menus import QUIT_FOOTER
from kiauh.core.menus.advanced_menu import AdvancedMenu from kiauh.core.menus.advanced_menu import AdvancedMenu
from kiauh.core.menus.base_menu import BaseMenu from kiauh.core.menus.base_menu import BaseMenu
from kiauh.core.menus.extensions_menu import ExtensionsMenu
from kiauh.core.menus.install_menu import InstallMenu from kiauh.core.menus.install_menu import InstallMenu
from kiauh.core.menus.remove_menu import RemoveMenu from kiauh.core.menus.remove_menu import RemoveMenu
from kiauh.core.menus.settings_menu import SettingsMenu from kiauh.core.menus.settings_menu import SettingsMenu
from kiauh.core.menus.update_menu import UpdateMenu from kiauh.core.menus.update_menu import UpdateMenu
from kiauh.modules.klipper.klipper_utils import get_klipper_status from kiauh.components.klipper.klipper_utils import get_klipper_status
from kiauh.modules.log_uploads.menus.log_upload_menu import LogUploadMenu from kiauh.components.log_uploads.menus.log_upload_menu import LogUploadMenu
from kiauh.modules.mainsail.mainsail_utils import get_mainsail_status from kiauh.components.mainsail.mainsail_utils import get_mainsail_status
from kiauh.modules.moonraker.moonraker_utils import get_moonraker_status from kiauh.components.moonraker.moonraker_utils import get_moonraker_status
from kiauh.utils.constants import ( from kiauh.utils.constants import (
COLOR_MAGENTA, COLOR_MAGENTA,
COLOR_CYAN, COLOR_CYAN,
@@ -37,13 +38,14 @@ class MainMenu(BaseMenu):
super().__init__( super().__init__(
header=True, header=True,
options={ options={
0: LogUploadMenu, "0": LogUploadMenu,
1: InstallMenu, "1": InstallMenu,
2: UpdateMenu, "2": UpdateMenu,
3: RemoveMenu, "3": RemoveMenu,
4: AdvancedMenu, "4": AdvancedMenu,
5: None, "5": None,
6: SettingsMenu, "e": ExtensionsMenu,
"s": SettingsMenu,
}, },
footer_type=QUIT_FOOTER, footer_type=QUIT_FOOTER,
) )
@@ -113,13 +115,13 @@ class MainMenu(BaseMenu):
| 4) [Advanced] |------------------------------------| | 4) [Advanced] |------------------------------------|
| 5) [Backup] | Mainsail: {self.ms_status:<26} | | 5) [Backup] | Mainsail: {self.ms_status:<26} |
| | Fluidd: {self.fl_status:<26} | | | Fluidd: {self.fl_status:<26} |
| 6) [Settings] | KlipperScreen: {self.ks_status:<26} | | E) [Extensions] | KlipperScreen: {self.ks_status:<26} |
| | Mobileraker: {self.mb_status:<26} | | | Mobileraker: {self.mb_status:<26} |
| | | | | |
| | Crowsnest: {self.cn_status:<26} | | | Crowsnest: {self.cn_status:<26} |
| | Telegram Bot: {self.tg_status:<26} | | | Telegram Bot: {self.tg_status:<26} |
| | Obico: {self.ob_status:<26} | | | Obico: {self.ob_status:<26} |
| | OctoEverywhere: {self.oe_status:<26} | | S) [Settings] | OctoEverywhere: {self.oe_status:<26} |
|-------------------------------------------------------| |-------------------------------------------------------|
| {COLOR_CYAN}{footer1:^16}{RESET_FORMAT} | {footer2:^43} | | {COLOR_CYAN}{footer1:^16}{RESET_FORMAT} | {footer2:^43} |
""" """

View File

@@ -13,9 +13,9 @@ import textwrap
from kiauh.core.menus import BACK_FOOTER from kiauh.core.menus import BACK_FOOTER
from kiauh.core.menus.base_menu import BaseMenu from kiauh.core.menus.base_menu import BaseMenu
from kiauh.modules.klipper.menus.klipper_remove_menu import KlipperRemoveMenu from kiauh.components.klipper.menus.klipper_remove_menu import KlipperRemoveMenu
from kiauh.modules.mainsail.menus.mainsail_remove_menu import MainsailRemoveMenu from kiauh.components.mainsail.menus.mainsail_remove_menu import MainsailRemoveMenu
from kiauh.modules.moonraker.menus.moonraker_remove_menu import MoonrakerRemoveMenu from kiauh.components.moonraker.menus.moonraker_remove_menu import MoonrakerRemoveMenu
from kiauh.utils.constants import COLOR_RED, RESET_FORMAT from kiauh.utils.constants import COLOR_RED, RESET_FORMAT
@@ -26,19 +26,19 @@ class RemoveMenu(BaseMenu):
super().__init__( super().__init__(
header=True, header=True,
options={ options={
1: KlipperRemoveMenu, "1": KlipperRemoveMenu,
2: MoonrakerRemoveMenu, "2": MoonrakerRemoveMenu,
3: MainsailRemoveMenu, "3": MainsailRemoveMenu,
5: self.remove_fluidd, "5": self.remove_fluidd,
6: self.remove_klipperscreen, "6": self.remove_klipperscreen,
7: self.remove_crowsnest, "7": self.remove_crowsnest,
8: self.remove_mjpgstreamer, "8": self.remove_mjpgstreamer,
9: self.remove_pretty_gcode, "9": self.remove_pretty_gcode,
10: self.remove_telegram_bot, "10": self.remove_telegram_bot,
11: self.remove_obico, "11": self.remove_obico,
12: self.remove_octoeverywhere, "12": self.remove_octoeverywhere,
13: self.remove_mobileraker, "13": self.remove_mobileraker,
14: self.remove_nginx, "14": self.remove_nginx,
}, },
footer_type=BACK_FOOTER, footer_type=BACK_FOOTER,
) )

View File

@@ -13,17 +13,17 @@ import textwrap
from kiauh.core.menus import BACK_FOOTER from kiauh.core.menus import BACK_FOOTER
from kiauh.core.menus.base_menu import BaseMenu from kiauh.core.menus.base_menu import BaseMenu
from kiauh.modules.klipper.klipper_setup import update_klipper from kiauh.components.klipper.klipper_setup import update_klipper
from kiauh.modules.klipper.klipper_utils import ( from kiauh.components.klipper.klipper_utils import (
get_klipper_status, get_klipper_status,
) )
from kiauh.modules.mainsail.mainsail_setup import update_mainsail from kiauh.components.mainsail.mainsail_setup import update_mainsail
from kiauh.modules.mainsail.mainsail_utils import ( from kiauh.components.mainsail.mainsail_utils import (
get_mainsail_local_version, get_mainsail_local_version,
get_mainsail_remote_version, get_mainsail_remote_version,
) )
from kiauh.modules.moonraker.moonraker_setup import update_moonraker from kiauh.components.moonraker.moonraker_setup import update_moonraker
from kiauh.modules.moonraker.moonraker_utils import get_moonraker_status from kiauh.components.moonraker.moonraker_utils import get_moonraker_status
from kiauh.utils.constants import COLOR_GREEN, RESET_FORMAT, COLOR_YELLOW, COLOR_WHITE from kiauh.utils.constants import COLOR_GREEN, RESET_FORMAT, COLOR_YELLOW, COLOR_WHITE
@@ -34,19 +34,19 @@ class UpdateMenu(BaseMenu):
super().__init__( super().__init__(
header=True, header=True,
options={ options={
0: self.update_all, "0": self.update_all,
1: self.update_klipper, "1": self.update_klipper,
2: self.update_moonraker, "2": self.update_moonraker,
3: self.update_mainsail, "3": self.update_mainsail,
4: self.update_fluidd, "4": self.update_fluidd,
5: self.update_klipperscreen, "5": self.update_klipperscreen,
6: self.update_pgc_for_klipper, "6": self.update_pgc_for_klipper,
7: self.update_telegram_bot, "7": self.update_telegram_bot,
8: self.update_moonraker_obico, "8": self.update_moonraker_obico,
9: self.update_octoeverywhere, "9": self.update_octoeverywhere,
10: self.update_mobileraker, "10": self.update_mobileraker,
11: self.update_crowsnest, "11": self.update_crowsnest,
12: self.upgrade_system_packages, "12": self.upgrade_system_packages,
}, },
footer_type=BACK_FOOTER, footer_type=BACK_FOOTER,
) )

View File

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python3
# ======================================================================= #
# 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 pathlib import Path
EXT_MODULE_NAME = "gcode_shell_command.py"
MODULE_PATH = Path(__file__).resolve().parent
MODULE_ASSETS = MODULE_PATH.joinpath("assets")
KLIPPER_DIR = Path.home().joinpath("klipper")
KLIPPER_EXTRAS = KLIPPER_DIR.joinpath("klippy/extras")
EXTENSION_SRC = MODULE_ASSETS.joinpath(EXT_MODULE_NAME)
EXTENSION_TARGET_PATH = KLIPPER_EXTRAS.joinpath(EXT_MODULE_NAME)
EXAMPLE_CFG_SRC = MODULE_ASSETS.joinpath("shell_command.cfg")

View File

@@ -0,0 +1,87 @@
# Run a shell command via gcode
#
# Copyright (C) 2019 Eric Callahan <arksine.code@gmail.com>
#
# This file may be distributed under the terms of the GNU GPLv3 license.
import os
import shlex
import subprocess
import logging
class ShellCommand:
def __init__(self, config):
self.name = config.get_name().split()[-1]
self.printer = config.get_printer()
self.gcode = self.printer.lookup_object('gcode')
cmd = config.get('command')
cmd = os.path.expanduser(cmd)
self.command = shlex.split(cmd)
self.timeout = config.getfloat('timeout', 2., above=0.)
self.verbose = config.getboolean('verbose', True)
self.proc_fd = None
self.partial_output = ""
self.gcode.register_mux_command(
"RUN_SHELL_COMMAND", "CMD", self.name,
self.cmd_RUN_SHELL_COMMAND,
desc=self.cmd_RUN_SHELL_COMMAND_help)
def _process_output(self, eventime):
if self.proc_fd is None:
return
try:
data = os.read(self.proc_fd, 4096)
except Exception:
pass
data = self.partial_output + data.decode()
if '\n' not in data:
self.partial_output = data
return
elif data[-1] != '\n':
split = data.rfind('\n') + 1
self.partial_output = data[split:]
data = data[:split]
else:
self.partial_output = ""
self.gcode.respond_info(data)
cmd_RUN_SHELL_COMMAND_help = "Run a linux shell command"
def cmd_RUN_SHELL_COMMAND(self, params):
gcode_params = params.get('PARAMS','')
gcode_params = shlex.split(gcode_params)
reactor = self.printer.get_reactor()
try:
proc = subprocess.Popen(
self.command + gcode_params, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
except Exception:
logging.exception(
"shell_command: Command {%s} failed" % (self.name))
raise self.gcode.error("Error running command {%s}" % (self.name))
if self.verbose:
self.proc_fd = proc.stdout.fileno()
self.gcode.respond_info("Running Command {%s}...:" % (self.name))
hdl = reactor.register_fd(self.proc_fd, self._process_output)
eventtime = reactor.monotonic()
endtime = eventtime + self.timeout
complete = False
while eventtime < endtime:
eventtime = reactor.pause(eventtime + .05)
if proc.poll() is not None:
complete = True
break
if not complete:
proc.terminate()
if self.verbose:
if self.partial_output:
self.gcode.respond_info(self.partial_output)
self.partial_output = ""
if complete:
msg = "Command {%s} finished\n" % (self.name)
else:
msg = "Command {%s} timed out" % (self.name)
self.gcode.respond_info(msg)
reactor.unregister_fd(hdl)
self.proc_fd = None
def load_config_prefix(config):
return ShellCommand(config)

View File

@@ -0,0 +1,7 @@
[gcode_shell_command hello_world]
command: echo hello world
timeout: 2.
verbose: True
[gcode_macro HELLO_WORLD]
gcode:
RUN_SHELL_COMMAND CMD=hello_world

View File

@@ -0,0 +1,127 @@
#!/usr/bin/env python3
# ======================================================================= #
# 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 #
# ======================================================================= #
import os
import shutil
from typing import List
from kiauh.components.klipper.klipper import Klipper
from kiauh.core.backup_manager.backup_manager import BackupManager
from kiauh.core.base_extension import BaseExtension
from kiauh.core.config_manager.config_manager import ConfigManager
from kiauh.core.instance_manager.instance_manager import InstanceManager
from kiauh.extensions.gcode_shell_cmd import (
EXTENSION_TARGET_PATH,
EXTENSION_SRC,
KLIPPER_DIR,
EXAMPLE_CFG_SRC,
KLIPPER_EXTRAS,
)
from kiauh.utils.filesystem_utils import check_file_exist
from kiauh.utils.input_utils import get_confirm
from kiauh.utils.logger import Logger
# noinspection PyMethodMayBeStatic
class GcodeShellCmdExtension(BaseExtension):
def install_extension(self, **kwargs) -> None:
install_example = get_confirm("Create an example shell command?", False, False)
klipper_dir_exists = check_file_exist(KLIPPER_DIR)
if not klipper_dir_exists:
Logger.print_warn(
"No Klipper directory found! Unable to install extension."
)
return
extension_installed = check_file_exist(EXTENSION_TARGET_PATH)
overwrite = True
if extension_installed:
overwrite = get_confirm(
"Extension seems to be installed already. Overwrite?", True, False
)
if not overwrite:
Logger.print_warn("Installation aborted due to user request.")
return
im = InstanceManager(Klipper)
im.stop_all_instance()
try:
Logger.print_status(f"Copy extension to '{KLIPPER_EXTRAS}' ...")
shutil.copy(EXTENSION_SRC, EXTENSION_TARGET_PATH)
except OSError as e:
Logger.print_error(f"Unable to install extension: {e}")
return
if install_example:
self.install_example_cfg(im.instances)
im.start_all_instance()
Logger.print_ok("Installing G-Code Shell Command extension successfull!")
def remove_extension(self, **kwargs) -> None:
extension_installed = check_file_exist(EXTENSION_TARGET_PATH)
if not extension_installed:
Logger.print_info("Extension does not seem to be installed! Skipping ...")
return
question = "Do you really want to remove the extension?"
if get_confirm(question, True, False):
try:
Logger.print_status(f"Removing '{EXTENSION_TARGET_PATH}' ...")
os.remove(EXTENSION_TARGET_PATH)
Logger.print_ok("Extension successfully removed!")
except OSError as e:
Logger.print_error(f"Unable to remove extension: {e}")
Logger.print_warn("PLEASE NOTE:")
Logger.print_warn(
"Remaining gcode shell command will cause Klipper to throw an error."
)
Logger.print_warn("Make sure to remove them from the printer.cfg!")
def install_example_cfg(self, instances: List[Klipper]):
cfg_dirs = [instance.cfg_dir for instance in instances]
# copy extension to klippy/extras
for cfg_dir in cfg_dirs:
Logger.print_status(f"Create shell_command.cfg in '{cfg_dir}' ...")
if check_file_exist(cfg_dir.joinpath("shell_command.cfg")):
Logger.print_info("File already exists! Skipping ...")
continue
try:
shutil.copy(EXAMPLE_CFG_SRC, cfg_dir)
Logger.print_ok("Done!")
except OSError as e:
Logger.warn(f"Unable to create example config: {e}")
# backup each printer.cfg before modification
bm = BackupManager()
for instance in instances:
bm.backup_file(
[instance.cfg_file],
custom_filename=f"{instance.suffix}.printer.cfg",
)
# add section to printer.cfg if not already defined
section = "include shell_command.cfg"
cfg_files = [instance.cfg_file for instance in instances]
for cfg_file in cfg_files:
Logger.print_status(f"Include shell_command.cfg in '{cfg_file}' ...")
cm = ConfigManager(cfg_file)
if cm.config.has_section(section):
Logger.print_info("Section already defined! Skipping ...")
continue
cm.config.add_section(section)
cm.write_config()
Logger.print_ok("Done!")

View File

@@ -0,0 +1,9 @@
{
"metadata": {
"index": 1,
"module": "gcode_shell_cmd_extension",
"maintained_by": "dw-0",
"display_name": "G-Code Shell Command",
"description": "Allows to run a shell command from gcode."
}
}

View File

@@ -79,7 +79,7 @@ def copy_upstream_nginx_cfg() -> None:
Creates an upstream.conf in /etc/nginx/conf.d Creates an upstream.conf in /etc/nginx/conf.d
:return: None :return: None
""" """
source = MODULE_PATH.joinpath("res/upstreams.conf") source = MODULE_PATH.joinpath("assets/upstreams.conf")
target = NGINX_CONFD.joinpath("upstreams.conf") target = NGINX_CONFD.joinpath("upstreams.conf")
try: try:
command = ["sudo", "cp", source, target] command = ["sudo", "cp", source, target]
@@ -95,7 +95,7 @@ def copy_common_vars_nginx_cfg() -> None:
Creates a common_vars.conf in /etc/nginx/conf.d Creates a common_vars.conf in /etc/nginx/conf.d
:return: None :return: None
""" """
source = MODULE_PATH.joinpath("res/common_vars.conf") source = MODULE_PATH.joinpath("assets/common_vars.conf")
target = NGINX_CONFD.joinpath("common_vars.conf") target = NGINX_CONFD.joinpath("common_vars.conf")
try: try:
command = ["sudo", "cp", source, target] command = ["sudo", "cp", source, target]
@@ -115,7 +115,7 @@ def create_nginx_cfg(name: str, port: int, root_dir: Path) -> None:
:return: None :return: None
""" """
tmp = Path.home().joinpath(f"{name}.tmp") tmp = Path.home().joinpath(f"{name}.tmp")
shutil.copy(MODULE_PATH.joinpath("res/nginx_cfg"), tmp) shutil.copy(MODULE_PATH.joinpath("assets/nginx_cfg"), tmp)
with open(tmp, "r+") as f: with open(tmp, "r+") as f:
content = f.read() content = f.read()
content = content.replace("%NAME%", name) content = content.replace("%NAME%", name)