mirror of
https://github.com/dw-0/kiauh.git
synced 2025-12-23 15:53:36 +05:00
Compare commits
4 Commits
0d7074f86f
...
a5eaed4f26
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a5eaed4f26 | ||
|
|
1484ebf445 | ||
|
|
4547ac571a | ||
|
|
b2dd5d8ed7 |
@@ -7,7 +7,7 @@
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license #
|
||||
# ======================================================================= #
|
||||
|
||||
from dataclasses import field, dataclass
|
||||
from dataclasses import field
|
||||
from enum import Enum
|
||||
from typing import Union, List
|
||||
|
||||
@@ -28,15 +28,14 @@ class ConnectionType(Enum):
|
||||
UART = "UART"
|
||||
|
||||
|
||||
@dataclass
|
||||
class FlashOptions:
|
||||
_instance = None
|
||||
flash_method: Union[FlashMethod, None] = None
|
||||
flash_command: Union[FlashCommand, None] = None
|
||||
connection_type: Union[ConnectionType, None] = None
|
||||
mcu_list: List[str] = field(default_factory=list)
|
||||
selected_mcu: str = ""
|
||||
selected_board: str = ""
|
||||
_flash_method: Union[FlashMethod, None] = None
|
||||
_flash_command: Union[FlashCommand, None] = None
|
||||
_connection_type: Union[ConnectionType, None] = None
|
||||
_mcu_list: List[str] = field(default_factory=list)
|
||||
_selected_mcu: str = ""
|
||||
_selected_board: str = ""
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
if not cls._instance:
|
||||
@@ -46,3 +45,51 @@ class FlashOptions:
|
||||
@classmethod
|
||||
def destroy(cls):
|
||||
cls._instance = None
|
||||
|
||||
@property
|
||||
def flash_method(self) -> Union[FlashMethod, None]:
|
||||
return self._flash_method
|
||||
|
||||
@flash_method.setter
|
||||
def flash_method(self, value: Union[FlashMethod, None]):
|
||||
self._flash_method = value
|
||||
|
||||
@property
|
||||
def flash_command(self) -> Union[FlashCommand, None]:
|
||||
return self._flash_command
|
||||
|
||||
@flash_command.setter
|
||||
def flash_command(self, value: Union[FlashCommand, None]):
|
||||
self._flash_command = value
|
||||
|
||||
@property
|
||||
def connection_type(self) -> Union[ConnectionType, None]:
|
||||
return self._connection_type
|
||||
|
||||
@connection_type.setter
|
||||
def connection_type(self, value: Union[ConnectionType, None]):
|
||||
self._connection_type = value
|
||||
|
||||
@property
|
||||
def mcu_list(self) -> List[str]:
|
||||
return self._mcu_list
|
||||
|
||||
@mcu_list.setter
|
||||
def mcu_list(self, value: List[str]) -> None:
|
||||
self._mcu_list = value
|
||||
|
||||
@property
|
||||
def selected_mcu(self) -> str:
|
||||
return self._selected_mcu
|
||||
|
||||
@selected_mcu.setter
|
||||
def selected_mcu(self, value: str) -> None:
|
||||
self._selected_mcu = value
|
||||
|
||||
@property
|
||||
def selected_board(self) -> str:
|
||||
return self._selected_board
|
||||
|
||||
@selected_board.setter
|
||||
def selected_board(self, value: str) -> None:
|
||||
self._selected_board = value
|
||||
|
||||
@@ -39,7 +39,7 @@ class KlipperFlashMethodMenu(BaseMenu):
|
||||
self.options = {
|
||||
"1": self.select_regular,
|
||||
"2": self.select_sdcard,
|
||||
"h": lambda: KlipperFlashMethodHelpMenu(self).run(),
|
||||
"h": self.help_menu,
|
||||
}
|
||||
self.input_label_txt = "Select flash method"
|
||||
self.footer_type = FooterType.BACK_HELP
|
||||
@@ -78,6 +78,9 @@ class KlipperFlashMethodMenu(BaseMenu):
|
||||
def goto_next_menu(self, **kwargs):
|
||||
KlipperFlashCommandMenu(previous_menu=self).run()
|
||||
|
||||
def help_menu(self, **kwargs):
|
||||
KlipperFlashMethodHelpMenu(previous_menu=self).run()
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
# noinspection PyMethodMayBeStatic
|
||||
@@ -89,7 +92,7 @@ class KlipperFlashCommandMenu(BaseMenu):
|
||||
self.options = {
|
||||
"1": self.select_flash,
|
||||
"2": self.select_serialflash,
|
||||
"h": lambda: KlipperFlashCommandHelpMenu(previous_menu=self).run(),
|
||||
"h": self.help_menu,
|
||||
}
|
||||
self.default_option = self.select_flash
|
||||
self.input_label_txt = "Select flash command"
|
||||
@@ -121,6 +124,9 @@ class KlipperFlashCommandMenu(BaseMenu):
|
||||
def goto_next_menu(self, **kwargs):
|
||||
KlipperSelectMcuConnectionMenu(previous_menu=self).run()
|
||||
|
||||
def help_menu(self, **kwargs):
|
||||
KlipperFlashCommandHelpMenu(previous_menu=self).run()
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
# noinspection PyMethodMayBeStatic
|
||||
@@ -133,7 +139,7 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
|
||||
"1": self.select_usb,
|
||||
"2": self.select_dfu,
|
||||
"3": self.select_usb_dfu,
|
||||
"h": lambda: KlipperMcuConnectionHelpMenu(previous_menu=self).run(),
|
||||
"h": self.help_menu,
|
||||
}
|
||||
self.input_label_txt = "Select connection type"
|
||||
self.footer_type = FooterType.BACK_HELP
|
||||
@@ -184,8 +190,6 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
|
||||
Logger.print_status("Identifying MCU connected via USB in DFU mode ...")
|
||||
self.flash_options.mcu_list = find_usb_dfu_device()
|
||||
|
||||
print(self.flash_options.mcu_list)
|
||||
|
||||
if len(self.flash_options.mcu_list) < 1:
|
||||
Logger.print_warn("No MCUs found!")
|
||||
Logger.print_warn("Make sure they are connected and repeat this step.")
|
||||
@@ -195,6 +199,9 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
|
||||
def goto_next_menu(self, **kwargs):
|
||||
KlipperSelectMcuIdMenu(previous_menu=self).run()
|
||||
|
||||
def help_menu(self, **kwargs):
|
||||
KlipperMcuConnectionHelpMenu(previous_menu=self).run()
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
# noinspection PyMethodMayBeStatic
|
||||
@@ -205,7 +212,6 @@ class KlipperSelectMcuIdMenu(BaseMenu):
|
||||
self.previous_menu: BaseMenu = previous_menu
|
||||
self.flash_options = FlashOptions()
|
||||
self.mcu_list = self.flash_options.mcu_list
|
||||
print(self.mcu_list)
|
||||
options = {f"{index}": self.flash_mcu for index in range(len(self.mcu_list))}
|
||||
self.options = options
|
||||
self.input_label_txt = "Select MCU to flash"
|
||||
|
||||
@@ -17,6 +17,7 @@ from core.menus.base_menu import BaseMenu
|
||||
from utils.constants import COLOR_YELLOW, RESET_FORMAT
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
class AdvancedMenu(BaseMenu):
|
||||
def __init__(self, previous_menu: BaseMenu):
|
||||
super().__init__()
|
||||
@@ -26,9 +27,9 @@ class AdvancedMenu(BaseMenu):
|
||||
"1": None,
|
||||
"2": None,
|
||||
"3": None,
|
||||
"4": lambda: KlipperFlashMethodMenu(previous_menu=self).run(),
|
||||
"4": self.flash,
|
||||
"5": None,
|
||||
"6": lambda: KlipperSelectMcuConnectionMenu(previous_menu=self).run(),
|
||||
"6": self.get_id,
|
||||
}
|
||||
|
||||
def print_menu(self):
|
||||
@@ -52,3 +53,9 @@ class AdvancedMenu(BaseMenu):
|
||||
"""
|
||||
)[1:]
|
||||
print(menu, end="")
|
||||
|
||||
def flash(self, **kwargs):
|
||||
KlipperFlashMethodMenu(previous_menu=self).run()
|
||||
|
||||
def get_id(self, **kwargs):
|
||||
KlipperSelectMcuConnectionMenu(previous_menu=self).run()
|
||||
|
||||
@@ -13,7 +13,7 @@ import subprocess
|
||||
import sys
|
||||
import textwrap
|
||||
from abc import abstractmethod, ABC
|
||||
from typing import Dict, Union, Callable, Type
|
||||
from typing import Dict, Union, Callable, Type, Tuple
|
||||
|
||||
from core.menus import FooterType, NAVI_OPTIONS, ExitAppException, GoBackException
|
||||
from utils.constants import (
|
||||
@@ -129,7 +129,7 @@ class BaseMenu(ABC):
|
||||
self.print_menu()
|
||||
self.print_footer()
|
||||
|
||||
def validate_user_input(self, usr_input: str) -> Callable:
|
||||
def validate_user_input(self, usr_input: str) -> Tuple[Callable, str]:
|
||||
"""
|
||||
Validate the user input and either return an Option, a string or None
|
||||
:param usr_input: The user input in form of a string
|
||||
@@ -148,16 +148,16 @@ class BaseMenu(ABC):
|
||||
elif usr_input == "b":
|
||||
raise GoBackException()
|
||||
elif usr_input == "h":
|
||||
return option
|
||||
return option, usr_input
|
||||
|
||||
# if usr_input is None or an empty string, we execute the menues default option if specified
|
||||
if usr_input == "" and self.default_option is not None:
|
||||
return self.default_option
|
||||
return self.default_option, usr_input
|
||||
|
||||
# user selected a regular option
|
||||
return option
|
||||
return option, usr_input
|
||||
|
||||
def handle_user_input(self) -> Callable:
|
||||
def handle_user_input(self) -> Tuple[Callable, str]:
|
||||
"""Handle the user input, return the validated input or print an error."""
|
||||
while True:
|
||||
print(f"{COLOR_CYAN}###### {self.input_label_txt}: {RESET_FORMAT}", end="")
|
||||
@@ -173,7 +173,8 @@ class BaseMenu(ABC):
|
||||
while True:
|
||||
try:
|
||||
self.display_menu()
|
||||
self.handle_user_input()()
|
||||
option = self.handle_user_input()
|
||||
option[0](opt_index=option[1])
|
||||
except GoBackException:
|
||||
return
|
||||
except ExitAppException:
|
||||
|
||||
@@ -12,10 +12,10 @@ import inspect
|
||||
import json
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
from typing import Type, Dict
|
||||
|
||||
from core.base_extension import BaseExtension
|
||||
from core.menus.base_menu import BaseMenu, Options
|
||||
from core.menus.base_menu import BaseMenu
|
||||
from utils.constants import RESET_FORMAT, COLOR_CYAN, COLOR_YELLOW
|
||||
|
||||
|
||||
@@ -27,42 +27,44 @@ class ExtensionsMenu(BaseMenu):
|
||||
|
||||
self.previous_menu: BaseMenu = previous_menu
|
||||
self.extensions = self.discover_extensions()
|
||||
self.options: Options = self.get_options(self.extensions)
|
||||
self.options = {ext: self.extension_submenu for ext in self.extensions}
|
||||
|
||||
def discover_extensions(self) -> List[BaseExtension]:
|
||||
extensions = []
|
||||
def discover_extensions(self) -> Dict[str, BaseExtension]:
|
||||
ext_dict = {}
|
||||
extensions_dir = Path(__file__).resolve().parents[2].joinpath("extensions")
|
||||
|
||||
for extension in extensions_dir.iterdir():
|
||||
metadata_json = Path(extension).joinpath("metadata.json")
|
||||
for ext in extensions_dir.iterdir():
|
||||
metadata_json = Path(ext).joinpath("metadata.json")
|
||||
if not metadata_json.exists():
|
||||
continue
|
||||
|
||||
try:
|
||||
with open(metadata_json, "r") as m:
|
||||
# read extension metadata from json
|
||||
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),
|
||||
module_name = metadata.get("module")
|
||||
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]
|
||||
extensions.append(extension(metadata))
|
||||
)[0][1]
|
||||
|
||||
# instantiate the extension with its metadata and add to dict
|
||||
ext_instance: BaseExtension = ext_class(metadata)
|
||||
ext_dict[f"{metadata.get('index')}"] = ext_instance
|
||||
|
||||
except (IOError, json.JSONDecodeError, ImportError) as e:
|
||||
print(f"Failed loading extension {extension}: {e}")
|
||||
print(f"Failed loading extension {ext}: {e}")
|
||||
|
||||
return sorted(extensions, key=lambda ex: ex.metadata.get("index"))
|
||||
return ext_dict
|
||||
|
||||
def get_options(self, extensions: List[BaseExtension]) -> Options:
|
||||
options: Options = {}
|
||||
for extension in extensions:
|
||||
index = extension.metadata.get("index")
|
||||
options[f"{index}"] = lambda: ExtensionSubmenu(self, extension).run()
|
||||
|
||||
return options
|
||||
def extension_submenu(self, **kwargs):
|
||||
extension = self.extensions.get(kwargs.get("opt_index"))
|
||||
ExtensionSubmenu(self, extension).run()
|
||||
|
||||
def print_menu(self):
|
||||
header = " [ Extensions Menu ] "
|
||||
@@ -80,7 +82,7 @@ class ExtensionsMenu(BaseMenu):
|
||||
)[1:]
|
||||
print(menu, end="")
|
||||
|
||||
for extension in self.extensions:
|
||||
for extension in self.extensions.values():
|
||||
index = extension.metadata.get("index")
|
||||
name = extension.metadata.get("display_name")
|
||||
row = f"{index}) {name}"
|
||||
|
||||
@@ -36,21 +36,21 @@ from utils.constants import (
|
||||
)
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
# noinspection PyMethodMayBeStatic
|
||||
class MainMenu(BaseMenu):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.options = {
|
||||
"0": lambda: LogUploadMenu(previous_menu=self).run(),
|
||||
"1": lambda: InstallMenu(previous_menu=self).run(),
|
||||
"2": lambda: UpdateMenu(previous_menu=self).run(),
|
||||
"3": lambda: RemoveMenu(previous_menu=self).run(),
|
||||
"4": lambda: AdvancedMenu(previous_menu=self).run(),
|
||||
"5": lambda: BackupMenu(previous_menu=self).run(),
|
||||
"6": None,
|
||||
"e": lambda: ExtensionsMenu(previous_menu=self).run(),
|
||||
"s": lambda: SettingsMenu(previous_menu=self).run(),
|
||||
"0": self.log_upload_menu,
|
||||
"1": self.install_menu,
|
||||
"2": self.update_menu,
|
||||
"3": self.remove_menu,
|
||||
"4": self.advanced_menu,
|
||||
"5": self.backup_menu,
|
||||
"e": self.extension_menu,
|
||||
"s": self.settings_menu,
|
||||
}
|
||||
self.header = True
|
||||
self.footer_type = FooterType.QUIT
|
||||
@@ -141,3 +141,27 @@ class MainMenu(BaseMenu):
|
||||
"""
|
||||
)[1:]
|
||||
print(menu, end="")
|
||||
|
||||
def log_upload_menu(self, **kwargs):
|
||||
LogUploadMenu(previous_menu=self).run()
|
||||
|
||||
def install_menu(self, **kwargs):
|
||||
InstallMenu(previous_menu=self).run()
|
||||
|
||||
def update_menu(self, **kwargs):
|
||||
UpdateMenu(previous_menu=self).run()
|
||||
|
||||
def remove_menu(self, **kwargs):
|
||||
RemoveMenu(previous_menu=self).run()
|
||||
|
||||
def advanced_menu(self, **kwargs):
|
||||
AdvancedMenu(previous_menu=self).run()
|
||||
|
||||
def backup_menu(self, **kwargs):
|
||||
BackupMenu(previous_menu=self).run()
|
||||
|
||||
def settings_menu(self, **kwargs):
|
||||
SettingsMenu(previous_menu=self).run()
|
||||
|
||||
def extension_menu(self, **kwargs):
|
||||
ExtensionsMenu(previous_menu=self).run()
|
||||
|
||||
@@ -27,14 +27,10 @@ class RemoveMenu(BaseMenu):
|
||||
|
||||
self.previous_menu: BaseMenu = previous_menu
|
||||
self.options = {
|
||||
"1": lambda: KlipperRemoveMenu(previous_menu=self).run(),
|
||||
"2": lambda: MoonrakerRemoveMenu(previous_menu=self).run(),
|
||||
"3": lambda: ClientRemoveMenu(
|
||||
previous_menu=self, client=load_client_data("mainsail")
|
||||
).run(),
|
||||
"4": lambda: ClientRemoveMenu(
|
||||
previous_menu=self, client=load_client_data("fluidd")
|
||||
).run(),
|
||||
"1": self.remove_klipper,
|
||||
"2": self.remove_moonraker,
|
||||
"3": self.remove_mainsail,
|
||||
"4": self.remove_fluidd,
|
||||
"5": None,
|
||||
"6": None,
|
||||
"7": None,
|
||||
@@ -72,3 +68,15 @@ class RemoveMenu(BaseMenu):
|
||||
"""
|
||||
)[1:]
|
||||
print(menu, end="")
|
||||
|
||||
def remove_klipper(self, **kwargs):
|
||||
KlipperRemoveMenu(previous_menu=self).run()
|
||||
|
||||
def remove_moonraker(self, **kwargs):
|
||||
MoonrakerRemoveMenu(previous_menu=self).run()
|
||||
|
||||
def remove_mainsail(self, **kwargs):
|
||||
ClientRemoveMenu(previous_menu=self, client=load_client_data("mainsail")).run()
|
||||
|
||||
def remove_fluidd(self, **kwargs):
|
||||
ClientRemoveMenu(previous_menu=self, client=load_client_data("fluidd")).run()
|
||||
|
||||
Reference in New Issue
Block a user