mirror of
https://github.com/dw-0/kiauh.git
synced 2025-12-15 03:24:29 +05:00
Compare commits
11 Commits
v6.0.0-alp
...
v5.1.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
985b66d41f | ||
|
|
f95d2586bf | ||
|
|
f5141e7eff | ||
|
|
33113e72e9 | ||
|
|
6f59fd06aa | ||
|
|
56ea43ccb6 | ||
|
|
25e22c993f | ||
|
|
ead521b377 | ||
|
|
3c952ccc12 | ||
|
|
c8f713c00e | ||
|
|
95cf809378 |
@@ -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
|
||||
#
|
||||
|
||||
@@ -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!")
|
||||
|
||||
@@ -315,8 +315,9 @@ 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)
|
||||
if self.settings.moonraker.optional_speedups:
|
||||
install_python_requirements(
|
||||
MOONRAKER_ENV_DIR, MOONRAKER_SPEEDUPS_REQ_FILE
|
||||
)
|
||||
|
||||
@@ -102,6 +102,7 @@ def install_client(
|
||||
section=f"update_manager {client.name}",
|
||||
instances=mr_instances,
|
||||
options=[
|
||||
("persistent_files", ["config.json"]),
|
||||
("type", "web"),
|
||||
("channel", "stable"),
|
||||
("repo", str(client.repo_path)),
|
||||
|
||||
@@ -119,7 +119,7 @@ def enable_mainsail_remotemode() -> None:
|
||||
with open(c_json, "r") as f:
|
||||
config_data = json.load(f)
|
||||
|
||||
if config_data["instancesDB"] == "browser":
|
||||
if config_data["instancesDB"] == "browser" or config_data["instancesDB"] == "json":
|
||||
Logger.print_info("Remote mode already configured. Skipped ...")
|
||||
return
|
||||
|
||||
|
||||
@@ -8,14 +8,15 @@
|
||||
# ======================================================================= #
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, List
|
||||
from typing import Any, Callable, List, TypeVar
|
||||
|
||||
from components.klipper import KLIPPER_REPO_URL
|
||||
from components.moonraker import MOONRAKER_REPO_URL
|
||||
from core.backup_manager.backup_manager import BackupManager
|
||||
from core.logger import DialogType, Logger
|
||||
from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import (
|
||||
NoOptionError,
|
||||
NoSectionError,
|
||||
SimpleConfigParser,
|
||||
)
|
||||
from utils.input_utils import get_confirm
|
||||
@@ -26,13 +27,7 @@ from kiauh import PROJECT_ROOT
|
||||
DEFAULT_CFG = PROJECT_ROOT.joinpath("default.kiauh.cfg")
|
||||
CUSTOM_CFG = PROJECT_ROOT.joinpath("kiauh.cfg")
|
||||
|
||||
|
||||
class NoValueError(Exception):
|
||||
"""Raised when a required value is not defined for an option"""
|
||||
|
||||
def __init__(self, section: str, option: str):
|
||||
msg = f"Missing value for option '{option}' in section '{section}'"
|
||||
super().__init__(msg)
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class InvalidValueError(Exception):
|
||||
@@ -55,8 +50,16 @@ class Repository:
|
||||
|
||||
|
||||
@dataclass
|
||||
class RepoSettings:
|
||||
class KlipperSettings:
|
||||
repositories: List[Repository] | None = field(default=None)
|
||||
use_python_binary: str | None = field(default=None)
|
||||
|
||||
|
||||
@dataclass
|
||||
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
|
||||
@@ -69,6 +72,7 @@ class WebUiSettings:
|
||||
# noinspection PyMethodMayBeStatic
|
||||
class KiauhSettings:
|
||||
__instance = None
|
||||
__initialized = False
|
||||
|
||||
def __new__(cls, *args, **kwargs) -> "KiauhSettings":
|
||||
if cls.__instance is None:
|
||||
@@ -86,20 +90,20 @@ class KiauhSettings:
|
||||
return getattr(self, item)
|
||||
|
||||
def __init__(self) -> None:
|
||||
if not hasattr(self, "__initialized"):
|
||||
self.__initialized = False
|
||||
if self.__initialized:
|
||||
return
|
||||
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()
|
||||
|
||||
self._load_config()
|
||||
self.__read_config_set_internal_state()
|
||||
|
||||
# todo: refactor this, at least rename to something else!
|
||||
def get(self, section: str, option: str) -> str | int | bool:
|
||||
"""
|
||||
Get a value from the settings state by providing the section and option name as
|
||||
@@ -117,128 +121,175 @@ class KiauhSettings:
|
||||
raise
|
||||
|
||||
def save(self) -> None:
|
||||
self._set_config_options_state()
|
||||
self.config.write_file(CUSTOM_CFG)
|
||||
self._load_config()
|
||||
self.__write_internal_state_to_cfg()
|
||||
self.__read_config_set_internal_state()
|
||||
|
||||
def _load_config(self) -> None:
|
||||
def __read_config_set_internal_state(self) -> None:
|
||||
if not CUSTOM_CFG.exists() and not DEFAULT_CFG.exists():
|
||||
self.__kill()
|
||||
|
||||
cfg = CUSTOM_CFG if CUSTOM_CFG.exists() else DEFAULT_CFG
|
||||
self.config.read_file(cfg)
|
||||
|
||||
needs_migration = self._check_deprecated_repo_config()
|
||||
if needs_migration:
|
||||
self._prompt_migration_dialog()
|
||||
return
|
||||
else:
|
||||
# Only validate if no migration was needed
|
||||
self._validate_cfg()
|
||||
self.__set_internal_state()
|
||||
|
||||
def _validate_cfg(self) -> None:
|
||||
def __err_and_kill(error: str) -> None:
|
||||
Logger.print_error(f"Error validating kiauh.cfg: {error}")
|
||||
Logger.print_dialog(
|
||||
DialogType.ERROR,
|
||||
[
|
||||
"No KIAUH configuration file found! Please make sure you have at least "
|
||||
"one of the following configuration files in KIAUH's root directory:",
|
||||
"● default.kiauh.cfg",
|
||||
"● kiauh.cfg",
|
||||
],
|
||||
)
|
||||
kill()
|
||||
|
||||
try:
|
||||
self._validate_bool("kiauh", "backup_before_update")
|
||||
# copy default config to custom config if it does not exist
|
||||
if not CUSTOM_CFG.exists():
|
||||
shutil.copyfile(DEFAULT_CFG, CUSTOM_CFG)
|
||||
|
||||
self._validate_repositories("klipper", "repositories")
|
||||
self._validate_repositories("moonraker", "repositories")
|
||||
self.config.read_file(CUSTOM_CFG)
|
||||
|
||||
self._validate_int("mainsail", "port")
|
||||
self._validate_bool("mainsail", "unstable_releases")
|
||||
# check if there are deprecated repo_url and branch options in the kiauh.cfg
|
||||
if self._check_deprecated_repo_config():
|
||||
self._prompt_migration_dialog()
|
||||
|
||||
self._validate_int("fluidd", "port")
|
||||
self._validate_bool("fluidd", "unstable_releases")
|
||||
|
||||
except ValueError:
|
||||
err = f"Invalid value for option '{self._v_option}' in section '{self._v_section}'"
|
||||
__err_and_kill(err)
|
||||
except NoSectionError:
|
||||
err = f"Missing section '{self._v_section}' in config file"
|
||||
__err_and_kill(err)
|
||||
except NoOptionError:
|
||||
err = f"Missing option '{self._v_option}' in section '{self._v_section}'"
|
||||
__err_and_kill(err)
|
||||
except NoValueError:
|
||||
err = f"Missing value for option '{self._v_option}' in section '{self._v_section}'"
|
||||
__err_and_kill(err)
|
||||
|
||||
def _validate_bool(self, section: str, option: str) -> None:
|
||||
self._v_section, self._v_option = (section, option)
|
||||
(bool(self.config.getboolean(section, option)))
|
||||
|
||||
def _validate_int(self, section: str, option: str) -> None:
|
||||
self._v_section, self._v_option = (section, option)
|
||||
int(self.config.getint(section, option))
|
||||
|
||||
def _validate_str(self, section: str, option: str) -> None:
|
||||
self._v_section, self._v_option = (section, option)
|
||||
v = self.config.getval(section, option)
|
||||
|
||||
if not v:
|
||||
raise ValueError
|
||||
|
||||
def _validate_repositories(self, section: str, option: str) -> None:
|
||||
self._v_section, self._v_option = (section, option)
|
||||
repos = self.config.getval(section, option)
|
||||
if not repos:
|
||||
raise NoValueError(section, option)
|
||||
|
||||
for repo in repos:
|
||||
if repo.strip().startswith("#") or repo.strip().startswith(";"):
|
||||
continue
|
||||
try:
|
||||
if "," in repo:
|
||||
url, branch = repo.strip().split(",")
|
||||
if not url:
|
||||
raise InvalidValueError(section, option, repo)
|
||||
else:
|
||||
url = repo.strip()
|
||||
if not url:
|
||||
raise InvalidValueError(section, option, repo)
|
||||
except ValueError:
|
||||
raise InvalidValueError(section, option, repo)
|
||||
self.__set_internal_state()
|
||||
|
||||
def __set_internal_state(self) -> None:
|
||||
self.kiauh.backup_before_update = self.config.getboolean(
|
||||
"kiauh", "backup_before_update"
|
||||
# parse Kiauh options
|
||||
self.kiauh.backup_before_update = self.__read_from_cfg(
|
||||
"kiauh",
|
||||
"backup_before_update",
|
||||
self.config.getboolean,
|
||||
False,
|
||||
)
|
||||
|
||||
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.mainsail.port = self.config.getint("mainsail", "port")
|
||||
self.mainsail.unstable_releases = self.config.getboolean(
|
||||
"mainsail", "unstable_releases"
|
||||
# parse Klipper options
|
||||
self.klipper.use_python_binary = self.__read_from_cfg(
|
||||
"klipper",
|
||||
"use_python_binary",
|
||||
self.config.getval,
|
||||
None,
|
||||
True,
|
||||
)
|
||||
self.fluidd.port = self.config.getint("fluidd", "port")
|
||||
self.fluidd.unstable_releases = self.config.getboolean(
|
||||
"fluidd", "unstable_releases"
|
||||
kl_repos: List[str] = self.__read_from_cfg(
|
||||
"klipper",
|
||||
"repositories",
|
||||
self.config.getvals,
|
||||
[KLIPPER_REPO_URL],
|
||||
)
|
||||
self.klipper.repositories = self.__set_repo_state("klipper", kl_repos)
|
||||
|
||||
# parse Moonraker options
|
||||
self.moonraker.use_python_binary = self.__read_from_cfg(
|
||||
"moonraker",
|
||||
"use_python_binary",
|
||||
self.config.getval,
|
||||
None,
|
||||
True,
|
||||
)
|
||||
self.moonraker.optional_speedups = self.__read_from_cfg(
|
||||
"moonraker",
|
||||
"optional_speedups",
|
||||
self.config.getboolean,
|
||||
True,
|
||||
)
|
||||
mr_repos: List[str] = self.__read_from_cfg(
|
||||
"moonraker",
|
||||
"repositories",
|
||||
self.config.getvals,
|
||||
[MOONRAKER_REPO_URL],
|
||||
)
|
||||
self.moonraker.repositories = self.__set_repo_state("moonraker", mr_repos)
|
||||
|
||||
# parse Mainsail options
|
||||
self.mainsail.port = self.__read_from_cfg(
|
||||
"mainsail",
|
||||
"port",
|
||||
self.config.getint,
|
||||
80,
|
||||
)
|
||||
self.mainsail.unstable_releases = self.__read_from_cfg(
|
||||
"mainsail",
|
||||
"unstable_releases",
|
||||
self.config.getboolean,
|
||||
False,
|
||||
)
|
||||
|
||||
def __set_repo_state(self, repos: List[str]) -> List[Repository]:
|
||||
# parse Fluidd options
|
||||
self.fluidd.port = self.__read_from_cfg(
|
||||
"fluidd",
|
||||
"port",
|
||||
self.config.getint,
|
||||
80,
|
||||
)
|
||||
self.fluidd.unstable_releases = self.__read_from_cfg(
|
||||
"fluidd",
|
||||
"unstable_releases",
|
||||
self.config.getboolean,
|
||||
False,
|
||||
)
|
||||
|
||||
def __check_option_exists(
|
||||
self, section: str, option: str, fallback: Any, silent: bool = False
|
||||
) -> bool:
|
||||
has_section = self.config.has_section(section)
|
||||
has_option = self.config.has_option(section, option)
|
||||
|
||||
if not (has_section and has_option):
|
||||
if not silent:
|
||||
Logger.print_warn(
|
||||
f"Option '{option}' in section '{section}' not defined. Falling back to '{fallback}'."
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
def __read_bool_from_cfg(
|
||||
self,
|
||||
section: str,
|
||||
option: str,
|
||||
fallback: bool | None = None,
|
||||
silent: bool = False,
|
||||
) -> bool | None:
|
||||
if not self.__check_option_exists(section, option, fallback, silent):
|
||||
return fallback
|
||||
return self.config.getboolean(section, option, fallback)
|
||||
|
||||
def __read_from_cfg(
|
||||
self,
|
||||
section: str,
|
||||
option: str,
|
||||
getter: Callable[[str, str, T | None], T],
|
||||
fallback: T = None,
|
||||
silent: bool = False,
|
||||
) -> T:
|
||||
if not self.__check_option_exists(section, option, fallback, silent):
|
||||
return fallback
|
||||
return getter(section, option, fallback)
|
||||
|
||||
def __set_repo_state(self, section: str, repos: List[str]) -> List[Repository]:
|
||||
_repos: List[Repository] = []
|
||||
for repo in repos:
|
||||
try:
|
||||
if repo.strip().startswith("#") or repo.strip().startswith(";"):
|
||||
continue
|
||||
if "," in repo:
|
||||
url, branch = repo.strip().split(",")
|
||||
|
||||
if not branch:
|
||||
branch = "master"
|
||||
else:
|
||||
url = repo.strip()
|
||||
branch = "master"
|
||||
|
||||
# url must not be empty otherwise it's considered
|
||||
# as an unrecoverable, invalid configuration
|
||||
if not url:
|
||||
raise InvalidValueError(section, "repositories", repo)
|
||||
|
||||
_repos.append(Repository(url.strip(), branch.strip()))
|
||||
|
||||
except InvalidValueError as e:
|
||||
Logger.print_error(f"Error parsing kiauh.cfg: {e}")
|
||||
kill()
|
||||
|
||||
return _repos
|
||||
|
||||
def _set_config_options_state(self) -> None:
|
||||
def __write_internal_state_to_cfg(self) -> None:
|
||||
"""Updates the config with current settings, preserving values that haven't been modified"""
|
||||
if self.kiauh.backup_before_update is not None:
|
||||
self.config.set_option(
|
||||
@@ -276,6 +327,8 @@ class KiauhSettings:
|
||||
"fluidd", "unstable_releases", str(self.fluidd.unstable_releases)
|
||||
)
|
||||
|
||||
self.config.write_file(CUSTOM_CFG)
|
||||
|
||||
def _check_deprecated_repo_config(self) -> bool:
|
||||
# repo_url and branch are deprecated - 2025.03.23
|
||||
for section in ["klipper", "moonraker"]:
|
||||
@@ -287,22 +340,23 @@ class KiauhSettings:
|
||||
|
||||
def _prompt_migration_dialog(self) -> None:
|
||||
migration_1: List[str] = [
|
||||
"The old 'repo_url' and 'branch' options are now combined under 'repositories'.",
|
||||
"Options 'repo_url' and 'branch' are now combined into a 'repositories' option.",
|
||||
"\n\n",
|
||||
"Example format:",
|
||||
"● Old format:",
|
||||
" [klipper]",
|
||||
" repo_url: https://github.com/Klipper3d/klipper",
|
||||
" branch: master",
|
||||
"\n\n",
|
||||
"● New format:",
|
||||
" [klipper]",
|
||||
" repositories:",
|
||||
" https://github.com/Klipper3d/klipper, master",
|
||||
"\n\n",
|
||||
"[moonraker]",
|
||||
"repositories:",
|
||||
" https://github.com/Arksine/moonraker, master",
|
||||
]
|
||||
Logger.print_dialog(
|
||||
DialogType.ATTENTION,
|
||||
[
|
||||
"Deprecated repository configuration found!",
|
||||
"KAIUH can now attempt to automatically migrate your configuration.",
|
||||
"Deprecated kiauh.cfg configuration found!",
|
||||
"KAIUH can now attempt to automatically migrate the configuration.",
|
||||
"\n\n",
|
||||
*migration_1,
|
||||
],
|
||||
@@ -313,7 +367,7 @@ class KiauhSettings:
|
||||
Logger.print_dialog(
|
||||
DialogType.ERROR,
|
||||
[
|
||||
"Please update your configuration file manually.",
|
||||
"Please update the configuration file manually.",
|
||||
],
|
||||
center_content=True,
|
||||
)
|
||||
@@ -354,23 +408,7 @@ class KiauhSettings:
|
||||
self.config.write_file(CUSTOM_CFG)
|
||||
self.config.read_file(CUSTOM_CFG) # reload config
|
||||
|
||||
# Validate the migrated config
|
||||
self._validate_cfg()
|
||||
self.__set_internal_state()
|
||||
|
||||
except Exception as e:
|
||||
Logger.print_error(f"Error migrating configuration: {e}")
|
||||
Logger.print_error("Please migrate manually.")
|
||||
kill()
|
||||
|
||||
def __kill(self) -> None:
|
||||
Logger.print_dialog(
|
||||
DialogType.ERROR,
|
||||
[
|
||||
"No KIAUH configuration file found! Please make sure you have at least "
|
||||
"one of the following configuration files in KIAUH's root directory:",
|
||||
"● default.kiauh.cfg",
|
||||
"● kiauh.cfg",
|
||||
],
|
||||
)
|
||||
kill()
|
||||
|
||||
@@ -314,9 +314,7 @@ class SimpleConfigParser:
|
||||
elements.pop(i)
|
||||
break
|
||||
|
||||
def getval(
|
||||
self, section: str, option: str, fallback: str | _UNSET = _UNSET
|
||||
) -> str | List[str]:
|
||||
def getval(self, section: str, option: str, fallback: str | _UNSET = _UNSET) -> str:
|
||||
"""
|
||||
Return the value of the given option in the given section
|
||||
|
||||
@@ -329,22 +327,34 @@ class SimpleConfigParser:
|
||||
if option not in self.get_options(section):
|
||||
raise NoOptionError(option, section)
|
||||
|
||||
# Find the option in the elements list
|
||||
for element in self.config[section]["elements"]:
|
||||
if element["type"] in [LineType.OPTION.value, LineType.OPTION_BLOCK.value] and element["name"] == option:
|
||||
raw_value = element["value"]
|
||||
if isinstance(raw_value, str) and raw_value.endswith("\n"):
|
||||
return raw_value[:-1].strip()
|
||||
elif isinstance(raw_value, list):
|
||||
values: List[str] = []
|
||||
for i, val in enumerate(raw_value):
|
||||
val = val.strip().strip("\n")
|
||||
if len(val) < 1:
|
||||
continue
|
||||
values.append(val.strip())
|
||||
return values
|
||||
return str(raw_value)
|
||||
if element["type"] is LineType.OPTION.value and element["name"] == option:
|
||||
return str(element["value"].strip().replace("\n", ""))
|
||||
return ""
|
||||
|
||||
except (NoSectionError, NoOptionError):
|
||||
if fallback is _UNSET:
|
||||
raise
|
||||
return fallback
|
||||
|
||||
def getvals(self, section: str, option: str, fallback: List[str] | _UNSET = _UNSET) -> List[str]:
|
||||
"""
|
||||
Return the values of the given multi-line option in the given section
|
||||
|
||||
If the key is not found and 'fallback' is provided, it is used as
|
||||
a fallback value.
|
||||
"""
|
||||
try:
|
||||
if section not in self.get_sections():
|
||||
raise NoSectionError(section)
|
||||
if option not in self.get_options(section):
|
||||
raise NoOptionError(option, section)
|
||||
|
||||
for element in self.config[section]["elements"]:
|
||||
if element["type"] is LineType.OPTION_BLOCK.value and element["name"] == option:
|
||||
return [val.strip() for val in element["value"] if val.strip()]
|
||||
return []
|
||||
|
||||
except (NoSectionError, NoOptionError):
|
||||
if fallback is _UNSET:
|
||||
raise
|
||||
|
||||
@@ -51,7 +51,7 @@ def test_getval(parser):
|
||||
assert parser.getval("section_2", "option_2") == "value_2"
|
||||
|
||||
# test multiline option values
|
||||
ml_val = parser.getval("section number 5", "multi_option")
|
||||
ml_val = parser.getvals("section number 5", "multi_option")
|
||||
assert isinstance(ml_val, list)
|
||||
assert len(ml_val) > 0
|
||||
|
||||
@@ -164,7 +164,7 @@ def test_set_new_option(parser):
|
||||
assert parser.getval("new_section", "very_new_option") == "very_new_value"
|
||||
|
||||
parser.set_option("section_2", "array_option", ["value_1", "value_2", "value_3"])
|
||||
assert parser.getval("section_2", "array_option") == [
|
||||
assert parser.getvals("section_2", "array_option") == [
|
||||
"value_1",
|
||||
"value_2",
|
||||
"value_3",
|
||||
|
||||
@@ -11,7 +11,7 @@ from __future__ import annotations
|
||||
import shutil
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from typing import List, Tuple
|
||||
from typing import List, Tuple, Union
|
||||
|
||||
from core.logger import Logger
|
||||
from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import (
|
||||
@@ -19,7 +19,7 @@ from core.submodules.simple_config_parser.src.simple_config_parser.simple_config
|
||||
)
|
||||
from utils.instance_type import InstanceType
|
||||
|
||||
ConfigOption = Tuple[str, str]
|
||||
ConfigOption = Tuple[str, Union[str, List[str]]]
|
||||
|
||||
|
||||
def add_config_section(
|
||||
|
||||
@@ -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,13 +104,19 @@ 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
|
||||
|
||||
n = 2
|
||||
while(n > 0):
|
||||
if not target.exists():
|
||||
try:
|
||||
run(cmd, check=True)
|
||||
@@ -119,6 +126,11 @@ def create_python_venv(
|
||||
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
|
||||
):
|
||||
@@ -127,8 +139,7 @@ def create_python_venv(
|
||||
|
||||
try:
|
||||
shutil.rmtree(target)
|
||||
create_python_venv(target)
|
||||
return True
|
||||
n -= 1
|
||||
except OSError as e:
|
||||
log = f"Error removing existing virtualenv: {e.strerror}"
|
||||
Logger.print_error(log, False)
|
||||
@@ -173,9 +184,6 @@ def install_python_requirements(target: Path, requirements: Path) -> None:
|
||||
:return: None
|
||||
"""
|
||||
try:
|
||||
# always update pip before installing requirements
|
||||
update_python_pip(target)
|
||||
|
||||
Logger.print_status("Installing Python requirements ...")
|
||||
command = [
|
||||
target.joinpath("bin/pip").as_posix(),
|
||||
@@ -185,7 +193,7 @@ def install_python_requirements(target: Path, requirements: Path) -> None:
|
||||
]
|
||||
result = run(command, stderr=PIPE, text=True)
|
||||
|
||||
if result.returncode != 0 or result.stderr:
|
||||
if result.returncode != 0:
|
||||
Logger.print_error(f"{result.stderr}", False)
|
||||
raise VenvCreationFailedException("Installing Python requirements failed!")
|
||||
|
||||
@@ -205,9 +213,6 @@ def install_python_packages(target: Path, packages: List[str]) -> None:
|
||||
:return: None
|
||||
"""
|
||||
try:
|
||||
# always update pip before installing requirements
|
||||
update_python_pip(target)
|
||||
|
||||
Logger.print_status("Installing Python requirements ...")
|
||||
command = [
|
||||
target.joinpath("bin/pip").as_posix(),
|
||||
@@ -217,7 +222,7 @@ def install_python_packages(target: Path, packages: List[str]) -> None:
|
||||
command.append(pkg)
|
||||
result = run(command, stderr=PIPE, text=True)
|
||||
|
||||
if result.returncode != 0 or result.stderr:
|
||||
if result.returncode != 0:
|
||||
Logger.print_error(f"{result.stderr}", False)
|
||||
raise VenvCreationFailedException("Installing Python requirements failed!")
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
requires-python = ">=3.8"
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev=["ruff", "mypy"]
|
||||
dev=["ruff", "pyright"]
|
||||
|
||||
[tool.ruff]
|
||||
required-version = ">=0.9.10"
|
||||
@@ -20,14 +20,3 @@ quote-style = "double"
|
||||
|
||||
[tool.ruff.lint]
|
||||
extend-select = ["I"]
|
||||
|
||||
[tool.mypy]
|
||||
python_version = "3.8"
|
||||
platform = "linux"
|
||||
# strict = true # TODO: enable this once everything is else is handled
|
||||
check_untyped_defs = true
|
||||
ignore_missing_imports = true
|
||||
warn_redundant_casts = true
|
||||
warn_unused_ignores = true
|
||||
warn_return_any = true
|
||||
warn_unreachable = true
|
||||
|
||||
6
pyrightconfig.json
Normal file
6
pyrightconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"pythonVersion": "3.8",
|
||||
"pythonPlatform": "Linux",
|
||||
"typeCheckingMode": "standard",
|
||||
"venvPath": "./.kiauh-env"
|
||||
}
|
||||
2
requirements-dev.txt
Normal file
2
requirements-dev.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
ruff (>=0.9.10)
|
||||
pyright
|
||||
@@ -280,7 +280,6 @@ function create_klipper_virtualenv() {
|
||||
status_msg "Installing $("python${python_version}" -V) virtual environment..."
|
||||
|
||||
if virtualenv -p "python${python_version}" "${KLIPPY_ENV}"; then
|
||||
(( python_version == 3 )) && "${KLIPPY_ENV}"/bin/pip install -U pip
|
||||
"${KLIPPY_ENV}"/bin/pip install -r "${KLIPPER_DIR}"/scripts/klippy-requirements.txt
|
||||
else
|
||||
log_error "failure while creating python3 klippy-env"
|
||||
|
||||
@@ -126,7 +126,7 @@ function update_klipperscreen() {
|
||||
git checkout -f master && ok_msg "Checkout successfull"
|
||||
|
||||
if [[ $(md5sum "${KLIPPERSCREEN_DIR}/scripts/KlipperScreen-requirements.txt" | cut -d " " -f1) != "${old_md5}" ]]; then
|
||||
status_msg "New dependecies detected..."
|
||||
status_msg "New dependencies detected..."
|
||||
"${KLIPPERSCREEN_ENV}"/bin/pip install -r "${KLIPPERSCREEN_DIR}/scripts/KlipperScreen-requirements.txt"
|
||||
ok_msg "Dependencies have been installed!"
|
||||
fi
|
||||
|
||||
@@ -133,7 +133,7 @@ function update_mobileraker() {
|
||||
git checkout -f main && ok_msg "Checkout successfull"
|
||||
|
||||
if [[ $(md5sum "${MOBILERAKER_DIR}/scripts/mobileraker-requirements.txt" | cut -d " " -f1) != "${old_md5}" ]]; then
|
||||
status_msg "New dependecies detected..."
|
||||
status_msg "New dependencies detected..."
|
||||
"${MOBILERAKER_ENV}"/bin/pip install -r "${MOBILERAKER_DIR}/scripts/mobileraker-requirements.txt"
|
||||
ok_msg "Dependencies have been installed!"
|
||||
fi
|
||||
|
||||
@@ -336,7 +336,6 @@ function create_moonraker_virtualenv() {
|
||||
[[ -d ${MOONRAKER_ENV} ]] && rm -rf "${MOONRAKER_ENV}"
|
||||
|
||||
if virtualenv -p /usr/bin/python3 "${MOONRAKER_ENV}"; then
|
||||
"${MOONRAKER_ENV}"/bin/pip install -U pip
|
||||
"${MOONRAKER_ENV}"/bin/pip install -r "${MOONRAKER_DIR}/scripts/moonraker-requirements.txt"
|
||||
else
|
||||
log_error "failure while creating python3 moonraker-env"
|
||||
|
||||
Reference in New Issue
Block a user