mirror of
https://github.com/dw-0/kiauh.git
synced 2025-12-14 11:04:29 +05:00
Compare commits
10 Commits
v6.0.0-alp
...
v6.0.0-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
425d86a12f | ||
|
|
ff6162d799 | ||
|
|
674c174224 | ||
|
|
a368331693 | ||
|
|
406b64d1e5 | ||
|
|
1b5691f2f5 | ||
|
|
e7eae5a0d1 | ||
|
|
dc561a562c | ||
|
|
55cfe124b2 | ||
|
|
43d6598be6 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,10 @@
|
||||
.idea
|
||||
.vscode
|
||||
.pytest_cache
|
||||
.jupyter
|
||||
*.ipynb
|
||||
*.ipynb_checkpoints
|
||||
*.tmp
|
||||
__pycache__
|
||||
.kiauh-env
|
||||
*.code-workspace
|
||||
|
||||
@@ -14,5 +14,5 @@ port: 80
|
||||
unstable_releases: False
|
||||
|
||||
[fluidd]
|
||||
port: 81
|
||||
port: 80
|
||||
unstable_releases: False
|
||||
|
||||
@@ -90,6 +90,21 @@ def find_usb_dfu_device() -> List[str]:
|
||||
return []
|
||||
|
||||
|
||||
def find_usb_rp2_boot_device() -> List[str]:
|
||||
try:
|
||||
output = check_output("lsusb", shell=True, text=True, stderr=DEVNULL)
|
||||
device_list = []
|
||||
if output:
|
||||
devices = output.splitlines()
|
||||
device_list = [d.split(" ")[5] for d in devices if "RP2 Boot" in d]
|
||||
return device_list
|
||||
|
||||
except CalledProcessError as e:
|
||||
Logger.print_error("Unable to find a USB RP2 Boot device!")
|
||||
Logger.print_error(e, prefix=False)
|
||||
return []
|
||||
|
||||
|
||||
def get_sd_flash_board_list() -> List[str]:
|
||||
if not KLIPPER_DIR.exists() or not SD_FLASH_SCRIPT.exists():
|
||||
return []
|
||||
|
||||
@@ -26,6 +26,7 @@ class FlashCommand(Enum):
|
||||
class ConnectionType(Enum):
|
||||
USB = "USB"
|
||||
USB_DFU = "USB (DFU)"
|
||||
USB_RP2040 = "USB (RP2040)"
|
||||
UART = "UART"
|
||||
|
||||
|
||||
|
||||
@@ -143,6 +143,8 @@ class KlipperMcuConnectionHelpMenu(BaseMenu):
|
||||
count = 62 - len(color) - len(RESET_FORMAT)
|
||||
subheader1 = f"{COLOR_CYAN}USB:{RESET_FORMAT}"
|
||||
subheader2 = f"{COLOR_CYAN}UART:{RESET_FORMAT}"
|
||||
subheader3 = f"{COLOR_CYAN}USB DFU:{RESET_FORMAT}"
|
||||
subheader4 = f"{COLOR_CYAN}USB RP2040 Boot:{RESET_FORMAT}"
|
||||
menu = textwrap.dedent(
|
||||
f"""
|
||||
╔═══════════════════════════════════════════════════════╗
|
||||
@@ -164,6 +166,19 @@ class KlipperMcuConnectionHelpMenu(BaseMenu):
|
||||
║ port your controller board is connected to when using ║
|
||||
║ this connection method. ║
|
||||
║ ║
|
||||
║ {subheader3:<62} ║
|
||||
║ Selecting USB DFU as the connection method will scan ║
|
||||
║ the USB ports for connected controller boards in ║
|
||||
║ STM32 DFU mode, which is usually done by holding down ║
|
||||
║ the BOOT button or setting a special jumper on the ║
|
||||
║ board before powering up. ║
|
||||
║ ║
|
||||
║ {subheader4:<62} ║
|
||||
║ Selecting USB RP2 Boot as the connection method will ║
|
||||
║ scan the USB ports for connected RP2040 controller ║
|
||||
║ boards in Boot mode, which is usually done by holding ║
|
||||
║ down the BOOT button before powering up. ║
|
||||
║ ║
|
||||
╟───────────────────────────────────────────────────────╢
|
||||
"""
|
||||
)[1:]
|
||||
|
||||
@@ -17,6 +17,7 @@ from components.klipper_firmware.firmware_utils import (
|
||||
find_uart_device,
|
||||
find_usb_device_by_id,
|
||||
find_usb_dfu_device,
|
||||
find_usb_rp2_boot_device,
|
||||
get_sd_flash_board_list,
|
||||
start_flash_process,
|
||||
)
|
||||
@@ -177,6 +178,7 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
|
||||
"1": Option(method=self.select_usb),
|
||||
"2": Option(method=self.select_dfu),
|
||||
"3": Option(method=self.select_usb_dfu),
|
||||
"4": Option(method=self.select_usb_rp2040),
|
||||
}
|
||||
|
||||
def print_menu(self) -> None:
|
||||
@@ -193,6 +195,7 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
|
||||
║ 1) USB ║
|
||||
║ 2) UART ║
|
||||
║ 3) USB (DFU mode) ║
|
||||
║ 4) USB (RP2040 mode) ║
|
||||
╟───────────────────────────┬───────────────────────────╢
|
||||
"""
|
||||
)[1:]
|
||||
@@ -210,6 +213,10 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
|
||||
self.flash_options.connection_type = ConnectionType.USB_DFU
|
||||
self.get_mcu_list()
|
||||
|
||||
def select_usb_rp2040(self, **kwargs):
|
||||
self.flash_options.connection_type = ConnectionType.USB_RP2040
|
||||
self.get_mcu_list()
|
||||
|
||||
def get_mcu_list(self, **kwargs):
|
||||
conn_type = self.flash_options.connection_type
|
||||
|
||||
@@ -222,6 +229,9 @@ class KlipperSelectMcuConnectionMenu(BaseMenu):
|
||||
elif conn_type is ConnectionType.USB_DFU:
|
||||
Logger.print_status("Identifying MCU connected via USB in DFU mode ...")
|
||||
self.flash_options.mcu_list = find_usb_dfu_device()
|
||||
elif conn_type is ConnectionType.USB_RP2040:
|
||||
Logger.print_status("Identifying MCU connected via USB in RP2 Boot mode ...")
|
||||
self.flash_options.mcu_list = find_usb_rp2_boot_device()
|
||||
|
||||
if len(self.flash_options.mcu_list) < 1:
|
||||
Logger.print_warn("No MCUs found!")
|
||||
|
||||
@@ -13,15 +13,15 @@ from components.webui_client.base_data import BaseWebClient
|
||||
from core.logger import DialogType, Logger
|
||||
|
||||
|
||||
def print_moonraker_not_found_dialog() -> None:
|
||||
def print_moonraker_not_found_dialog(name: str) -> None:
|
||||
Logger.print_dialog(
|
||||
DialogType.WARNING,
|
||||
[
|
||||
"No local Moonraker installation was found!",
|
||||
"\n\n",
|
||||
"It is possible to install Mainsail without a local Moonraker installation. "
|
||||
f"It is possible to install {name} without a local Moonraker installation. "
|
||||
"If you continue, you need to make sure, that Moonraker is installed on "
|
||||
"another machine in your network. Otherwise Mainsail will NOT work "
|
||||
f"another machine in your network. Otherwise {name} will NOT work "
|
||||
"correctly.",
|
||||
],
|
||||
)
|
||||
@@ -40,20 +40,25 @@ def print_client_already_installed_dialog(name: str) -> None:
|
||||
def print_client_port_select_dialog(
|
||||
name: str, port: int, ports_in_use: List[int]
|
||||
) -> None:
|
||||
Logger.print_dialog(
|
||||
DialogType.CUSTOM,
|
||||
[
|
||||
f"Please select the port, {name} should be served on. If your are unsure "
|
||||
f"what to select, hit Enter to apply the suggested value of: {port}",
|
||||
"\n\n",
|
||||
f"In case you need {name} to be served on a specific port, you can set it "
|
||||
f"now. Make sure that the port is not already used by another application "
|
||||
f"on your system!",
|
||||
"\n\n",
|
||||
"The following ports were found to be in use already:",
|
||||
*[f"● {port}" for port in ports_in_use],
|
||||
],
|
||||
)
|
||||
dialog_content: List[str] = [
|
||||
f"Please select the port, {name} should be served on. If your are unsure "
|
||||
f"what to select, hit Enter to apply the suggested value of: {port}",
|
||||
"\n\n",
|
||||
f"In case you need {name} to be served on a specific port, you can set it "
|
||||
f"now. Make sure that the port is not already used by another application "
|
||||
f"on your system!",
|
||||
]
|
||||
|
||||
if ports_in_use:
|
||||
dialog_content.extend(
|
||||
[
|
||||
"\n\n",
|
||||
"The following ports were found to be in use already:",
|
||||
*[f"● {port}" for port in ports_in_use],
|
||||
]
|
||||
)
|
||||
|
||||
Logger.print_dialog(DialogType.CUSTOM, dialog_content)
|
||||
|
||||
|
||||
def print_install_client_config_dialog(client: BaseWebClient) -> None:
|
||||
|
||||
@@ -23,7 +23,6 @@ from components.webui_client.client_config.client_config_setup import (
|
||||
install_client_config,
|
||||
)
|
||||
from components.webui_client.client_dialogs import (
|
||||
print_client_port_select_dialog,
|
||||
print_install_client_config_dialog,
|
||||
print_moonraker_not_found_dialog,
|
||||
)
|
||||
@@ -33,18 +32,15 @@ from components.webui_client.client_utils import (
|
||||
create_nginx_cfg,
|
||||
detect_client_cfg_conflict,
|
||||
enable_mainsail_remotemode,
|
||||
get_next_free_port,
|
||||
is_valid_port,
|
||||
read_ports_from_nginx_configs,
|
||||
get_client_port_selection,
|
||||
symlink_webui_nginx_log,
|
||||
)
|
||||
from core.instance_manager.instance_manager import InstanceManager
|
||||
from core.logger import Logger
|
||||
from core.settings.kiauh_settings import KiauhSettings
|
||||
from utils.common import check_install_dependencies
|
||||
from utils.config_utils import add_config_section
|
||||
from utils.fs_utils import unzip
|
||||
from utils.input_utils import get_confirm, get_number_input
|
||||
from utils.input_utils import get_confirm
|
||||
from utils.instance_utils import get_instances
|
||||
from utils.sys_utils import (
|
||||
cmd_sysctl_service,
|
||||
@@ -67,7 +63,7 @@ def install_client(client: BaseWebClient) -> None:
|
||||
|
||||
enable_remotemode = False
|
||||
if not mr_instances:
|
||||
print_moonraker_not_found_dialog()
|
||||
print_moonraker_not_found_dialog(client.display_name)
|
||||
if not get_confirm(f"Continue {client.display_name} installation?"):
|
||||
return
|
||||
|
||||
@@ -92,21 +88,7 @@ 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)
|
||||
|
||||
settings = KiauhSettings()
|
||||
port: int = settings.get(client.name, "port")
|
||||
ports_in_use: List[int] = read_ports_from_nginx_configs()
|
||||
|
||||
# check if configured port is a valid number and not in use already
|
||||
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)
|
||||
port = get_number_input(
|
||||
f"Configure {client.display_name} for port",
|
||||
min_count=int(next_port),
|
||||
default=next_port,
|
||||
)
|
||||
valid_port = is_valid_port(port, ports_in_use)
|
||||
port: int = get_client_port_selection(client)
|
||||
|
||||
check_install_dependencies({"nginx"})
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ from components.webui_client.base_data import (
|
||||
BaseWebClient,
|
||||
WebClientType,
|
||||
)
|
||||
from components.webui_client.client_dialogs import print_client_port_select_dialog
|
||||
from components.webui_client.fluidd_data import FluiddData
|
||||
from components.webui_client.mainsail_data import MainsailData
|
||||
from core.backup_manager.backup_manager import BackupManager
|
||||
@@ -33,7 +34,7 @@ from core.constants import (
|
||||
RESET_FORMAT,
|
||||
)
|
||||
from core.logger import Logger
|
||||
from core.settings.kiauh_settings import KiauhSettings
|
||||
from core.settings.kiauh_settings import KiauhSettings, WebUiSettings
|
||||
from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import (
|
||||
SimpleConfigParser,
|
||||
)
|
||||
@@ -44,6 +45,7 @@ from utils.git_utils import (
|
||||
get_latest_remote_tag,
|
||||
get_latest_unstable_tag,
|
||||
)
|
||||
from utils.input_utils import get_number_input
|
||||
from utils.instance_utils import get_instances
|
||||
|
||||
|
||||
@@ -353,17 +355,44 @@ def read_ports_from_nginx_configs() -> List[int]:
|
||||
lines = cfg.readlines()
|
||||
|
||||
for line in lines:
|
||||
line = line.replace("default_server", "")
|
||||
line = re.sub(r"[;:\[\]]", "", line.strip())
|
||||
if line.startswith("listen") and line.split()[-1] not in port_list:
|
||||
port_list.append(line.split()[-1])
|
||||
line = re.sub(
|
||||
r"default_server|http://|https://|[;\[\]]",
|
||||
"",
|
||||
line.strip(),
|
||||
)
|
||||
if line.startswith("listen"):
|
||||
if ":" not in line:
|
||||
port_list.append(line.split()[-1])
|
||||
else:
|
||||
port_list.append(line.split(":")[-1])
|
||||
|
||||
ports_to_ints_list = [int(port) for port in port_list]
|
||||
return sorted(ports_to_ints_list, key=lambda x: int(x))
|
||||
|
||||
|
||||
def is_valid_port(port: int, ports_in_use: List[int]) -> bool:
|
||||
return port not in ports_in_use
|
||||
def get_client_port_selection(client: BaseWebClient) -> int:
|
||||
settings = KiauhSettings()
|
||||
default_port: int = int(settings.get(client.name, "port"))
|
||||
|
||||
ports_in_use: List[int] = read_ports_from_nginx_configs()
|
||||
next_free_port: int = get_next_free_port(ports_in_use)
|
||||
|
||||
port: int = next_free_port if default_port in ports_in_use else default_port
|
||||
|
||||
print_client_port_select_dialog(client.display_name, port, ports_in_use)
|
||||
|
||||
while True:
|
||||
question = f"Configure {client.display_name} for port"
|
||||
port_input = get_number_input(question, min_count=80, default=port)
|
||||
|
||||
if port_input not in ports_in_use:
|
||||
client_settings: WebUiSettings = settings[client.name]
|
||||
client_settings.port = port_input
|
||||
settings.save()
|
||||
|
||||
return port_input
|
||||
|
||||
Logger.print_error("This port is already in use. Please select another one.")
|
||||
|
||||
|
||||
def get_next_free_port(ports_in_use: List[int]) -> int:
|
||||
|
||||
@@ -33,7 +33,7 @@ CURRENT_USER = pwd.getpwuid(os.getuid())[0]
|
||||
|
||||
# dirs
|
||||
SYSTEMD = Path("/etc/systemd/system")
|
||||
PRINTER_CFG_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("printer-cfg-backups")
|
||||
PRINTER_DATA_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("printer-data-backups")
|
||||
NGINX_SITES_AVAILABLE = Path("/etc/nginx/sites-available")
|
||||
NGINX_SITES_ENABLED = Path("/etc/nginx/sites-enabled")
|
||||
NGINX_CONFD = Path("/etc/nginx/conf.d")
|
||||
|
||||
@@ -58,12 +58,16 @@ class ExtensionsMenu(BaseMenu):
|
||||
module_path = f"kiauh.extensions.{ext.name}.{module_name}"
|
||||
|
||||
# get the class name of the extension
|
||||
ext_class: Type[BaseExtension] = inspect.getmembers(
|
||||
importlib.import_module(module_path),
|
||||
predicate=lambda o: inspect.isclass(o)
|
||||
and issubclass(o, BaseExtension)
|
||||
and o != BaseExtension,
|
||||
)[0][1]
|
||||
module = importlib.import_module(module_path)
|
||||
|
||||
def predicate(o):
|
||||
return (
|
||||
inspect.isclass(o)
|
||||
and issubclass(o, BaseExtension)
|
||||
and o != BaseExtension
|
||||
)
|
||||
|
||||
ext_class: type = inspect.getmembers(module, predicate)[0][1]
|
||||
|
||||
# instantiate the extension with its metadata and add to dict
|
||||
ext_instance: BaseExtension = ext_class(metadata)
|
||||
@@ -72,7 +76,7 @@ class ExtensionsMenu(BaseMenu):
|
||||
except (IOError, json.JSONDecodeError, ImportError) as e:
|
||||
print(f"Failed loading extension {ext}: {e}")
|
||||
|
||||
return dict(sorted(ext_dict.items()))
|
||||
return dict(sorted(ext_dict.items(), key=lambda x: int(x[0])))
|
||||
|
||||
def extension_submenu(self, **kwargs):
|
||||
ExtensionSubmenu(kwargs.get("opt_data"), self.__class__).run()
|
||||
|
||||
@@ -14,7 +14,6 @@ OA_REPO = "https://github.com/crysxd/OctoApp-Plugin.git"
|
||||
# directories
|
||||
OA_DIR = Path.home().joinpath("octoapp")
|
||||
OA_ENV_DIR = Path.home().joinpath("octoapp-env")
|
||||
OA_STORE_DIR = OA_DIR.joinpath("octoapp-store")
|
||||
|
||||
# files
|
||||
OA_REQ_FILE = OA_DIR.joinpath("requirements.txt")
|
||||
|
||||
@@ -10,6 +10,7 @@ import json
|
||||
from typing import List
|
||||
|
||||
from components.moonraker.moonraker import Moonraker
|
||||
from components.klipper.klipper import Klipper
|
||||
from core.instance_manager.instance_manager import InstanceManager
|
||||
from core.logger import DialogType, Logger
|
||||
from extensions.base_extension import BaseExtension
|
||||
@@ -131,6 +132,7 @@ class OctoappExtension(BaseExtension):
|
||||
|
||||
try:
|
||||
self._remove_OA_instances(ob_instances)
|
||||
self._remove_OA_store_dirs()
|
||||
self._remove_OA_dir()
|
||||
self._remove_OA_env()
|
||||
remove_config_section(f"include {OA_SYS_CFG_NAME}", mr_instances)
|
||||
@@ -181,6 +183,21 @@ class OctoappExtension(BaseExtension):
|
||||
|
||||
run_remove_routines(OA_DIR)
|
||||
|
||||
|
||||
def _remove_OA_store_dirs(self) -> None:
|
||||
Logger.print_status("Removing OctoApp for Klipper store directory ...")
|
||||
|
||||
klipper_instances: List[Moonraker] = get_instances(Klipper)
|
||||
|
||||
for instance in klipper_instances:
|
||||
store_dir = instance.data_dir.joinpath("octoapp-store")
|
||||
if not store_dir.exists():
|
||||
Logger.print_info(f"'{store_dir}' does not exist. Skipped ...")
|
||||
return
|
||||
|
||||
run_remove_routines(store_dir)
|
||||
|
||||
|
||||
def _remove_OA_env(self) -> None:
|
||||
Logger.print_status("Removing OctoApp for Klipper environment ...")
|
||||
|
||||
|
||||
0
kiauh/extensions/simply_print/__init__.py
Normal file
0
kiauh/extensions/simply_print/__init__.py
Normal file
13
kiauh/extensions/simply_print/metadata.json
Normal file
13
kiauh/extensions/simply_print/metadata.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"metadata": {
|
||||
"index": 10,
|
||||
"module": "simply_print_extension",
|
||||
"maintained_by": "dw-0",
|
||||
"display_name": "SimplyPrint",
|
||||
"description": [
|
||||
"3D Printer Cloud Management Software.",
|
||||
"\n\n",
|
||||
"3D printing doesn't have to be a complicated, analog, SD card-filled experience; step into the future of modern 3D printing"
|
||||
]
|
||||
}
|
||||
}
|
||||
131
kiauh/extensions/simply_print/simply_print_extension.py
Normal file
131
kiauh/extensions/simply_print/simply_print_extension.py
Normal file
@@ -0,0 +1,131 @@
|
||||
# ======================================================================= #
|
||||
# Copyright (C) 2020 - 2024 Dominik Willner <th33xitus@gmail.com> #
|
||||
# #
|
||||
# This file is part of KIAUH - Klipper Installation And Update Helper #
|
||||
# https://github.com/dw-0/kiauh #
|
||||
# #
|
||||
# This file may be distributed under the terms of the GNU GPLv3 license #
|
||||
# ======================================================================= #
|
||||
from typing import List
|
||||
|
||||
from components.moonraker.moonraker import Moonraker
|
||||
from core.instance_manager.instance_manager import InstanceManager
|
||||
from core.logger import DialogType, Logger
|
||||
from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import (
|
||||
SimpleConfigParser,
|
||||
)
|
||||
from extensions.base_extension import BaseExtension
|
||||
from utils.common import backup_printer_config_dir, moonraker_exists
|
||||
from utils.input_utils import get_confirm
|
||||
|
||||
|
||||
# noinspection PyMethodMayBeStatic
|
||||
class SimplyPrintExtension(BaseExtension):
|
||||
def install_extension(self, **kwargs) -> None:
|
||||
Logger.print_status("Installing SimplyPrint ...")
|
||||
|
||||
if not (mr_instances := moonraker_exists("SimplyPrint Installer")):
|
||||
return
|
||||
|
||||
Logger.print_dialog(
|
||||
DialogType.INFO,
|
||||
self._construct_dialog(mr_instances, True),
|
||||
)
|
||||
|
||||
if not get_confirm(
|
||||
"Continue SimplyPrint installation?",
|
||||
default_choice=True,
|
||||
allow_go_back=True,
|
||||
):
|
||||
Logger.print_info("Exiting SimplyPrint installation ...")
|
||||
return
|
||||
|
||||
try:
|
||||
self._patch_moonraker_confs(mr_instances, True)
|
||||
|
||||
except Exception as e:
|
||||
Logger.print_error(f"Error during SimplyPrint installation:\n{e}")
|
||||
|
||||
def remove_extension(self, **kwargs) -> None:
|
||||
Logger.print_status("Removing SimplyPrint ...")
|
||||
|
||||
if not (mr_instances := moonraker_exists("SimplyPrint Uninstaller")):
|
||||
return
|
||||
|
||||
Logger.print_dialog(
|
||||
DialogType.INFO,
|
||||
self._construct_dialog(mr_instances, False),
|
||||
)
|
||||
|
||||
if not get_confirm(
|
||||
"Do you really want to uninstall SimplyPrint?",
|
||||
default_choice=True,
|
||||
allow_go_back=True,
|
||||
):
|
||||
Logger.print_info("Exiting SimplyPrint uninstallation ...")
|
||||
return
|
||||
|
||||
try:
|
||||
self._patch_moonraker_confs(mr_instances, False)
|
||||
|
||||
except Exception as e:
|
||||
Logger.print_error(f"Error during SimplyPrint installation:\n{e}")
|
||||
|
||||
def _construct_dialog(
|
||||
self, mr_instances: List[Moonraker], is_install: bool
|
||||
) -> List[str]:
|
||||
mr_names = [f"● {m.service_file_path.name}" for m in mr_instances]
|
||||
_type = "install" if is_install else "uninstall"
|
||||
|
||||
return [
|
||||
"The following Moonraker instances were found:",
|
||||
*mr_names,
|
||||
"\n\n",
|
||||
f"The setup will {_type} SimplyPrint for all Moonraker instances. "
|
||||
f"After {_type}ation, all Moonraker services will be restarted!",
|
||||
]
|
||||
|
||||
def _patch_moonraker_confs(
|
||||
self, mr_instances: List[Moonraker], is_install: bool
|
||||
) -> None:
|
||||
section = "simplyprint"
|
||||
_type, _ft = ("Adding", "to") if is_install else ("Removing", "from")
|
||||
|
||||
patched_files = []
|
||||
for moonraker in mr_instances:
|
||||
Logger.print_status(
|
||||
f"{_type} section 'simplyprint' {_ft} {moonraker.cfg_file} ..."
|
||||
)
|
||||
scp = SimpleConfigParser()
|
||||
scp.read_file(moonraker.cfg_file)
|
||||
|
||||
install_and_has_section = is_install and scp.has_section(section)
|
||||
uninstall_and_has_no_section = not is_install and not scp.has_section(
|
||||
section
|
||||
)
|
||||
|
||||
if install_and_has_section or uninstall_and_has_no_section:
|
||||
status = "already" if is_install else "does not"
|
||||
Logger.print_info(
|
||||
f"Section 'simplyprint' {status} exists! Skipping ..."
|
||||
)
|
||||
continue
|
||||
|
||||
if is_install and not scp.has_section("simplyprint"):
|
||||
backup_printer_config_dir()
|
||||
scp.add_section(section)
|
||||
elif not is_install and scp.has_section("simplyprint"):
|
||||
backup_printer_config_dir()
|
||||
scp.remove_section(section)
|
||||
scp.write_file(moonraker.cfg_file)
|
||||
patched_files.append(moonraker.cfg_file)
|
||||
|
||||
if patched_files:
|
||||
InstanceManager.restart_all(mr_instances)
|
||||
|
||||
install_state = "successfully" if patched_files else "was already"
|
||||
Logger.print_dialog(
|
||||
DialogType.SUCCESS,
|
||||
[f"SimplyPrint {install_state} {'' if is_install else 'un'}installed!"],
|
||||
center_content=True,
|
||||
)
|
||||
@@ -14,10 +14,11 @@ from pathlib import Path
|
||||
from typing import Dict, List, Literal, Optional, Set
|
||||
|
||||
from components.klipper.klipper import Klipper
|
||||
from components.moonraker.moonraker import Moonraker
|
||||
from core.constants import (
|
||||
COLOR_CYAN,
|
||||
GLOBAL_DEPS,
|
||||
PRINTER_CFG_BACKUP_DIR,
|
||||
PRINTER_DATA_BACKUP_DIR,
|
||||
RESET_FORMAT,
|
||||
)
|
||||
from core.logger import DialogType, Logger
|
||||
@@ -142,23 +143,25 @@ def backup_printer_config_dir() -> None:
|
||||
instances: List[Klipper] = get_instances(Klipper)
|
||||
bm = BackupManager()
|
||||
|
||||
if not instances:
|
||||
Logger.print_info("Unable to find directory to backup!")
|
||||
Logger.print_info("Are there no Klipper instances installed?")
|
||||
return
|
||||
|
||||
for instance in instances:
|
||||
name = f"config-{instance.data_dir.name}"
|
||||
bm.backup_directory(
|
||||
name,
|
||||
instance.data_dir.name,
|
||||
source=instance.base.cfg_dir,
|
||||
target=PRINTER_CFG_BACKUP_DIR,
|
||||
target=PRINTER_DATA_BACKUP_DIR,
|
||||
)
|
||||
|
||||
|
||||
def moonraker_exists(name: str = "") -> bool:
|
||||
def moonraker_exists(name: str = "") -> List[Moonraker]:
|
||||
"""
|
||||
Helper method to check if a Moonraker instance exists
|
||||
:param name: Optional name of an installer where the check is performed
|
||||
:return: True if at least one Moonraker instance exists, False otherwise
|
||||
"""
|
||||
from components.moonraker.moonraker import Moonraker
|
||||
|
||||
mr_instances: List[Moonraker] = get_instances(Moonraker)
|
||||
|
||||
info = (
|
||||
@@ -175,8 +178,8 @@ def moonraker_exists(name: str = "") -> bool:
|
||||
f"{info}. Please install Moonraker first!",
|
||||
],
|
||||
)
|
||||
return False
|
||||
return True
|
||||
return []
|
||||
return mr_instances
|
||||
|
||||
|
||||
def trunc_string(input_str: str, length: int) -> str:
|
||||
|
||||
@@ -7,7 +7,7 @@ from http.client import HTTPResponse
|
||||
from json import JSONDecodeError
|
||||
from pathlib import Path
|
||||
from subprocess import DEVNULL, PIPE, CalledProcessError, check_output, run
|
||||
from typing import List, Type
|
||||
from typing import List, Tuple, Type
|
||||
|
||||
from core.instance_manager.instance_manager import InstanceManager
|
||||
from core.logger import Logger
|
||||
@@ -70,7 +70,7 @@ def git_pull_wrapper(repo: str, target_dir: Path) -> None:
|
||||
return
|
||||
|
||||
|
||||
def get_repo_name(repo: Path) -> tuple[str, str] | None:
|
||||
def get_repo_name(repo: Path) -> Tuple[str, str]:
|
||||
"""
|
||||
Helper method to extract the organisation and name of a repository |
|
||||
:param repo: repository to extract the values from
|
||||
@@ -83,11 +83,14 @@ def get_repo_name(repo: Path) -> tuple[str, str] | None:
|
||||
cmd = ["git", "-C", repo.as_posix(), "config", "--get", "remote.origin.url"]
|
||||
result: str = check_output(cmd, stderr=DEVNULL).decode(encoding="utf-8")
|
||||
substrings: List[str] = result.strip().split("/")[-2:]
|
||||
return substrings[0], substrings[1]
|
||||
|
||||
# return "/".join(substrings).replace(".git", "")
|
||||
orga: str = substrings[0] if substrings[0] else "-"
|
||||
name: str = substrings[1] if substrings[1] else "-"
|
||||
|
||||
return orga, name
|
||||
|
||||
except CalledProcessError:
|
||||
return None
|
||||
return "-", "-"
|
||||
|
||||
|
||||
def get_local_tags(repo_path: Path, _filter: str | None = None) -> List[str]:
|
||||
@@ -184,7 +187,7 @@ def compare_semver_tags(tag1: str, tag2: str) -> bool:
|
||||
if tag1 == tag2:
|
||||
return False
|
||||
|
||||
def parse_version(v):
|
||||
def parse_version(v) -> List[int]:
|
||||
return list(map(int, v[1:].split(".")))
|
||||
|
||||
tag1_parts = parse_version(tag1)
|
||||
|
||||
@@ -127,9 +127,9 @@ managed_services: Spoolman
|
||||
regex="${HOME//\//\\/}\/([A-Za-z0-9_]+)\/moonraker\.asvc"
|
||||
moonraker_asvc=$(find "${HOME}" -maxdepth 2 -type f -regextype posix-extended -regex "${regex}" | sort)
|
||||
|
||||
if [[ -n ${moonraker_asvc} ]]; then
|
||||
if ! grep -q "^Spoolman$" "${moonraker_asvc}"; then
|
||||
status_msg "Adding Spoolman service to moonraker.asvc..."
|
||||
/bin/sh -c "echo 'Spoolman' >> ${moonraker_asvc}"
|
||||
sed -i '$a''Spoolman' "${moonraker_asvc}"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ function get_spoolman_status() {
|
||||
|
||||
function get_local_spoolman_version() {
|
||||
[[ ! -d "${SPOOLMAN_DIR}" ]] && return
|
||||
|
||||
|
||||
local version
|
||||
version=$(grep -o '"version":\s*"[^"]*' "${SPOOLMAN_DIR}"/release_info.json | cut -d'"' -f4)
|
||||
echo "${version}"
|
||||
|
||||
Reference in New Issue
Block a user