Compare commits

..

2 Commits

Author SHA1 Message Date
Patrick Gehrsitz 9f97ae6c2a refactor(crowsnest): fix crowsnest install status and update for v5 (#799)
fix: fix crowsnest install status and update for v5

Crowsnest v5 introduced multiple breaking changes resulting in a
'Incomplete' install status even after successful installation.
This adds support for the new v5 setup with backwards compatibility for
old versions.

Signed-off-by: Patrick Gehrsitz <github@mryel.de>
2026-05-30 15:36:32 +02:00
_Redstone_c_ b90a8f13b1 fix(switch_repo): honor use_python_binary when recreating venv (#793)
* fix(switch_repo): honor use_python_binary when recreating venv

* fix(switch_repo): validate name at function entry
2026-04-24 13:34:45 +02:00
3 changed files with 86 additions and 9 deletions
+2
View File
@@ -19,10 +19,12 @@ CROWSNEST_SERVICE_NAME = "crowsnest.service"
# directories
CROWSNEST_DIR = Path.home().joinpath("crowsnest")
CROWSNEST_ENV_DIR = Path.home().joinpath("crowsnest-env")
# files
CROWSNEST_MULTI_CONFIG = CROWSNEST_DIR.joinpath("tools/.config")
CROWSNEST_INSTALL_SCRIPT = CROWSNEST_DIR.joinpath("tools/install.sh")
CROWSNEST_DEPS_JSON_FILE = CROWSNEST_DIR.joinpath("system-dependencies.json")
CROWSNEST_BIN_FILE = Path("/usr/local/bin/crowsnest")
CROWSNEST_LOGROTATE_FILE = Path("/etc/logrotate.d/crowsnest")
CROWSNEST_SERVICE_FILE = SYSTEMD.joinpath(CROWSNEST_SERVICE_NAME)
+68 -8
View File
@@ -16,7 +16,9 @@ from typing import List
from components.crowsnest import (
CROWSNEST_BIN_FILE,
CROWSNEST_DEPS_JSON_FILE,
CROWSNEST_DIR,
CROWSNEST_ENV_DIR,
CROWSNEST_INSTALL_SCRIPT,
CROWSNEST_LOGROTATE_FILE,
CROWSNEST_MULTI_CONFIG,
@@ -25,6 +27,8 @@ from components.crowsnest import (
CROWSNEST_SERVICE_NAME,
)
from components.klipper.klipper import Klipper
from components.moonraker.utils.sysdeps_parser import SysDepsParser
from components.moonraker.utils.utils import load_sysdeps_json
from core.logger import DialogType, Logger
from core.services.backup_service import BackupService
from core.settings.kiauh_settings import KiauhSettings
@@ -34,6 +38,7 @@ from utils.common import (
get_install_status,
)
from utils.git_utils import (
get_current_branch,
git_clone_wrapper,
git_pull_wrapper,
)
@@ -135,8 +140,7 @@ def update_crowsnest() -> None:
git_pull_wrapper(CROWSNEST_DIR)
deps = parse_packages_from_file(CROWSNEST_INSTALL_SCRIPT)
check_install_dependencies({*deps})
install_crowsnest_packages()
cmd_sysctl_service(CROWSNEST_SERVICE_NAME, "restart")
@@ -147,12 +151,68 @@ def update_crowsnest() -> None:
def get_crowsnest_status() -> ComponentStatus:
files = [
CROWSNEST_BIN_FILE,
CROWSNEST_LOGROTATE_FILE,
CROWSNEST_SERVICE_FILE,
]
return get_install_status(CROWSNEST_DIR, files=files)
"""
Get the current install status of Crowsnest. Depending on the version the installed
files are different. If a version is not yet specified, it will search for a
non_existant file resulting in 'Incomplete' status.
:return: Installation status
"""
files_dict = {
4: [
CROWSNEST_BIN_FILE,
CROWSNEST_LOGROTATE_FILE,
CROWSNEST_SERVICE_FILE,
],
5: [CROWSNEST_SERVICE_FILE],
}
version = get_crowsnest_version()
non_existant = CROWSNEST_DIR.joinpath("non_existant")
files = files_dict.get(version, [non_existant])
env_dir = None
if version >= 5:
env_dir = CROWSNEST_ENV_DIR
return get_install_status(CROWSNEST_DIR, files=files, env_dir=env_dir)
def get_crowsnest_version() -> int:
"""
Get the current major version. Starting with v5 the default branch will be named
after the major version.
:return: Current major version
"""
version = get_current_branch(CROWSNEST_DIR)
if version is None:
return 0
if version == "master":
return 4
return int(version.removeprefix("v"))
def install_crowsnest_packages() -> None:
Logger.print_status("Parsing Crowsnest system dependencies ...")
crowsnest_deps = []
crowsnest_version = get_crowsnest_version()
if crowsnest_version >= 5 and CROWSNEST_DEPS_JSON_FILE.exists():
Logger.print_info(
f"Parsing system dependencies from {CROWSNEST_DEPS_JSON_FILE.name} ..."
)
parser = SysDepsParser()
sysdeps = load_sysdeps_json(CROWSNEST_DEPS_JSON_FILE)
crowsnest_deps.extend(parser.parse_dependencies(sysdeps))
elif crowsnest_version <= 4 and CROWSNEST_INSTALL_SCRIPT.exists():
Logger.print_info(
f"Parsing system dependencies from {CROWSNEST_INSTALL_SCRIPT.name} ..."
)
crowsnest_deps = parse_packages_from_file(CROWSNEST_INSTALL_SCRIPT)
if not crowsnest_deps:
raise ValueError("Error parsing crowsnest dependencies!")
check_install_dependencies({*crowsnest_deps})
def remove_crowsnest() -> None:
+16 -1
View File
@@ -31,6 +31,7 @@ from components.moonraker.services.moonraker_setup_service import (
from core.instance_manager.instance_manager import InstanceManager
from core.logger import Logger
from core.services.backup_service import BackupService
from core.settings.kiauh_settings import KiauhSettings
from utils.git_utils import GitException, git_clone_wrapper
from utils.instance_utils import get_instances
from utils.sys_utils import (
@@ -47,6 +48,11 @@ class RepoSwitchFailedException(Exception):
def run_switch_repo_routine(
name: Literal["klipper", "moonraker"], repo_url: str, branch: str
) -> None:
if name not in ("klipper", "moonraker"):
raise ValueError(
f"Invalid name: {name!r}. Must be 'klipper' or 'moonraker'."
)
repo_dir: Path = KLIPPER_DIR if name == "klipper" else MOONRAKER_DIR
env_dir: Path = KLIPPER_ENV_DIR if name == "klipper" else MOONRAKER_ENV_DIR
req_file = KLIPPER_REQ_FILE if name == "klipper" else MOONRAKER_REQ_FILE
@@ -89,7 +95,16 @@ def run_switch_repo_routine(
# step 6: recreate python virtualenv
Logger.print_status(f"Recreating {_type.__name__} virtualenv ...")
if not create_python_venv(env_dir, force=True):
settings = KiauhSettings()
if name == "klipper":
use_python_binary = settings.klipper.use_python_binary
elif name == "moonraker":
use_python_binary = settings.moonraker.use_python_binary
if not create_python_venv(
env_dir, force=True, use_python_binary=use_python_binary
):
raise GitException(f"Failed to recreate virtualenv for {_type.__name__}")
else:
install_python_requirements(env_dir, req_file)