refactor: full refactor of how webclient data is handled

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
This commit is contained in:
dw-0
2024-04-06 15:09:33 +02:00
parent 1484ebf445
commit 06801a47eb
20 changed files with 543 additions and 369 deletions

View File

@@ -30,7 +30,7 @@ from components.klipper.klipper_dialogs import (
)
from components.moonraker.moonraker import Moonraker
from components.moonraker.moonraker_utils import moonraker_to_multi_conversion
from components.webui_client import ClientData
from components.webui_client.base_data import BaseWebClient
from components.webui_client.client_config.client_config_setup import (
create_client_config_symlink,
)
@@ -288,7 +288,7 @@ def get_highest_index(instance_list: List[Klipper]) -> int:
def create_example_printer_cfg(
instance: Klipper, clients: Optional[List[ClientData]] = None
instance: Klipper, clients: Optional[List[BaseWebClient]] = None
) -> None:
Logger.print_status(f"Creating example printer.cfg in '{instance.cfg_dir}'")
if instance.cfg_file.is_file():
@@ -309,8 +309,8 @@ def create_example_printer_cfg(
# include existing client configs in the example config
if clients is not None and len(clients) > 0:
for c in clients:
client_config = c.get("client_config")
section = client_config.get("printer_cfg_section")
client_config = c.client_config
section = client_config.config_section
cm.config.add_section(section=section)
create_client_config_symlink(client_config, [instance])

View File

@@ -11,11 +11,11 @@ import subprocess
import sys
from pathlib import Path
from components.webui_client import MAINSAIL_DIR
from components.webui_client.client_utils import (
enable_mainsail_remotemode,
get_existing_clients,
)
from components.webui_client.mainsail_data import MainsailData
from kiauh import KIAUH_CFG
from components.klipper.klipper import Klipper
from components.moonraker import (
@@ -113,7 +113,7 @@ def install_moonraker() -> None:
# if mainsail is installed, and we installed
# multiple moonraker instances, we enable mainsails remote mode
if MAINSAIL_DIR.exists() and len(mr_im.instances) > 1:
if MainsailData().client_dir.exists() and len(mr_im.instances) > 1:
enable_mainsail_remotemode()

View File

@@ -19,8 +19,9 @@ from components.moonraker import (
MOONRAKER_DB_BACKUP_DIR,
)
from components.moonraker.moonraker import Moonraker
from components.webui_client import MAINSAIL_DIR, ClientData
from components.webui_client.base_data import BaseWebClient
from components.webui_client.client_utils import enable_mainsail_remotemode
from components.webui_client.mainsail_data import MainsailData
from core.backup_manager.backup_manager import BackupManager
from core.config_manager.config_manager import ConfigManager
from core.instance_manager.instance_manager import InstanceManager
@@ -52,7 +53,7 @@ def get_moonraker_status() -> (
def create_example_moonraker_conf(
instance: Moonraker,
ports_map: Dict[str, int],
clients: Optional[List[ClientData]] = None,
clients: Optional[List[BaseWebClient]] = None,
) -> None:
Logger.print_status(f"Creating example moonraker.conf in '{instance.cfg_dir}'")
if instance.cfg_file.is_file():
@@ -100,26 +101,26 @@ def create_example_moonraker_conf(
if clients is not None and len(clients) > 0:
for c in clients:
# client part
c_section = f"update_manager {c.get('name')}"
c_section = f"update_manager {c.name}"
c_options = [
("type", "web"),
("channel", "stable"),
("repo", c.get("mr_conf_repo")),
("path", c.get("mr_conf_path")),
("repo", c.repo_path),
("path", c.client_dir),
]
cm.config.add_section(section=c_section)
for option in c_options:
cm.config.set(c_section, option[0], option[1])
# client config part
c_config = c.get("client_config")
if c_config.get("dir").exists():
c_config_section = f"update_manager {c_config.get('name')}"
c_config = c.client_config
if c_config.config_dir.exists():
c_config_section = f"update_manager {c_config.name}"
c_config_options = [
("type", "git_repo"),
("primary_branch", "master"),
("path", c_config.get("mr_conf_path")),
("origin", c_config.get("mr_conf_origin")),
("path", c_config.config_dir),
("origin", c_config.repo_url),
("managed_services", "klipper"),
]
cm.config.add_section(section=c_config_section)
@@ -177,7 +178,7 @@ def moonraker_to_multi_conversion(new_name: str) -> None:
im.start_instance()
# if mainsail is installed, we enable mainsails remote mode
if MAINSAIL_DIR.exists() and len(im.instances) > 1:
if MainsailData().client_dir.exists() and len(im.instances) > 1:
enable_mainsail_remotemode()

View File

@@ -1,75 +0,0 @@
# ======================================================================= #
# 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
from typing import Literal, TypedDict
from core.backup_manager import BACKUP_ROOT_DIR
MODULE_PATH = Path(__file__).resolve().parent
###########
# MAINSAIL
###########
MAINSAIL_DIR = Path.home().joinpath("mainsail")
MAINSAIL_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("mainsail-backups")
MAINSAIL_CONFIG_DIR = Path.home().joinpath("mainsail-config")
MAINSAIL_CONFIG_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("mainsail-config-backups")
MAINSAIL_CONFIG_REPO_URL = "https://github.com/mainsail-crew/mainsail-config.git"
MAINSAIL_CONFIG_JSON = MAINSAIL_DIR.joinpath("config.json")
MAINSAIL_URL = (
"https://github.com/mainsail-crew/mainsail/releases/latest/download/mainsail.zip"
)
MAINSAIL_PRE_RLS_URL = (
"https://github.com/mainsail-crew/mainsail/releases/download/%TAG%/mainsail.zip"
)
MAINSAIL_TAGS_URL = "https://api.github.com/repos/mainsail-crew/mainsail/tags"
#########
# FLUIDD
#########
FLUIDD_DIR = Path.home().joinpath("fluidd")
FLUIDD_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("fluidd-backups")
FLUIDD_CONFIG_DIR = Path.home().joinpath("fluidd-config")
FLUIDD_CONFIG_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("fluidd-config-backups")
FLUIDD_CONFIG_REPO_URL = "https://github.com/fluidd-core/fluidd-config.git"
FLUIDD_URL = "https://github.com/fluidd-core/fluidd/releases/latest/download/fluidd.zip"
FLUIDD_PRE_RLS_URL = (
"https://github.com/fluidd-core/fluidd/releases/download/%TAG%/fluidd.zip"
)
FLUIDD_TAGS_URL = "https://api.github.com/repos/fluidd-core/fluidd/tags"
ClientName = Literal["mainsail", "fluidd"]
ClientConfigName = Literal["mainsail-config", "fluidd-config"]
class ClientData(TypedDict):
name: ClientName
display_name: str
dir: Path
backup_dir: Path
url: str
pre_release_url: str
tags_url: str
remote_mode: bool # required only for Mainsail
mr_conf_repo: str
mr_conf_path: str
client_config: "ClientConfigData"
class ClientConfigData(TypedDict):
name: ClientConfigName
display_name: str
cfg_filename: str
dir: Path
backup_dir: Path
url: str
printer_cfg_section: str
mr_conf_path: str
mr_conf_origin: str

View File

@@ -0,0 +1,117 @@
# ======================================================================= #
# 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 __future__ import annotations
from abc import ABC, abstractmethod
from enum import Enum
from pathlib import Path
class WebClientType(Enum):
MAINSAIL: str = "mainsail"
FLUIDD: str = "fluidd"
class WebClientConfigType(Enum):
MAINSAIL: str = "mainsail-config"
FLUIDD: str = "fluidd-config"
class BaseWebClient(ABC):
"""Base class for webclient data"""
@property
@abstractmethod
def client(self) -> WebClientType:
raise NotImplementedError
@property
@abstractmethod
def name(self) -> str:
raise NotImplementedError
@property
@abstractmethod
def display_name(self) -> str:
raise NotImplementedError
@property
@abstractmethod
def client_dir(self) -> Path:
raise NotImplementedError
@property
@abstractmethod
def backup_dir(self) -> Path:
raise NotImplementedError
@property
@abstractmethod
def repo_path(self) -> str:
raise NotImplementedError
@property
@abstractmethod
def stable_url(self) -> str:
raise NotImplementedError
@property
@abstractmethod
def unstable_url(self) -> str:
raise NotImplementedError
@property
@abstractmethod
def client_config(self) -> BaseWebClientConfig:
raise NotImplementedError
class BaseWebClientConfig(ABC):
"""Base class for webclient config data"""
@property
@abstractmethod
def client_config(self) -> WebClientConfigType:
raise NotImplementedError
@property
@abstractmethod
def name(self) -> str:
raise NotImplementedError
@property
@abstractmethod
def display_name(self) -> str:
raise NotImplementedError
@property
@abstractmethod
def config_filename(self) -> str:
raise NotImplementedError
@property
@abstractmethod
def config_dir(self) -> Path:
raise NotImplementedError
@property
@abstractmethod
def backup_dir(self) -> Path:
raise NotImplementedError
@property
@abstractmethod
def repo_url(self) -> str:
raise NotImplementedError
@property
@abstractmethod
def config_section(self) -> str:
raise NotImplementedError

View File

@@ -14,26 +14,26 @@ from typing import List
from components.klipper.klipper import Klipper
from components.moonraker.moonraker import Moonraker
from components.webui_client import ClientConfigData
from components.webui_client.base_data import BaseWebClientConfig
from core.instance_manager.instance_manager import InstanceManager
from utils.filesystem_utils import remove_file, remove_config_section
from utils.logger import Logger
def run_client_config_removal(
client_config: ClientConfigData,
client_config: BaseWebClientConfig,
kl_instances: List[Klipper],
mr_instances: List[Moonraker],
) -> None:
remove_client_config_dir(client_config)
remove_client_config_symlink(client_config)
remove_config_section(f"update_manager {client_config.get('name')}", mr_instances)
remove_config_section(client_config.get("printer_cfg_section"), kl_instances)
remove_config_section(f"update_manager {client_config.name}", mr_instances)
remove_config_section(client_config.config_section, kl_instances)
def remove_client_config_dir(client_config: ClientConfigData) -> None:
Logger.print_status(f"Removing {client_config.get('name')} ...")
client_config_dir = client_config.get("dir")
def remove_client_config_dir(client_config: BaseWebClientConfig) -> None:
Logger.print_status(f"Removing {client_config.name} ...")
client_config_dir = client_config.config_dir
if not client_config_dir.exists():
Logger.print_info(f"'{client_config_dir}' does not exist. Skipping ...")
return
@@ -44,12 +44,12 @@ def remove_client_config_dir(client_config: ClientConfigData) -> None:
Logger.print_error(f"Unable to delete '{client_config_dir}':\n{e}")
def remove_client_config_symlink(client_config: ClientConfigData) -> None:
def remove_client_config_symlink(client_config: BaseWebClientConfig) -> None:
im = InstanceManager(Klipper)
instances: List[Klipper] = im.instances
for instance in instances:
Logger.print_status(f"Removing symlink from '{instance.cfg_dir}' ...")
symlink = instance.cfg_dir.joinpath(client_config.get("cfg_filename"))
symlink = instance.cfg_dir.joinpath(client_config.config_filename)
if not symlink.is_symlink():
Logger.print_info(f"'{symlink}' does not exist. Skipping ...")
continue

View File

@@ -12,15 +12,14 @@ import subprocess
from pathlib import Path
from typing import List
from components.webui_client.base_data import BaseWebClient, BaseWebClientConfig
from kiauh import KIAUH_CFG
from components.klipper.klipper import Klipper
from components.moonraker.moonraker import Moonraker
from components.webui_client import ClientConfigData, ClientName, ClientData
from components.webui_client.client_dialogs import (
print_client_already_installed_dialog,
)
from components.webui_client.client_utils import (
load_client_data,
backup_client_config_data,
config_for_other_client_exist,
)
@@ -38,19 +37,18 @@ from utils.input_utils import get_confirm
from utils.logger import Logger
def install_client_config(client_name: ClientName) -> None:
client: ClientData = load_client_data(client_name)
client_config: ClientConfigData = client.get("client_config")
d_name = client_config.get("display_name")
def install_client_config(client_data: BaseWebClient) -> None:
client_config: BaseWebClientConfig = client_data.client_config
display_name = client_config.display_name
if config_for_other_client_exist(client_name):
if config_for_other_client_exist(client_data.client):
Logger.print_info("Another Client-Config is already installed! Skipped ...")
return
if client_config.get("dir").exists():
print_client_already_installed_dialog(d_name)
if get_confirm(f"Re-install {d_name}?", allow_go_back=True):
shutil.rmtree(client_config.get("dir"))
if client_config.config_dir.exists():
print_client_already_installed_dialog(display_name)
if get_confirm(f"Re-install {display_name}?", allow_go_back=True):
shutil.rmtree(client_config.config_dir)
else:
return
@@ -66,69 +64,74 @@ def install_client_config(client_name: ClientName) -> None:
backup_printer_config_dir()
add_config_section(
section=f"update_manager {client_config.get('name')}",
section=f"update_manager {client_config.name}",
instances=mr_instances,
options=[
("type", "git_repo"),
("primary_branch", "master"),
("path", client_config.get("mr_conf_path")),
("origin", client_config.get("mr_conf_origin")),
("path", str(client_config.config_dir)),
("origin", str(client_config.repo_url)),
("managed_services", "klipper"),
],
)
add_config_section_at_top(
client_config.get("printer_cfg_section"), kl_instances
)
add_config_section_at_top(client_config.config_section, kl_instances)
kl_im.restart_all_instance()
except Exception as e:
Logger.print_error(f"{d_name} installation failed!\n{e}")
Logger.print_error(f"{display_name} installation failed!\n{e}")
return
Logger.print_ok(f"{d_name} installation complete!", start="\n")
Logger.print_ok(f"{display_name} installation complete!", start="\n")
def download_client_config(client_config: ClientConfigData) -> None:
def download_client_config(client_config: BaseWebClientConfig) -> None:
try:
Logger.print_status(f"Downloading {client_config.get('display_name')} ...")
Logger.print_status(f"Downloading {client_config.display_name} ...")
rm = RepoManager(
client_config.get("url"), target_dir=str(client_config.get("dir"))
client_config.repo_url,
target_dir=str(client_config.config_dir),
)
rm.clone_repo()
except Exception:
Logger.print_error(f"Downloading {client_config.get('display_name')} failed!")
Logger.print_error(f"Downloading {client_config.display_name} failed!")
raise
def update_client_config(client: ClientData) -> None:
client_config: ClientConfigData = client.get("client_config")
def update_client_config(client: BaseWebClient) -> None:
client_config: BaseWebClientConfig = client.client_config
Logger.print_status(f"Updating {client_config.get('display_name')} ...")
Logger.print_status(f"Updating {client_config.display_name} ...")
if not client_config.config_dir.exists():
Logger.print_info(
f"Unable to update {client_config.display_name}. Directory does not exist! Skipping ..."
)
return
cm = ConfigManager(cfg_file=KIAUH_CFG)
if cm.get_value("kiauh", "backup_before_update"):
backup_client_config_data(client)
repo_manager = RepoManager(
repo=client_config.get("url"),
repo=client_config.repo_url,
branch="master",
target_dir=str(client_config.get("dir")),
target_dir=str(client_config.config_dir),
)
repo_manager.pull_repo()
Logger.print_ok(f"Successfully updated {client_config.get('display_name')}.")
Logger.print_warn("Remember to restart Klipper to reload the configurations!")
Logger.print_ok(f"Successfully updated {client_config.display_name}.")
Logger.print_info("Restart Klipper to reload the configuration!")
def create_client_config_symlink(
client_config: ClientConfigData, klipper_instances: List[Klipper] = None
client_config: BaseWebClientConfig, klipper_instances: List[Klipper] = None
) -> None:
if klipper_instances is None:
kl_im = InstanceManager(Klipper)
klipper_instances = kl_im.instances
Logger.print_status(f"Create symlink for {client_config.get('cfg_filename')} ...")
source = Path(client_config.get("dir"), client_config.get("cfg_filename"))
Logger.print_status(f"Create symlink for {client_config.config_filename} ...")
source = Path(client_config.config_dir, client_config.config_filename)
for instance in klipper_instances:
target = instance.cfg_dir
Logger.print_status(f"Linking {source} to {target}")

View File

@@ -10,7 +10,7 @@
import textwrap
from typing import List
from components.webui_client import ClientData
from components.webui_client.base_data import BaseWebClient
from core.menus.base_menu import print_back_footer
from utils.constants import RESET_FORMAT, COLOR_YELLOW, COLOR_CYAN
@@ -84,9 +84,9 @@ def print_client_port_select_dialog(name: str, port: str, ports_in_use: List[str
print(dialog, end="")
def print_install_client_config_dialog(client: ClientData):
name = client.get("display_name")
url = client.get("client_config").get("url").replace(".git", "")
def print_install_client_config_dialog(client: BaseWebClient):
name = client.display_name
url = client.client_config.repo_url.replace(".git", "")
line1 = f"have {name} fully functional and working."
line2 = f"The recommended macros for {name} can be seen here:"
dialog = textwrap.dedent(

View File

@@ -13,7 +13,10 @@ from typing import List
from components.klipper.klipper import Klipper
from components.moonraker.moonraker import Moonraker
from components.webui_client import ClientData
from components.webui_client.base_data import (
BaseWebClient,
WebClientType,
)
from components.webui_client.client_config.client_config_remove import (
run_client_config_removal,
)
@@ -29,7 +32,7 @@ from utils.logger import Logger
def run_client_removal(
client: ClientData,
client: BaseWebClient,
rm_client: bool,
rm_client_config: bool,
backup_ms_config_json: bool,
@@ -39,11 +42,11 @@ def run_client_removal(
kl_im = InstanceManager(Klipper)
kl_instances: List[Klipper] = kl_im.instances
if backup_ms_config_json and client.get("name") == "mainsail":
if backup_ms_config_json and client.client == WebClientType.MAINSAIL:
backup_mainsail_config_json()
if rm_client:
client_name = client.get("name")
client_name = client.name
remove_client_dir(client)
remove_nginx_config(client_name)
remove_nginx_logs(client_name)
@@ -53,16 +56,16 @@ def run_client_removal(
if rm_client_config:
run_client_config_removal(
client.get("client_config"),
client.client_config,
kl_instances,
mr_instances,
)
def remove_client_dir(client: ClientData) -> None:
Logger.print_status(f"Removing {client.get('display_name')} ...")
client_dir = client.get("dir")
if not client.get("dir").exists():
def remove_client_dir(client: BaseWebClient) -> None:
Logger.print_status(f"Removing {client.display_name} ...")
client_dir = client.client_dir
if not client.client_dir.exists():
Logger.print_info(f"'{client_dir}' does not exist. Skipping ...")
return

View File

@@ -11,12 +11,13 @@ from pathlib import Path
from typing import List
from components.klipper.klipper import Klipper
from components.webui_client import (
ClientName,
ClientData,
)
from components.moonraker.moonraker import Moonraker
from components.webui_client.base_data import (
WebClientType,
BaseWebClient,
BaseWebClientConfig,
)
from components.webui_client.client_config.client_config_setup import (
install_client_config,
)
@@ -30,7 +31,6 @@ from components.webui_client.client_utils import (
restore_mainsail_config_json,
enable_mainsail_remotemode,
symlink_webui_nginx_log,
load_client_data,
config_for_other_client_exist,
)
from core.config_manager.config_manager import ConfigManager
@@ -60,17 +60,13 @@ from utils.system_utils import (
)
def install_client(client_name: ClientName) -> None:
client: ClientData = load_client_data(client_name)
d_name = client.get("display_name")
def install_client(client: BaseWebClient) -> None:
if client is None:
Logger.print_error("Missing parameter client_name!")
return
raise ValueError("Missing parameter client_data!")
if client.get("dir").exists():
if client.client_dir.exists():
Logger.print_info(
f"{client.get('display_name')} seems to be already installed! Skipped ..."
f"{client.display_name} seems to be already installed! Skipped ..."
)
return
@@ -81,31 +77,35 @@ def install_client(client_name: ClientName) -> None:
if not mr_instances:
print_moonraker_not_found_dialog()
if not get_confirm(
f"Continue {d_name} installation?",
f"Continue {client.display_name} installation?",
allow_go_back=True,
):
return
# if moonraker is not installed or multiple instances
# are installed we enable mainsails remote mode
if client.get("remote_mode") and not mr_instances or len(mr_instances) > 1:
if (
client.client == WebClientType.MAINSAIL
and not mr_instances
or len(mr_instances) > 1
):
enable_remotemode = True
kl_im = InstanceManager(Klipper)
kl_instances = kl_im.instances
install_client_cfg = False
client_config = client.get("client_config")
client_config: BaseWebClientConfig = client.client_config
if (
kl_instances
and not client_config.get("dir").exists()
and not config_for_other_client_exist(client_to_ignore=client.get("name"))
and not client_config.config_dir.exists()
and not config_for_other_client_exist(client_to_ignore=client.client)
):
print_install_client_config_dialog(client)
question = f"Download the recommended {client_config.get('display_name')}?"
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.get("name"), "port")
default_port = cm.get_value(client.name, "port")
client_port = default_port if default_port and default_port.isdigit() else "80"
ports_in_use = read_ports_from_nginx_configs()
@@ -113,10 +113,10 @@ def install_client(client_name: ClientName) -> None:
valid_port = is_valid_port(client_port, ports_in_use)
while not valid_port:
next_port = get_next_free_port(ports_in_use)
print_client_port_select_dialog(d_name, next_port, ports_in_use)
print_client_port_select_dialog(client.display_name, next_port, ports_in_use)
client_port = str(
get_number_input(
f"Configure {d_name} for port",
f"Configure {client.display_name} for port",
min_count=int(next_port),
default=next_port,
)
@@ -127,22 +127,22 @@ def install_client(client_name: ClientName) -> None:
try:
download_client(client)
if enable_remotemode and client.get("name") == "mainsail":
if enable_remotemode and client.client == WebClientType.MAINSAIL:
enable_mainsail_remotemode()
if mr_instances:
add_config_section(
section=f"update_manager {client.get('name')}",
section=f"update_manager {client.name}",
instances=mr_instances,
options=[
("type", "web"),
("channel", "stable"),
("repo", client.get("mr_conf_repo")),
("path", client.get("mr_conf_path")),
("repo", str(client.repo_path)),
("path", str(client.client_dir)),
],
)
mr_im.restart_all_instance()
if install_client_cfg and kl_instances:
install_client_config(client.get("name"))
install_client_config(client)
copy_upstream_nginx_cfg()
copy_common_vars_nginx_cfg()
@@ -152,24 +152,24 @@ def install_client(client_name: ClientName) -> None:
control_systemd_service("nginx", "restart")
except Exception as e:
Logger.print_error(f"{d_name} installation failed!\n{e}")
Logger.print_error(f"{client.display_name} installation failed!\n{e}")
return
log = f"Open {d_name} now on: http://{get_ipv4_addr()}:{client_port}"
Logger.print_ok(f"{d_name} installation complete!", start="\n")
log = f"Open {client.display_name} now on: http://{get_ipv4_addr()}:{client_port}"
Logger.print_ok(f"{client.display_name} installation complete!", start="\n")
Logger.print_ok(log, prefix=False, end="\n\n")
def download_client(client: ClientData) -> None:
zipfile = f"{client.get('name').lower()}.zip"
def download_client(client: BaseWebClient) -> None:
zipfile = f"{client.name.lower()}.zip"
target = Path().home().joinpath(zipfile)
try:
Logger.print_status(f"Downloading {zipfile} ...")
download_file(client.get("url"), target, True)
download_file(client.stable_url, target, True)
Logger.print_ok("Download complete!")
Logger.print_status(f"Extracting {zipfile} ...")
unzip(target, client.get("dir"))
unzip(target, client.client_dir)
target.unlink(missing_ok=True)
Logger.print_ok("OK!")
@@ -178,29 +178,35 @@ def download_client(client: ClientData) -> None:
raise
def update_client(client: ClientData) -> None:
Logger.print_status(f"Updating {client.get('display_name')} ...")
if client.get("name") == "mainsail":
def update_client(client: BaseWebClient) -> None:
Logger.print_status(f"Updating {client.display_name} ...")
if not client.client_dir.exists():
Logger.print_info(
f"Unable to update {client.display_name}. Directory does not exist! Skipping ..."
)
return
if client.client == WebClientType.MAINSAIL:
backup_mainsail_config_json(is_temp=True)
download_client(client)
if client.get("name") == "mainsail":
if client.client == WebClientType.MAINSAIL:
restore_mainsail_config_json()
def create_client_nginx_cfg(client: ClientData, port: int) -> None:
d_name = client.get("display_name")
root_dir = client.get("dir")
source = NGINX_SITES_AVAILABLE.joinpath(client.get("name"))
target = NGINX_SITES_ENABLED.joinpath(client.get("name"))
def create_client_nginx_cfg(client: BaseWebClient, port: int) -> None:
display_name = client.display_name
root_dir = client.client_dir
source = NGINX_SITES_AVAILABLE.joinpath(client.name)
target = NGINX_SITES_ENABLED.joinpath(client.name)
try:
Logger.print_status(f"Creating NGINX config for {d_name} ...")
Logger.print_status(f"Creating NGINX config for {display_name} ...")
remove_file(Path("/etc/nginx/sites-enabled/default"), True)
create_nginx_cfg(client.get("name"), port, root_dir)
create_nginx_cfg(client.name, port, root_dir)
create_symlink(source, target, True)
set_nginx_permissions()
Logger.print_ok(f"NGINX config for {d_name} successfully created.")
Logger.print_ok(f"NGINX config for {display_name} successfully created.")
except Exception:
Logger.print_error(f"Creating NGINX config for {d_name} failed!")
Logger.print_error(f"Creating NGINX config for {display_name} failed!")
raise

View File

@@ -9,117 +9,43 @@
import json
import shutil
from json import JSONDecodeError
from pathlib import Path
from typing import List, Optional, Dict, Literal, Union, get_args
from typing import List, Dict, Literal, Union, get_args
import urllib.request
from components.klipper.klipper import Klipper
from components.webui_client import (
MAINSAIL_CONFIG_JSON,
MAINSAIL_DIR,
MAINSAIL_BACKUP_DIR,
FLUIDD_PRE_RLS_URL,
FLUIDD_BACKUP_DIR,
FLUIDD_URL,
FLUIDD_DIR,
ClientData,
FLUIDD_CONFIG_REPO_URL,
FLUIDD_CONFIG_DIR,
ClientConfigData,
MAINSAIL_PRE_RLS_URL,
MAINSAIL_URL,
MAINSAIL_CONFIG_REPO_URL,
MAINSAIL_CONFIG_DIR,
ClientName,
MAINSAIL_TAGS_URL,
FLUIDD_TAGS_URL,
FLUIDD_CONFIG_BACKUP_DIR,
MAINSAIL_CONFIG_BACKUP_DIR,
from components.webui_client.base_data import (
WebClientType,
BaseWebClient,
BaseWebClientConfig,
)
from components.webui_client.mainsail_data import MainsailData
from core.backup_manager.backup_manager import BackupManager
from core.repo_manager.repo_manager import RepoManager
from utils import NGINX_SITES_AVAILABLE, NGINX_CONFD
from utils.common import get_install_status_webui
from utils.constants import COLOR_CYAN, RESET_FORMAT, COLOR_YELLOW
from utils.git_utils import get_latest_tag
from utils.logger import Logger
def load_client_data(client_name: ClientName) -> Optional[ClientData]:
client_data = None
if client_name == "mainsail":
client_config_data = ClientConfigData(
name="mainsail-config",
display_name="Mainsail-Config",
cfg_filename="mainsail.cfg",
dir=MAINSAIL_CONFIG_DIR,
backup_dir=MAINSAIL_CONFIG_BACKUP_DIR,
url=MAINSAIL_CONFIG_REPO_URL,
printer_cfg_section="include mainsail.cfg",
mr_conf_path="~/mainsail-config",
mr_conf_origin=MAINSAIL_CONFIG_REPO_URL,
)
client_data = ClientData(
name=client_name,
display_name=client_name.capitalize(),
dir=MAINSAIL_DIR,
backup_dir=MAINSAIL_BACKUP_DIR,
url=MAINSAIL_URL,
pre_release_url=MAINSAIL_PRE_RLS_URL,
tags_url=MAINSAIL_TAGS_URL,
remote_mode=True,
mr_conf_repo="mainsail-crew/mainsail",
mr_conf_path="~/mainsail",
client_config=client_config_data,
)
elif client_name == "fluidd":
client_config_data = ClientConfigData(
name="fluidd-config",
display_name="Fluidd-Config",
cfg_filename="fluidd.cfg",
dir=FLUIDD_CONFIG_DIR,
backup_dir=FLUIDD_CONFIG_BACKUP_DIR,
url=FLUIDD_CONFIG_REPO_URL,
printer_cfg_section="include fluidd.cfg",
mr_conf_path="~/fluidd-config",
mr_conf_origin=FLUIDD_CONFIG_REPO_URL,
)
client_data = ClientData(
name=client_name,
display_name=client_name.capitalize(),
dir=FLUIDD_DIR,
backup_dir=FLUIDD_BACKUP_DIR,
url=FLUIDD_URL,
pre_release_url=FLUIDD_PRE_RLS_URL,
tags_url=FLUIDD_TAGS_URL,
remote_mode=False,
mr_conf_repo="fluidd-core/fluidd",
mr_conf_path="~/fluidd",
client_config=client_config_data,
)
return client_data
def get_client_status(client: ClientData) -> str:
def get_client_status(client: BaseWebClient) -> str:
return get_install_status_webui(
client.get("dir"),
NGINX_SITES_AVAILABLE.joinpath(client.get("name")),
client.client_dir,
NGINX_SITES_AVAILABLE.joinpath(client.name),
NGINX_CONFD.joinpath("upstreams.conf"),
NGINX_CONFD.joinpath("common_vars.conf"),
)
def get_client_config_status(
client: ClientData,
client: BaseWebClient,
) -> Dict[
Literal["repo", "local", "remote"],
Union[str, int],
]:
client_config = client.get("client_config")
client_config = client_config.get("dir")
client_config = client.client_config
client_config = client_config.config_dir
return {
"repo": RepoManager.get_repo_name(client_config),
@@ -128,44 +54,47 @@ def get_client_config_status(
}
def get_current_client_config(clients: List[ClientData]) -> str:
def get_current_client_config(clients: List[BaseWebClient]) -> str:
installed = []
for client in clients:
client_config = client.get("client_config")
if client_config.get("dir").exists():
client_config = client.client_config
if client_config.config_dir.exists():
installed.append(client)
if len(installed) > 1:
return f"{COLOR_YELLOW}Conflict!{RESET_FORMAT}"
elif len(installed) == 1:
cfg = installed[0].get("client_config")
return f"{COLOR_CYAN}{cfg.get('display_name')}{RESET_FORMAT}"
cfg = installed[0].client_config
return f"{COLOR_CYAN}{cfg.display_name}{RESET_FORMAT}"
return f"{COLOR_CYAN}-{RESET_FORMAT}"
def backup_mainsail_config_json(is_temp=False) -> None:
Logger.print_status(f"Backup '{MAINSAIL_CONFIG_JSON}' ...")
c_json = MainsailData().client_dir.joinpath("config.json")
Logger.print_status(f"Backup '{c_json}' ...")
bm = BackupManager()
if is_temp:
fn = Path.home().joinpath("config.json.kiauh.bak")
bm.backup_file(MAINSAIL_CONFIG_JSON, custom_filename=fn)
bm.backup_file(c_json, custom_filename=fn)
else:
bm.backup_file(MAINSAIL_CONFIG_JSON)
bm.backup_file(c_json)
def restore_mainsail_config_json() -> None:
try:
Logger.print_status(f"Restore '{MAINSAIL_CONFIG_JSON}' ...")
c_json = MainsailData().client_dir.joinpath("config.json")
Logger.print_status(f"Restore '{c_json}' ...")
source = Path.home().joinpath("config.json.kiauh.bak")
shutil.copy(source, MAINSAIL_CONFIG_JSON)
shutil.copy(source, c_json)
except OSError:
Logger.print_info("Unable to restore config.json. Skipped ...")
def enable_mainsail_remotemode() -> None:
Logger.print_status("Enable Mainsails remote mode ...")
with open(MAINSAIL_CONFIG_JSON, "r") as f:
c_json = MainsailData().client_dir.joinpath("config.json")
with open(c_json, "r") as f:
config_data = json.load(f)
if config_data["instancesDB"] == "browser":
@@ -175,7 +104,7 @@ def enable_mainsail_remotemode() -> None:
Logger.print_status("Setting instance storage location to 'browser' ...")
config_data["instancesDB"] = "browser"
with open(MAINSAIL_CONFIG_JSON, "w") as f:
with open(c_json, "w") as f:
json.dump(config_data, f, indent=4)
Logger.print_ok("Mainsails remote mode enabled!")
@@ -195,8 +124,8 @@ def symlink_webui_nginx_log(klipper_instances: List[Klipper]) -> None:
desti_error.symlink_to(error_log)
def get_local_client_version(client: ClientData) -> str:
relinfo_file = client.get("dir").joinpath("release_info.json")
def get_local_client_version(client: BaseWebClient) -> str:
relinfo_file = client.client_dir.joinpath("release_info.json")
if not relinfo_file.is_file():
return "-"
@@ -204,19 +133,19 @@ def get_local_client_version(client: ClientData) -> str:
return json.load(f)["version"]
def get_remote_client_version(client: ClientData) -> str:
def get_remote_client_version(client: BaseWebClient) -> str:
try:
with urllib.request.urlopen(client.get("tags_url")) as response:
data = json.loads(response.read())
return data[0]["name"]
except (JSONDecodeError, TypeError):
if (tag := get_latest_tag(client.repo_path)) != "":
return tag
return "ERROR"
except Exception:
return "ERROR"
def backup_client_data(client: ClientData) -> None:
name = client.get("name")
src = client.get("dir")
dest = client.get("backup_dir")
def backup_client_data(client: BaseWebClient) -> None:
name = client.name
src = client.client_dir
dest = client.backup_dir
with open(src.joinpath(".version"), "r") as v:
version = v.readlines()[0]
@@ -224,43 +153,42 @@ def backup_client_data(client: ClientData) -> None:
bm = BackupManager()
bm.backup_directory(f"{name}-{version}", src, dest)
if name == "mainsail":
bm.backup_file(MAINSAIL_CONFIG_JSON, dest)
c_json = MainsailData().client_dir.joinpath("config.json")
bm.backup_file(c_json, dest)
bm.backup_file(NGINX_SITES_AVAILABLE.joinpath(name), dest)
def backup_client_config_data(client: ClientData) -> None:
client_config = client.get("client_config")
name = client_config.get("name")
source = client_config.get("dir")
target = client_config.get("backup_dir")
def backup_client_config_data(client: BaseWebClient) -> None:
client_config = client.client_config
name = client_config.name
source = client_config.config_dir
target = client_config.backup_dir
bm = BackupManager()
bm.backup_directory(name, source, target)
def get_existing_clients() -> List[ClientData]:
clients = list(get_args(ClientName))
installed_clients: List[ClientData] = []
for c in clients:
c_data: ClientData = load_client_data(c)
if c_data.get("dir").exists():
installed_clients.append(c_data)
def get_existing_clients() -> List[BaseWebClient]:
clients = list(get_args(WebClientType))
installed_clients: List[BaseWebClient] = []
for client in clients:
if client.client_dir.exists():
installed_clients.append(client)
return installed_clients
def get_existing_client_config() -> List[ClientData]:
clients = list(get_args(ClientName))
installed_client_configs: List[ClientData] = []
for c in clients:
c_data: ClientData = load_client_data(c)
c_config_data: ClientConfigData = c_data.get("client_config")
if c_config_data.get("dir").exists():
installed_client_configs.append(c_data)
def get_existing_client_config() -> List[BaseWebClient]:
clients = list(get_args(WebClientType))
installed_client_configs: List[BaseWebClient] = []
for client in clients:
c_config_data: BaseWebClientConfig = client.client_config
if c_config_data.config_dir.exists():
installed_client_configs.append(client)
return installed_client_configs
def config_for_other_client_exist(client_to_ignore: ClientName) -> bool:
def config_for_other_client_exist(client_to_ignore: WebClientType) -> bool:
"""
Check if any other client configs are present on the system.
It is usually not harmful, but chances are they can conflict each other.
@@ -269,7 +197,7 @@ def config_for_other_client_exist(client_to_ignore: ClientName) -> bool:
:return: True, if other client configs were found, else False
"""
clients = set([c["name"] for c in get_existing_client_config()])
clients = clients - {client_to_ignore}
clients = set([c.name for c in get_existing_client_config()])
clients = clients - {client_to_ignore.value}
return True if len(clients) > 0 else False

View File

@@ -0,0 +1,65 @@
# ======================================================================= #
# 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 __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
from components.webui_client.base_data import (
BaseWebClientConfig,
WebClientConfigType,
WebClientType,
BaseWebClient,
)
from core.backup_manager import BACKUP_ROOT_DIR
from utils.git_utils import get_latest_unstable_tag
@dataclass(frozen=True)
class FluiddConfigWeb(BaseWebClientConfig):
client_config: WebClientConfigType = WebClientConfigType.FLUIDD
name: str = client_config.value
display_name: str = name.title()
config_dir: Path = Path.home().joinpath("fluidd-config")
config_filename: str = "fluidd.cfg"
config_section: str = f"include {config_filename}"
backup_dir: Path = BACKUP_ROOT_DIR.joinpath("fluidd-config-backups")
repo_url: str = "https://github.com/fluidd-core/fluidd-config.git"
@dataclass(frozen=True)
class FluiddData(BaseWebClient):
BASE_DL_URL = "https://github.com/fluidd-core/fluidd/releases"
client: WebClientType = WebClientType.FLUIDD
name: str = client.value
display_name: str = name.capitalize()
client_dir: Path = Path.home().joinpath("fluidd")
backup_dir: Path = BACKUP_ROOT_DIR.joinpath("fluidd-backups")
repo_path: str = "fluidd-core/fluidd"
@property
def stable_url(self) -> str:
return f"{self.BASE_DL_URL}/latest/download/fluidd.zip"
@property
def unstable_url(self) -> str:
try:
unstable_tag = get_latest_unstable_tag(self.repo_path)
if unstable_tag != "":
return f"{self.BASE_DL_URL}/download/{unstable_tag}/fluidd.zip"
else:
raise Exception
except Exception:
return self.stable_url
@property
def client_config(self) -> BaseWebClientConfig:
return FluiddConfigWeb()

View File

@@ -0,0 +1,65 @@
# ======================================================================= #
# 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 __future__ import annotations
from dataclasses import dataclass
from pathlib import Path
from components.webui_client.base_data import (
BaseWebClientConfig,
WebClientConfigType,
WebClientType,
BaseWebClient,
)
from core.backup_manager import BACKUP_ROOT_DIR
from utils.git_utils import get_latest_unstable_tag
@dataclass(frozen=True)
class MainsailConfigWeb(BaseWebClientConfig):
client_config: WebClientConfigType = WebClientConfigType.MAINSAIL
name: str = client_config.value
display_name: str = name.title()
config_dir: Path = Path.home().joinpath("mainsail-config")
config_filename: str = "mainsail.cfg"
config_section: str = f"include {config_filename}"
backup_dir: Path = BACKUP_ROOT_DIR.joinpath("mainsail-config-backups")
repo_url: str = "https://github.com/mainsail-crew/mainsail-config.git"
@dataclass(frozen=True)
class MainsailData(BaseWebClient):
BASE_DL_URL: str = "https://github.com/mainsail-crew/mainsail/releases"
client: WebClientType = WebClientType.MAINSAIL
name: str = WebClientType.MAINSAIL.value
display_name: str = name.capitalize()
client_dir: Path = Path.home().joinpath("mainsail")
backup_dir: Path = BACKUP_ROOT_DIR.joinpath("mainsail-backups")
repo_path: str = "mainsail-crew/mainsail"
@property
def stable_url(self) -> str:
return f"{self.BASE_DL_URL}/latest/download/mainsail.zip"
@property
def unstable_url(self) -> str:
try:
unstable_tag = get_latest_unstable_tag(self.repo_path)
if unstable_tag != "":
return f"{self.BASE_DL_URL}/download/{unstable_tag}/mainsail.zip"
else:
raise Exception
except Exception:
return self.stable_url
@property
def client_config(self) -> BaseWebClientConfig:
return MainsailConfigWeb()

View File

@@ -10,14 +10,15 @@
import textwrap
from typing import Callable, Dict
from components.webui_client import client_remove, ClientData
from components.webui_client import client_remove
from components.webui_client.base_data import BaseWebClient, WebClientType
from core.menus.base_menu import BaseMenu
from utils.constants import RESET_FORMAT, COLOR_RED, COLOR_CYAN
# noinspection PyUnusedLocal
class ClientRemoveMenu(BaseMenu):
def __init__(self, previous_menu: BaseMenu, client: ClientData):
def __init__(self, previous_menu: BaseMenu, client: BaseWebClient):
super().__init__()
self.previous_menu = previous_menu
self.options = self.get_options(client)
@@ -27,22 +28,22 @@ class ClientRemoveMenu(BaseMenu):
self.rm_client_config = False
self.backup_mainsail_config_json = False
def get_options(self, client: ClientData) -> Dict[str, Callable]:
def get_options(self, client: BaseWebClient) -> Dict[str, Callable]:
options = {
"0": self.toggle_all,
"1": self.toggle_rm_client,
"2": self.toggle_rm_client_config,
"c": self.run_removal_process,
}
if client.get("name") == "mainsail":
if client.client == WebClientType.MAINSAIL:
options["3"] = self.toggle_backup_mainsail_config_json
return options
def print_menu(self) -> None:
client_name = self.client.get("display_name")
client_config = self.client.get("client_config")
client_config_name = client_config.get("display_name")
client_name = self.client.display_name
client_config = self.client.client_config
client_config_name = client_config.display_name
header = f" [ Remove {client_name} ] "
color = COLOR_RED
@@ -66,7 +67,7 @@ class ClientRemoveMenu(BaseMenu):
"""
)[1:]
if self.client.get("name") == "mainsail":
if self.client.client == WebClientType.MAINSAIL:
o3 = checked if self.backup_mainsail_config_json else unchecked
menu += textwrap.dedent(
f"""

View File

@@ -16,9 +16,10 @@ from components.moonraker.moonraker_utils import (
)
from components.webui_client.client_utils import (
backup_client_data,
load_client_data,
backup_client_config_data,
)
from components.webui_client.fluidd_data import FluiddData
from components.webui_client.mainsail_data import MainsailData
from core.menus.base_menu import BaseMenu
from utils.common import backup_printer_config_dir
from utils.constants import COLOR_CYAN, RESET_FORMAT, COLOR_YELLOW
@@ -81,16 +82,16 @@ class BackupMenu(BaseMenu):
backup_moonraker_db_dir()
def backup_mainsail(self, **kwargs):
backup_client_data(load_client_data("mainsail"))
backup_client_data(MainsailData().get())
def backup_fluidd(self, **kwargs):
backup_client_data(load_client_data("fluidd"))
backup_client_data(FluiddData().get())
def backup_mainsail_config(self, **kwargs):
backup_client_config_data(load_client_data("mainsail"))
backup_client_config_data(MainsailData().get())
def backup_fluidd_config(self, **kwargs):
backup_client_config_data(load_client_data("fluidd"))
backup_client_config_data(FluiddData().get())
def backup_klipperscreen(self, **kwargs):
pass

View File

@@ -13,6 +13,8 @@ from components.klipper import klipper_setup
from components.moonraker import moonraker_setup
from components.webui_client import client_setup
from components.webui_client.client_config import client_config_setup
from components.webui_client.fluidd_data import FluiddData
from components.webui_client.mainsail_data import MainsailData
from core.menus.base_menu import BaseMenu
from utils.constants import COLOR_GREEN, RESET_FORMAT
@@ -69,13 +71,13 @@ class InstallMenu(BaseMenu):
moonraker_setup.install_moonraker()
def install_mainsail(self, **kwargs):
client_setup.install_client(client_name="mainsail")
client_setup.install_client(MainsailData())
def install_mainsail_config(self, **kwargs):
client_config_setup.install_client_config(client_name="mainsail")
client_config_setup.install_client_config(MainsailData())
def install_fluidd(self, **kwargs):
client_setup.install_client(client_name="fluidd")
client_setup.install_client(FluiddData())
def install_fluidd_config(self, **kwargs):
client_config_setup.install_client_config(client_name="fluidd")
client_config_setup.install_client_config(FluiddData())

View File

@@ -14,9 +14,10 @@ from components.log_uploads.menus.log_upload_menu import LogUploadMenu
from components.moonraker.moonraker_utils import get_moonraker_status
from components.webui_client.client_utils import (
get_client_status,
load_client_data,
get_current_client_config,
)
from components.webui_client.fluidd_data import FluiddData
from components.webui_client.mainsail_data import MainsailData
from core.menus import FooterType
from core.menus.advanced_menu import AdvancedMenu
from core.menus.backup_menu import BackupMenu
@@ -92,15 +93,11 @@ class MainMenu(BaseMenu):
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
mainsail_client_data = load_client_data("mainsail")
self.ms_status = get_client_status(mainsail_client_data)
self.ms_status = get_client_status(MainsailData())
# fluidd
fluidd_client_data = load_client_data("fluidd")
self.fl_status = get_client_status(fluidd_client_data)
self.fl_status = get_client_status(FluiddData())
# client-config
self.cc_status = get_current_client_config(
[mainsail_client_data, fluidd_client_data]
)
self.cc_status = get_current_client_config([MainsailData(), FluiddData()])
def format_status_by_code(self, code: int, status: str, count: str) -> str:
if code == 1:

View File

@@ -13,7 +13,8 @@ from components.klipper.menus.klipper_remove_menu import KlipperRemoveMenu
from components.moonraker.menus.moonraker_remove_menu import (
MoonrakerRemoveMenu,
)
from components.webui_client.client_utils import load_client_data
from components.webui_client.fluidd_data import FluiddData
from components.webui_client.mainsail_data import MainsailData
from components.webui_client.menus.client_remove_menu import ClientRemoveMenu
from core.menus.base_menu import BaseMenu
from utils.constants import COLOR_RED, RESET_FORMAT
@@ -76,7 +77,7 @@ class RemoveMenu(BaseMenu):
MoonrakerRemoveMenu(previous_menu=self).run()
def remove_mainsail(self, **kwargs):
ClientRemoveMenu(previous_menu=self, client=load_client_data("mainsail")).run()
ClientRemoveMenu(previous_menu=self, client=MainsailData()).run()
def remove_fluidd(self, **kwargs):
ClientRemoveMenu(previous_menu=self, client=load_client_data("fluidd")).run()
ClientRemoveMenu(previous_menu=self, client=FluiddData()).run()

View File

@@ -22,9 +22,10 @@ from components.webui_client.client_setup import update_client
from components.webui_client.client_utils import (
get_local_client_version,
get_remote_client_version,
load_client_data,
get_client_config_status,
)
from components.webui_client.fluidd_data import FluiddData
from components.webui_client.mainsail_data import MainsailData
from core.menus.base_menu import BaseMenu
from utils.constants import (
COLOR_GREEN,
@@ -69,6 +70,9 @@ class UpdateMenu(BaseMenu):
self.fc_local = f"{COLOR_WHITE}{RESET_FORMAT}"
self.fc_remote = f"{COLOR_WHITE}{RESET_FORMAT}"
self.mainsail_cient = MainsailData()
self.fluidd_client = FluiddData()
def print_menu(self):
self.fetch_update_status()
@@ -114,16 +118,16 @@ class UpdateMenu(BaseMenu):
update_moonraker()
def update_mainsail(self, **kwargs):
update_client(load_client_data("mainsail"))
update_client(self.mainsail_cient)
def update_mainsail_config(self, **kwargs):
update_client_config(load_client_data("mainsail"))
update_client_config(self.mainsail_cient)
def update_fluidd(self, **kwargs):
update_client(load_client_data("fluidd"))
update_client(self.fluidd_client)
def update_fluidd_config(self, **kwargs):
update_client_config(load_client_data("fluidd"))
update_client_config(self.fluidd_client)
def update_klipperscreen(self, **kwargs): ...
@@ -153,25 +157,23 @@ class UpdateMenu(BaseMenu):
self.mr_local = f"{COLOR_YELLOW}{self.mr_local}{RESET_FORMAT}"
self.mr_remote = f"{COLOR_GREEN}{self.mr_remote}{RESET_FORMAT}"
# mainsail
mainsail_client_data = load_client_data("mainsail")
self.ms_local = get_local_client_version(mainsail_client_data)
self.ms_remote = get_remote_client_version(mainsail_client_data)
self.ms_local = get_local_client_version(self.mainsail_cient)
self.ms_remote = get_remote_client_version(self.mainsail_cient)
if self.ms_local == self.ms_remote:
self.ms_local = f"{COLOR_GREEN}{self.ms_local}{RESET_FORMAT}"
else:
self.ms_local = f"{COLOR_YELLOW}{self.ms_local}{RESET_FORMAT}"
self.ms_remote = f"{COLOR_GREEN if self.ms_remote != 'ERROR' else COLOR_RED}{self.ms_remote}{RESET_FORMAT}"
# fluidd
fluidd_client_data = load_client_data("fluidd")
self.fl_local = get_local_client_version(fluidd_client_data)
self.fl_remote = get_remote_client_version(fluidd_client_data)
self.fl_local = get_local_client_version(self.fluidd_client)
self.fl_remote = get_remote_client_version(self.fluidd_client)
if self.fl_local == self.fl_remote:
self.fl_local = f"{COLOR_GREEN}{self.fl_local}{RESET_FORMAT}"
else:
self.fl_local = f"{COLOR_YELLOW}{self.fl_local}{RESET_FORMAT}"
self.fl_remote = f"{COLOR_GREEN if self.fl_remote != 'ERROR' else COLOR_RED}{self.fl_remote}{RESET_FORMAT}"
# mainsail-config
mc_status = get_client_config_status(load_client_data("mainsail"))
mc_status = get_client_config_status(self.mainsail_cient)
self.mc_local = mc_status.get("local")
self.mc_remote = mc_status.get("remote")
if self.mc_local == self.mc_remote:
@@ -180,7 +182,7 @@ class UpdateMenu(BaseMenu):
self.mc_local = f"{COLOR_YELLOW}{self.mc_local}{RESET_FORMAT}"
self.mc_remote = f"{COLOR_GREEN}{self.mc_remote}{RESET_FORMAT}"
# fluidd-config
fc_status = get_client_config_status(load_client_data("fluidd"))
fc_status = get_client_config_status(self.fluidd_client)
self.fc_local = fc_status.get("local")
self.fc_remote = fc_status.get("remote")
if self.fc_local == self.mc_remote:

57
kiauh/utils/git_utils.py Normal file
View File

@@ -0,0 +1,57 @@
import json
import urllib.request
from http.client import HTTPResponse
from json import JSONDecodeError
from typing import List
from utils.logger import Logger
def get_tags(repo_path: str) -> List[str]:
try:
url = f"https://api.github.com/repos/{repo_path}/tags"
with urllib.request.urlopen(url) as r:
response: HTTPResponse = r
if response.getcode() != 200:
Logger.print_error(
f"Error retrieving tags: HTTP status code {response.getcode()}"
)
return []
data = json.loads(response.read())
return [item["name"] for item in data]
except (JSONDecodeError, TypeError) as e:
Logger.print_error(f"Error while processing the response: {e}")
raise
def get_latest_tag(repo_path: str) -> str:
"""
Gets the latest stable tag of a GitHub repostiory
:param repo_path: path of the GitHub repository - e.g. `<owner>/<name>`
:return: tag or empty string
"""
try:
if len(latest_tag := get_tags(repo_path)) > 0:
return latest_tag[0]
else:
return ""
except Exception:
Logger.print_error("Error while getting the latest tag")
raise
def get_latest_unstable_tag(repo_path: str) -> str:
"""
Gets the latest unstable (alpha, beta, rc) tag of a GitHub repository
:param repo_path: path of the GitHub repository - e.g. `<owner>/<name>`
:return: tag or empty string
"""
try:
if len(unstable_tags := [t for t in get_tags(repo_path) if "-" in t]) > 0:
return unstable_tags[0]
else:
return ""
except Exception:
Logger.print_error("Error while getting the latest unstable tag")
raise