Files
kiauh/kiauh/utils/common.py
dw-0 a54514c400 fix: fix switching of repositories (#519)
* fix: fix repo switching

Extend the functionality of repo switching by creating a backup before the switch. Also implement a rollback mechanic in case of an error.

Signed-off-by: Dominik Willner <th33xitus@gmail.com>

* refactor: fail when installing requirements fails

Signed-off-by: Dominik Willner <th33xitus@gmail.com>

* refactor: display owner and repo in main menu on separate lines

long owner and repo names would case the menu to be too wide

Signed-off-by: Dominik Willner <th33xitus@gmail.com>

---------

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-09-05 20:31:38 +02:00

180 lines
5.3 KiB
Python

# ======================================================================= #
# 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
import re
from datetime import datetime
from pathlib import Path
from typing import Dict, List, Literal, Optional, Set
from components.klipper.klipper import Klipper
from core.constants import (
COLOR_CYAN,
GLOBAL_DEPS,
PRINTER_CFG_BACKUP_DIR,
RESET_FORMAT,
)
from core.logger import DialogType, Logger
from core.types import ComponentStatus, StatusCode
from utils.git_utils import (
get_local_commit,
get_local_tags,
get_remote_commit,
get_repo_name,
)
from utils.instance_utils import get_instances
from utils.sys_utils import (
check_package_install,
install_system_packages,
update_system_package_lists,
)
def get_kiauh_version() -> str:
"""
Helper method to get the current KIAUH version by reading the latest tag
:return: string of the latest tag
"""
return get_local_tags(Path(__file__).parent.parent)[-1]
def convert_camelcase_to_kebabcase(name: str) -> str:
return re.sub(r"(?<!^)(?=[A-Z])", "-", name).lower()
def get_current_date() -> Dict[Literal["date", "time"], str]:
"""
Get the current date |
:return: Dict holding a date and time key:value pair
"""
now: datetime = datetime.today()
date: str = now.strftime("%Y%m%d")
time: str = now.strftime("%H%M%S")
return {"date": date, "time": time}
def check_install_dependencies(
deps: Set[str] | None = None, include_global: bool = True
) -> None:
"""
Common helper method to check if dependencies are installed
and if not, install them automatically |
:param include_global: Wether to include the global dependencies or not
:param deps: List of strings of package names to check if installed
:return: None
"""
if deps is None:
deps = set()
if include_global:
deps.update(GLOBAL_DEPS)
requirements = check_package_install(deps)
if requirements:
Logger.print_status("Installing dependencies ...")
Logger.print_info("The following packages need installation:")
for r in requirements:
print(f"{COLOR_CYAN}{r}{RESET_FORMAT}")
update_system_package_lists(silent=False)
install_system_packages(requirements)
def get_install_status(
repo_dir: Path,
env_dir: Optional[Path] = None,
instance_type: type | None = None,
files: Optional[List[Path]] = None,
) -> ComponentStatus:
"""
Helper method to get the installation status of software components
:param repo_dir: the repository directory
:param env_dir: the python environment directory
:param instance_type: The component type
:param files: List of optional files to check for existence
:return: Dictionary with status string, statuscode and instance count
"""
from utils.instance_utils import get_instances
checks = [repo_dir.exists()]
if env_dir is not None:
checks.append(env_dir.exists())
instances = 0
if instance_type is not None:
instances = len(get_instances(instance_type))
checks.append(instances > 0)
if files is not None:
for f in files:
checks.append(f.exists())
status: StatusCode
if all(checks):
status = 2 # installed
elif not any(checks):
status = 0 # not installed
else:
status = 1 # incomplete
org, repo = get_repo_name(repo_dir)
return ComponentStatus(
status=status,
instances=instances,
owner=org,
repo=repo,
local=get_local_commit(repo_dir),
remote=get_remote_commit(repo_dir),
)
def backup_printer_config_dir() -> None:
# local import to prevent circular import
from core.backup_manager.backup_manager import BackupManager
instances: List[Klipper] = get_instances(Klipper)
bm = BackupManager()
for instance in instances:
name = f"config-{instance.data_dir.name}"
bm.backup_directory(
name,
source=instance.base.cfg_dir,
target=PRINTER_CFG_BACKUP_DIR,
)
def moonraker_exists(name: str = "") -> bool:
"""
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 = (
f"{name} requires Moonraker to be installed"
if name
else "A Moonraker installation is required"
)
if not mr_instances:
Logger.print_dialog(
DialogType.WARNING,
[
"No Moonraker instances found!",
f"{info}. Please install Moonraker first!",
],
)
return False
return True