Compare commits

...

5 Commits

Author SHA1 Message Date
dw-0
d420daca26 fix: options not applied to self.options
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-04-28 12:49:44 +02:00
dw-0
cb62909f41 feat: implement functions of SettingsMenu
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-04-28 12:12:45 +02:00
dw-0
02eebff571 feat: implement KiauhSettings and use it where appropriate
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-04-27 15:03:29 +02:00
dw-0
36b295bd1b refactor: clean up fetch_status code
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-04-26 17:26:52 +02:00
dw-0
372c9c0b7d refactor: update remove menu ui
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-04-25 20:57:35 +02:00
16 changed files with 423 additions and 107 deletions

18
default_kiauh.cfg Normal file
View File

@@ -0,0 +1,18 @@
[kiauh]
backup_before_update: False
[klipper]
repo_url: https://github.com/Klipper3d/klipper
branch: master
[moonraker]
repo_url: https://github.com/Arksine/moonraker
branch: master
[mainsail]
port: 80
unstable_releases: False
[fluidd]
port: 81
unstable_releases: False

View File

@@ -11,7 +11,5 @@ import sys
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
KIAUH_CFG = PROJECT_ROOT.joinpath("kiauh.cfg")
APPLICATION_ROOT = Path(__file__).resolve().parent
sys.path.append(str(APPLICATION_ROOT))

View File

@@ -17,6 +17,5 @@ KLIPPER_DIR = Path.home().joinpath("klipper")
KLIPPER_ENV_DIR = Path.home().joinpath("klippy-env")
KLIPPER_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("klipper-backups")
KLIPPER_REQUIREMENTS_TXT = KLIPPER_DIR.joinpath("scripts/klippy-requirements.txt")
DEFAULT_KLIPPER_REPO_URL = "https://github.com/Klipper3D/klipper"
EXIT_KLIPPER_SETUP = "Exiting Klipper setup ..."

View File

@@ -12,10 +12,9 @@ from pathlib import Path
from components.webui_client.client_utils import (
get_existing_clients,
)
from kiauh import KIAUH_CFG
from core.settings.kiauh_settings import KiauhSettings
from components.klipper import (
EXIT_KLIPPER_SETUP,
DEFAULT_KLIPPER_REPO_URL,
KLIPPER_DIR,
KLIPPER_ENV_DIR,
KLIPPER_REQUIREMENTS_TXT,
@@ -36,7 +35,6 @@ from components.klipper.klipper_utils import (
backup_klipper_dir,
)
from components.moonraker.moonraker import Moonraker
from core.config_manager.config_manager import ConfigManager
from core.instance_manager.instance_manager import InstanceManager
from core.repo_manager.repo_manager import RepoManager
from utils.input_utils import get_confirm
@@ -109,13 +107,10 @@ def install_klipper() -> None:
def setup_klipper_prerequesites() -> None:
cm = ConfigManager(cfg_file=KIAUH_CFG)
repo = str(cm.get_value("klipper", "repository_url") or DEFAULT_KLIPPER_REPO_URL)
branch = str(cm.get_value("klipper", "branch") or "master")
settings = KiauhSettings()
repo_manager = RepoManager(
repo=repo,
branch=branch,
repo=settings.get("klipper", "repo_url"),
branch=settings.get("klipper", "branch"),
target_dir=KLIPPER_DIR,
)
repo_manager.clone_repo()
@@ -150,19 +145,16 @@ def update_klipper() -> None:
if not get_confirm("Update Klipper now?"):
return
cm = ConfigManager(cfg_file=KIAUH_CFG)
if cm.get_value("kiauh", "backup_before_update"):
settings = KiauhSettings()
if settings.get("kiauh", "backup_before_update"):
backup_klipper_dir()
instance_manager = InstanceManager(Klipper)
instance_manager.stop_all_instance()
repo = str(cm.get_value("klipper", "repository_url") or DEFAULT_KLIPPER_REPO_URL)
branch = str(cm.get_value("klipper", "branch") or "master")
repo_manager = RepoManager(
repo=repo,
branch=branch,
repo=settings.get("klipper", "repo_url"),
branch=settings.get("klipper", "branch"),
target_dir=KLIPPER_DIR,
)
repo_manager.pull_repo()

View File

@@ -20,7 +20,6 @@ MOONRAKER_DB_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("moonraker-db-backups")
MOONRAKER_REQUIREMENTS_TXT = MOONRAKER_DIR.joinpath(
"scripts/moonraker-requirements.txt"
)
DEFAULT_MOONRAKER_REPO_URL = "https://github.com/Arksine/moonraker"
DEFAULT_MOONRAKER_PORT = 7125
# introduced due to

View File

@@ -16,11 +16,10 @@ from components.webui_client.client_utils import (
get_existing_clients,
)
from components.webui_client.mainsail_data import MainsailData
from kiauh import KIAUH_CFG
from core.settings.kiauh_settings import KiauhSettings
from components.klipper.klipper import Klipper
from components.moonraker import (
EXIT_MOONRAKER_SETUP,
DEFAULT_MOONRAKER_REPO_URL,
MOONRAKER_DIR,
MOONRAKER_ENV_DIR,
MOONRAKER_REQUIREMENTS_TXT,
@@ -35,7 +34,6 @@ from components.moonraker.moonraker_utils import (
create_example_moonraker_conf,
backup_moonraker_dir,
)
from core.config_manager.config_manager import ConfigManager
from core.instance_manager.instance_manager import InstanceManager
from core.repo_manager.repo_manager import RepoManager
from utils.filesystem_utils import check_file_exist
@@ -133,11 +131,9 @@ def check_moonraker_install_requirements() -> bool:
def setup_moonraker_prerequesites() -> None:
cm = ConfigManager(cfg_file=KIAUH_CFG)
repo = str(
cm.get_value("moonraker", "repository_url") or DEFAULT_MOONRAKER_REPO_URL
)
branch = str(cm.get_value("moonraker", "branch") or "master")
settings = KiauhSettings()
repo = settings.get("moonraker", "repo_url")
branch = settings.get("moonraker", "branch")
repo_manager = RepoManager(
repo=repo,
@@ -193,21 +189,16 @@ def update_moonraker() -> None:
if not get_confirm("Update Moonraker now?"):
return
cm = ConfigManager(cfg_file=KIAUH_CFG)
if cm.get_value("kiauh", "backup_before_update"):
settings = KiauhSettings()
if settings.get("kiauh", "backup_before_update"):
backup_moonraker_dir()
instance_manager = InstanceManager(Moonraker)
instance_manager.stop_all_instance()
repo = str(
cm.get_value("moonraker", "repository_url") or DEFAULT_MOONRAKER_REPO_URL
)
branch = str(cm.get_value("moonraker", "branch") or "master")
repo_manager = RepoManager(
repo=repo,
branch=branch,
repo=settings.get("moonraker", "repo_url"),
branch=settings.get("moonraker", "branch"),
target_dir=MOONRAKER_DIR,
)
repo_manager.pull_repo()

View File

@@ -13,7 +13,7 @@ from pathlib import Path
from typing import List
from components.webui_client.base_data import BaseWebClient, BaseWebClientConfig
from kiauh import KIAUH_CFG
from core.settings.kiauh_settings import KiauhSettings
from components.klipper.klipper import Klipper
from components.moonraker.moonraker import Moonraker
from components.webui_client.client_dialogs import (
@@ -23,7 +23,6 @@ from components.webui_client.client_utils import (
backup_client_config_data,
config_for_other_client_exist,
)
from core.config_manager.config_manager import ConfigManager
from core.instance_manager.instance_manager import InstanceManager
from core.repo_manager.repo_manager import RepoManager
@@ -108,8 +107,8 @@ def update_client_config(client: BaseWebClient) -> None:
)
return
cm = ConfigManager(cfg_file=KIAUH_CFG)
if cm.get_value("kiauh", "backup_before_update"):
settings = KiauhSettings()
if settings.get("kiauh", "backup_before_update"):
backup_client_config_data(client)
repo_manager = RepoManager(

View File

@@ -33,9 +33,8 @@ from components.webui_client.client_utils import (
symlink_webui_nginx_log,
config_for_other_client_exist,
)
from core.config_manager.config_manager import ConfigManager
from core.instance_manager.instance_manager import InstanceManager
from kiauh import KIAUH_CFG
from core.settings.kiauh_settings import KiauhSettings
from utils import NGINX_SITES_AVAILABLE, NGINX_SITES_ENABLED
from utils.common import check_install_dependencies
from utils.filesystem_utils import (
@@ -104,24 +103,23 @@ def install_client(client: BaseWebClient) -> None:
question = f"Download the recommended {client_config.display_name}?"
install_client_cfg = get_confirm(question, allow_go_back=False)
cm = ConfigManager(cfg_file=KIAUH_CFG)
default_port = cm.get_value(client.name, "port")
client_port = default_port if default_port and default_port.isdigit() else "80"
settings = KiauhSettings()
port = settings.get(client.name, "port")
ports_in_use = read_ports_from_nginx_configs()
# check if configured port is a valid number and not in use already
valid_port = is_valid_port(client_port, ports_in_use)
valid_port = is_valid_port(port, ports_in_use)
while not valid_port:
next_port = get_next_free_port(ports_in_use)
print_client_port_select_dialog(client.display_name, next_port, ports_in_use)
client_port = str(
port = str(
get_number_input(
f"Configure {client.display_name} for port",
min_count=int(next_port),
default=next_port,
)
)
valid_port = is_valid_port(client_port, ports_in_use)
valid_port = is_valid_port(port, ports_in_use)
check_install_dependencies(["nginx"])
@@ -146,7 +144,7 @@ def install_client(client: BaseWebClient) -> None:
copy_upstream_nginx_cfg()
copy_common_vars_nginx_cfg()
create_client_nginx_cfg(client, client_port)
create_client_nginx_cfg(client, port)
if kl_instances:
symlink_webui_nginx_log(kl_instances)
control_systemd_service("nginx", "restart")
@@ -155,7 +153,7 @@ def install_client(client: BaseWebClient) -> None:
Logger.print_error(f"{client.display_name} installation failed!\n{e}")
return
log = f"Open {client.display_name} now on: http://{get_ipv4_addr()}:{client_port}"
log = f"Open {client.display_name} now on: http://{get_ipv4_addr()}:{port}"
Logger.print_ok(f"{client.display_name} installation complete!", start="\n")
Logger.print_ok(log, prefix=False, end="\n\n")

View File

@@ -8,7 +8,7 @@
# ======================================================================= #
import textwrap
from typing import Dict, Type, Optional
from typing import Type, Optional
from components.webui_client import client_remove
from components.webui_client.base_data import BaseWebClient, WebClientType
@@ -36,17 +36,15 @@ class ClientRemoveMenu(BaseMenu):
previous_menu if previous_menu is not None else RemoveMenu
)
def set_options(self) -> Dict[str, Option]:
options = {
def set_options(self) -> None:
self.options = {
"0": Option(method=self.toggle_all, menu=False),
"1": Option(method=self.toggle_rm_client, menu=False),
"2": Option(method=self.toggle_rm_client_config, menu=False),
"c": Option(method=self.run_removal_process, menu=False),
}
if self.client.client == WebClientType.MAINSAIL:
options["3"] = Option(self.toggle_backup_mainsail_config_json, False)
return options
self.options["3"] = Option(self.toggle_backup_mainsail_config_json, False)
def print_menu(self) -> None:
client_name = self.client.display_name

View File

@@ -85,28 +85,29 @@ class MainMenu(BaseMenu):
)
def fetch_status(self) -> None:
# klipper
klipper_status = get_klipper_status()
kl_status = klipper_status.get("status")
kl_code = klipper_status.get("status_code")
kl_instances = f" {klipper_status.get('instances')}" if kl_code == 1 else ""
self.kl_status = self.format_status_by_code(kl_code, kl_status, kl_instances)
self.kl_repo = f"{COLOR_CYAN}{klipper_status.get('repo')}{RESET_FORMAT}"
# moonraker
moonraker_status = get_moonraker_status()
mr_status = moonraker_status.get("status")
mr_code = moonraker_status.get("status_code")
mr_instances = f" {moonraker_status.get('instances')}" if mr_code == 1 else ""
self.mr_status = self.format_status_by_code(mr_code, mr_status, mr_instances)
self.mr_repo = f"{COLOR_CYAN}{moonraker_status.get('repo')}{RESET_FORMAT}"
# mainsail
self._update_status("kl", get_klipper_status)
self._update_status("mr", get_moonraker_status)
self.ms_status = get_client_status(MainsailData())
# fluidd
self.fl_status = get_client_status(FluiddData())
# client-config
self.cc_status = get_current_client_config([MainsailData(), FluiddData()])
def format_status_by_code(self, code: int, status: str, count: str) -> str:
def _update_status(self, status_name: str, status_fn: callable) -> None:
status_data = status_fn()
status = status_data.get("status")
code = status_data.get("status_code")
instances = f" {status_data.get('instances')}" if code == 1 else ""
setattr(
self,
f"{status_name}_status",
self._format_status_by_code(code, status, instances),
)
setattr(
self,
f"{status_name}_repo",
f"{COLOR_CYAN}{status_data.get('repo')}{RESET_FORMAT}",
)
def _format_status_by_code(self, code: int, status: str, count: str) -> str:
if code == 1:
return f"{COLOR_GREEN}{status}{count}{RESET_FORMAT}"
elif code == 2:
@@ -165,7 +166,7 @@ class MainMenu(BaseMenu):
BackupMenu(previous_menu=self.__class__).run()
def settings_menu(self, **kwargs):
SettingsMenu().run()
SettingsMenu(previous_menu=self.__class__).run()
def extension_menu(self, **kwargs):
ExtensionsMenu(previous_menu=self.__class__).run()

View File

@@ -55,17 +55,13 @@ class RemoveMenu(BaseMenu):
|-------------------------------------------------------|
| INFO: Configurations and/or any backups will be kept! |
|-------------------------------------------------------|
| Firmware & API: | Webcam Streamer: |
| 1) [Klipper] | 6) [Crowsnest] |
| 2) [Moonraker] | 7) [MJPG-Streamer] |
| | |
| Klipper Webinterface: | Other: |
| 3) [Mainsail] | 8) [PrettyGCode] |
| 4) [Fluidd] | 9) [Telegram Bot] |
| | 10) [Obico for Klipper] |
| Touchscreen GUI: | 11) [OctoEverywhere] |
| 5) [KlipperScreen] | 12) [Mobileraker] |
| | 13) [NGINX] |
| Firmware & API: | Touchscreen GUI: |
| 1) [Klipper] | 5) [KlipperScreen] |
| 2) [Moonraker] | |
| | Webcam Streamer: |
| Klipper Webinterface: | 6) [Crowsnest] |
| 3) [Mainsail] | |
| 4) [Fluidd] | |
| | |
"""
)[1:]

View File

@@ -6,16 +6,37 @@
# #
# This file may be distributed under the terms of the GNU GPLv3 license #
# ======================================================================= #
from typing import Type, Optional
import shutil
import textwrap
from pathlib import Path
from typing import Type, Optional, Tuple
from components.klipper import KLIPPER_DIR
from components.klipper.klipper import Klipper
from components.moonraker import MOONRAKER_DIR
from components.moonraker.moonraker import Moonraker
from core.instance_manager.instance_manager import InstanceManager
from core.menus import Option
from core.menus.base_menu import BaseMenu
from core.repo_manager.repo_manager import RepoManager
from core.settings.kiauh_settings import KiauhSettings
from utils.constants import COLOR_CYAN, RESET_FORMAT, COLOR_GREEN, COLOR_YELLOW
from utils.input_utils import get_string_input, get_confirm
from utils.logger import Logger
# noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic
class SettingsMenu(BaseMenu):
def __init__(self, previous_menu: Optional[Type[BaseMenu]] = None):
super().__init__()
self.previous_menu = previous_menu
self.klipper_repo = None
self.moonraker_repo = None
self.mainsail_unstable = None
self.fluidd_unstable = None
self.auto_backups_enabled = None
self._load_settings()
def set_previous_menu(self, previous_menu: Optional[Type[BaseMenu]]) -> None:
from core.menus.main_menu import MainMenu
@@ -25,19 +46,183 @@ class SettingsMenu(BaseMenu):
)
def set_options(self) -> None:
pass
self.options = {
"1": Option(method=self.set_klipper_repo, menu=True),
"2": Option(method=self.set_moonraker_repo, menu=True),
"3": Option(method=self.toggle_mainsail_release, menu=True),
"4": Option(method=self.toggle_fluidd_release, menu=False),
"5": Option(method=self.toggle_backup_before_update, menu=False),
}
def print_menu(self):
print("self")
header = " [ KIAUH Settings ] "
color = COLOR_CYAN
count = 62 - len(color) - len(RESET_FORMAT)
checked = f"[{COLOR_GREEN}x{RESET_FORMAT}]"
unchecked = "[ ]"
o1 = checked if self.mainsail_unstable else unchecked
o2 = checked if self.fluidd_unstable else unchecked
o3 = checked if self.auto_backups_enabled else unchecked
menu = textwrap.dedent(
f"""
/=======================================================\\
| {color}{header:~^{count}}{RESET_FORMAT} |
|-------------------------------------------------------|
| Klipper source repository: |
| ● {self.klipper_repo:<67} |
| |
| Moonraker source repository: |
| ● {self.moonraker_repo:<67} |
| |
| Install unstable Webinterface releases: |
| {o1} Mainsail |
| {o2} Fluidd |
| |
| Auto-Backup: |
| {o3} Automatic backup before update |
| |
|-------------------------------------------------------|
| 1) Set Klipper source repository |
| 2) Set Moonraker source repository |
| |
| 3) Toggle unstable Mainsail releases |
| 4) Toggle unstable Fluidd releases |
| |
| 5) Toggle automatic backups before updates |
"""
)[1:]
print(menu, end="")
def execute_option_p(self):
# Implement the functionality for Option P
print("Executing Option P")
def _load_settings(self):
self.kiauh_settings = KiauhSettings()
def execute_option_q(self):
# Implement the functionality for Option Q
print("Executing Option Q")
self._format_repo_str("klipper")
self._format_repo_str("moonraker")
def execute_option_r(self):
# Implement the functionality for Option R
print("Executing Option R")
self.auto_backups_enabled = self.kiauh_settings.get(
"kiauh", "backup_before_update"
)
self.mainsail_unstable = self.kiauh_settings.get(
"mainsail", "unstable_releases"
)
self.fluidd_unstable = self.kiauh_settings.get("fluidd", "unstable_releases")
def _format_repo_str(self, repo_name: str) -> None:
repo = self.kiauh_settings.get(repo_name, "repo_url")
repo = f"{'/'.join(repo.rsplit('/', 2)[-2:])}"
branch = self.kiauh_settings.get(repo_name, "branch")
branch = f"({COLOR_CYAN}@ {branch}{RESET_FORMAT})"
setattr(self, f"{repo_name}_repo", f"{COLOR_CYAN}{repo}{RESET_FORMAT} {branch}")
def _gather_input(self) -> Tuple[str, str]:
l2 = "Make sure your input is correct!"
error = textwrap.dedent(
f"""\n
{COLOR_YELLOW}/=======================================================\\
| ATTENTION: |
| There is no input validation in place! Make sure your |
| input is valid and has no typos! For any change to |
| take effect, the repository must be cloned again. |
| Make sure you don't have any ongoing prints running, |
| as the services will be restarted! |
\=======================================================/{RESET_FORMAT}
"""
)[1:]
print(error, end="\n")
repo = get_string_input(
"Enter new repository URL",
allow_special_chars=True,
)
branch = get_string_input(
"Enter new branch name",
allow_special_chars=True,
)
return repo, branch
def _display_summary(self, name: str, repo: str, branch: str):
l1 = f"New {name} repository URL:"
l2 = f"{repo}"
l3 = f"New {name} repository branch:"
l4 = f"{branch}"
summary = textwrap.dedent(
f"""\n
/=======================================================\\
| {l1:<52} |
| {l2:<52} |
| {l3:<52} |
| {l4:<52} |
\=======================================================/
"""
)[1:]
print(summary, end="")
def _set_repo(self, repo_name: str):
repo, branch = self._gather_input()
self._display_summary(repo_name.capitalize(), repo, branch)
if get_confirm("Apply changes?", allow_go_back=True):
self.kiauh_settings.set(repo_name, "repo_url", repo)
self.kiauh_settings.set(repo_name, "branch", branch)
self.kiauh_settings.save()
self._load_settings()
Logger.print_ok("Changes saved!")
else:
Logger.print_info(
f"Skipping change of {repo_name.capitalize()} source repository ..."
)
return
Logger.print_status(
f"Switching to {repo_name.capitalize()}'s new source repository ..."
)
self._switch_repo(repo_name)
Logger.print_ok(f"Switched to {repo} at branch {branch}!")
def _switch_repo(self, name: str) -> None:
target_dir: Path
if name == "klipper":
target_dir = KLIPPER_DIR
_type = Klipper
elif name == "moonraker":
target_dir = MOONRAKER_DIR
_type = Moonraker
else:
Logger.print_error("Invalid repository name!")
return
if target_dir.exists():
shutil.rmtree(target_dir)
im = InstanceManager(_type)
im.stop_all_instance()
repo = self.kiauh_settings.get(name, "repo_url")
branch = self.kiauh_settings.get(name, "branch")
repman = RepoManager(repo, str(target_dir), branch)
repman.clone_repo()
im.start_all_instance()
def set_klipper_repo(self, **kwargs):
self._set_repo("klipper")
def set_moonraker_repo(self, **kwargs):
self._set_repo("moonraker")
def toggle_mainsail_release(self, **kwargs):
self.mainsail_unstable = not self.mainsail_unstable
self.kiauh_settings.set("mainsail", "unstable_releases", self.mainsail_unstable)
self.kiauh_settings.save()
def toggle_fluidd_release(self, **kwargs):
self.fluidd_unstable = not self.fluidd_unstable
self.kiauh_settings.set("fluidd", "unstable_releases", self.fluidd_unstable)
self.kiauh_settings.save()
def toggle_backup_before_update(self, **kwargs):
self.auto_backups_enabled = not self.auto_backups_enabled
self.kiauh_settings.set(
"kiauh", "backup_before_update", self.auto_backups_enabled
)
self.kiauh_settings.save()

View File

View File

@@ -0,0 +1,130 @@
# ======================================================================= #
# 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 textwrap
import configparser
from typing import Dict, Union
from core.config_manager.config_manager import CustomConfigParser
from kiauh import PROJECT_ROOT
from utils.constants import RESET_FORMAT, COLOR_RED
from utils.logger import Logger
from utils.system_utils import kill
# noinspection PyUnusedLocal
# noinspection PyMethodMayBeStatic
class KiauhSettings:
_instance = None
_default_cfg = PROJECT_ROOT.joinpath("default_kiauh.cfg")
_custom_cfg = PROJECT_ROOT.joinpath("kiauh.cfg")
def __new__(cls, *args, **kwargs) -> "KiauhSettings":
if cls._instance is None:
cls._instance = super(KiauhSettings, cls).__new__(cls, *args, **kwargs)
cls._instance.__initialized = False
return cls._instance
def __init__(self) -> None:
if self.__initialized:
return
self.__initialized = True
self.config = CustomConfigParser()
self.settings: Dict[str, Dict[str, Union[str, int, bool]]] = {}
self._load_settings()
def get(self, section: str, option: str) -> Union[str, int, bool]:
return self.settings[section][option]
def set(self, section: str, option: str, value: Union[str, int, bool]) -> None:
self.settings[section][option] = value
def save(self) -> None:
for section, option in self.settings.items():
self.config[section] = option
with open(self._custom_cfg, "w") as configfile:
self.config.write(configfile)
self._load_settings()
def _load_settings(self) -> None:
if self._custom_cfg.exists():
self.config.read(self._custom_cfg)
elif self._default_cfg.exists():
self.config.read(self._default_cfg)
else:
self._kill()
self._validate_cfg()
self._parse_settings()
def _validate_cfg(self) -> None:
try:
self._validate_bool("kiauh", "backup_before_update")
self._validate_str("klipper", "repo_url")
self._validate_str("klipper", "branch")
self._validate_int("mainsail", "port")
self._validate_bool("mainsail", "unstable_releases")
self._validate_int("fluidd", "port")
self._validate_bool("fluidd", "unstable_releases")
except ValueError:
err = f"Invalid value for option '{self._v_option}' in section '{self._v_section}'"
Logger.print_error(err)
kill()
except configparser.NoSectionError:
err = f"Missing section '{self._v_section}' in config file"
Logger.print_error(err)
kill()
except configparser.NoOptionError:
err = f"Missing option '{self._v_option}' in section '{self._v_section}'"
Logger.print_error(err)
kill()
def _validate_bool(self, section: str, option: str) -> None:
self._v_section, self._v_option = (section, option)
bool(self.config.getboolean(section, option))
def _validate_int(self, section: str, option: str) -> None:
self._v_section, self._v_option = (section, option)
int(self.config.getint(section, option))
def _validate_str(self, section: str, option: str) -> None:
self._v_section, self._v_option = (section, option)
v = self.config.get(section, option)
if v.isdigit() or v.lower() == "true" or v.lower() == "false":
raise ValueError
def _parse_settings(self):
for s in self.config.sections():
self.settings[s] = {}
for o, v in self.config.items(s):
if v.lower() == "true":
self.settings[s][o] = True
elif v.lower() == "false":
self.settings[s][o] = False
elif v.isdigit():
self.settings[s][o] = int(v)
else:
self.settings[s][o] = v
def _kill(self) -> None:
l1 = "!!! ERROR !!!"
l2 = "No KIAUH configuration file found!"
error = textwrap.dedent(
f"""
{COLOR_RED}/=======================================================\\
| {l1:^53} |
| {l2:^53} |
\=======================================================/{RESET_FORMAT}
"""
)[1:]
print(error, end="")
kill()

View File

@@ -8,11 +8,13 @@
# ======================================================================= #
from core.menus.main_menu import MainMenu
from core.settings.kiauh_settings import KiauhSettings
from utils.logger import Logger
def main():
try:
KiauhSettings()
MainMenu().run()
except KeyboardInterrupt:
Logger.print_ok("\nHappy printing!\n", prefix=False)

View File

@@ -7,7 +7,7 @@
# This file may be distributed under the terms of the GNU GPLv3 license #
# ======================================================================= #
from typing import Optional, List, Union
from typing import List, Union
from utils import INVALID_CHOICE
from utils.constants import COLOR_CYAN, RESET_FORMAT
@@ -82,23 +82,33 @@ def get_number_input(
Logger.print_error(INVALID_CHOICE)
def get_string_input(question: str, exclude=Optional[List], default=None) -> str:
def get_string_input(
question: str,
exclude: Union[List, None] = None,
allow_special_chars=False,
default=None,
) -> str:
"""
Helper method to get a string input from the user
:param question: The question to display
:param exclude: List of strings which are not allowed
:param allow_special_chars: Wheter to allow special characters in the input
:param default: Optional default value
:return: The validated string value
"""
_exclude = [] if exclude is None else exclude
_question = format_question(question, default)
while True:
_input = input(format_question(question, default)).strip()
_input = input(_question)
if _input.isalnum() and _input.lower() not in exclude:
return _input
Logger.print_error(INVALID_CHOICE)
if _input in exclude:
if _input.lower() in _exclude:
Logger.print_error("This value is already in use/reserved.")
elif allow_special_chars:
return _input
elif not allow_special_chars and _input.isalnum():
return _input
else:
Logger.print_error(INVALID_CHOICE)
def get_selection_input(question: str, option_list: List, default=None) -> str: