diff --git a/default.kiauh.cfg b/default.kiauh.cfg index 5333a60..d3ac149 100644 --- a/default.kiauh.cfg +++ b/default.kiauh.cfg @@ -13,6 +13,10 @@ repositories: https://github.com/Klipper3d/klipper [moonraker] +# Moonraker supports two optional Python packages that can be used to reduce its CPU load +# If set to true, those packages will be installed during the Moonraker installation +optional_speedups: True + # add custom repositories here, if at least one is given, the first in the list will be used by default # otherwise the official repository is used # diff --git a/kiauh/components/klipper/services/klipper_setup_service.py b/kiauh/components/klipper/services/klipper_setup_service.py index 9c5a695..2a80b94 100644 --- a/kiauh/components/klipper/services/klipper_setup_service.py +++ b/kiauh/components/klipper/services/klipper_setup_service.py @@ -277,7 +277,7 @@ class KlipperSetupService: try: install_klipper_packages() - if create_python_venv(KLIPPER_ENV_DIR): + if create_python_venv(KLIPPER_ENV_DIR, False, False, self.settings.klipper.use_python_binary): install_python_requirements(KLIPPER_ENV_DIR, KLIPPER_REQ_FILE) except Exception: Logger.print_error("Error during installation of Klipper requirements!") diff --git a/kiauh/components/moonraker/services/moonraker_setup_service.py b/kiauh/components/moonraker/services/moonraker_setup_service.py index 7f6e6b3..45edd6f 100644 --- a/kiauh/components/moonraker/services/moonraker_setup_service.py +++ b/kiauh/components/moonraker/services/moonraker_setup_service.py @@ -315,11 +315,12 @@ class MoonrakerSetupService: try: install_moonraker_packages() - if create_python_venv(MOONRAKER_ENV_DIR): + if create_python_venv(MOONRAKER_ENV_DIR, False, False, self.settings.moonraker.use_python_binary): install_python_requirements(MOONRAKER_ENV_DIR, MOONRAKER_REQ_FILE) - install_python_requirements( - MOONRAKER_ENV_DIR, MOONRAKER_SPEEDUPS_REQ_FILE - ) + if self.settings.moonraker.optional_speedups: + install_python_requirements( + MOONRAKER_ENV_DIR, MOONRAKER_SPEEDUPS_REQ_FILE + ) self.__install_polkit() except Exception: Logger.print_error("Error during installation of Moonraker requirements!") diff --git a/kiauh/core/settings/kiauh_settings.py b/kiauh/core/settings/kiauh_settings.py index 55dacb7..6c61a68 100644 --- a/kiauh/core/settings/kiauh_settings.py +++ b/kiauh/core/settings/kiauh_settings.py @@ -53,11 +53,16 @@ class Repository: url: str branch: str +@dataclass +class KlipperSettings: + repositories: List[Repository] | None = field(default=None) + use_python_binary: str | None = field(default=None) @dataclass -class RepoSettings: +class MoonrakerSettings: + optional_speedups: bool | None = field(default=None) repositories: List[Repository] | None = field(default=None) - + use_python_binary: str | None = field(default=None) @dataclass class WebUiSettings: @@ -93,8 +98,8 @@ class KiauhSettings: self.__initialized = True self.config = SimpleConfigParser() self.kiauh = AppSettings() - self.klipper = RepoSettings() - self.moonraker = RepoSettings() + self.klipper = KlipperSettings() + self.moonraker = MoonrakerSettings() self.mainsail = WebUiSettings() self.fluidd = WebUiSettings() @@ -153,6 +158,8 @@ class KiauhSettings: self._validate_int("fluidd", "port") self._validate_bool("fluidd", "unstable_releases") + + self._validate_bool("moonraker", "optional_speedups") except ValueError: err = f"Invalid value for option '{self._v_option}' in section '{self._v_section}'" @@ -208,12 +215,17 @@ class KiauhSettings: "kiauh", "backup_before_update" ) + self.moonraker.optional_speedups = self.config.getboolean("moonraker", "optional_speedups", True) + kl_repos = self.config.getval("klipper", "repositories") self.klipper.repositories = self.__set_repo_state(kl_repos) mr_repos = self.config.getval("moonraker", "repositories") self.moonraker.repositories = self.__set_repo_state(mr_repos) + self.klipper.use_python_binary = self.config.getval("klipper", "use_python_binary", None) + self.moonraker.use_python_binary = self.config.getval("moonraker", "use_python_binary", None) + self.mainsail.port = self.config.getint("mainsail", "port") self.mainsail.unstable_releases = self.config.getboolean( "mainsail", "unstable_releases" diff --git a/kiauh/utils/sys_utils.py b/kiauh/utils/sys_utils.py index a3600bd..add3ef2 100644 --- a/kiauh/utils/sys_utils.py +++ b/kiauh/utils/sys_utils.py @@ -95,6 +95,7 @@ def create_python_venv( target: Path, force: bool = False, allow_access_to_system_site_packages: bool = False, + use_python_binary: str | None = None ) -> bool: """ Create a python 3 virtualenv at the provided target destination. @@ -103,36 +104,46 @@ def create_python_venv( :param target: Path where to create the virtualenv at :param force: Force recreation of the virtualenv :param allow_access_to_system_site_packages: give the virtual environment access to the system site-packages dir + :param use_python_binary: allows to override default python binary :return: bool """ Logger.print_status("Set up Python virtual environment ...") - cmd = ["virtualenv", "-p", "/usr/bin/python3", target.as_posix()] + # If binarry override is not set, we use default defined here + python_binary = use_python_binary if use_python_binary else "/usr/bin/python3" + cmd = ["virtualenv", "-p", python_binary, target.as_posix()] cmd.append( "--system-site-packages" ) if allow_access_to_system_site_packages else None - if not target.exists(): - try: - run(cmd, check=True) - Logger.print_ok("Setup of virtualenv successful!") - return True - except CalledProcessError as e: - Logger.print_error(f"Error setting up virtualenv:\n{e}") - return False - else: - if not force and not get_confirm( - "Virtualenv already exists. Re-create?", default_choice=False - ): - Logger.print_info("Skipping re-creation of virtualenv ...") - return False - try: - shutil.rmtree(target) - create_python_venv(target) - return True - except OSError as e: - log = f"Error removing existing virtualenv: {e.strerror}" - Logger.print_error(log, False) - return False + n = 2 + while(n > 0): + if not target.exists(): + try: + run(cmd, check=True) + Logger.print_ok("Setup of virtualenv successful!") + return True + except CalledProcessError as e: + Logger.print_error(f"Error setting up virtualenv:\n{e}") + return False + else: + if n == 1: + # This case should never happen, + # but the function should still behave correctly + Logger.print_error("Virtualenv still exists after deletion.") + return False + if not force and not get_confirm( + "Virtualenv already exists. Re-create?", default_choice=False + ): + Logger.print_info("Skipping re-creation of virtualenv ...") + return False + + try: + shutil.rmtree(target) + n -= 1 + except OSError as e: + log = f"Error removing existing virtualenv: {e.strerror}" + Logger.print_error(log, False) + return False def update_python_pip(target: Path) -> None: