Compare commits

...

7 Commits

Author SHA1 Message Date
dw-0
1cd9414cae refactor: extract redundant code into shared methods
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-07-01 21:04:15 +02:00
dw-0
2391f491bb refactor: implement constants for klipper
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-07-01 20:42:22 +02:00
dw-0
92ed67ddd2 fix(mobileraker): fix typo and add more constants
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-07-01 20:41:56 +02:00
dw-0
0cb1e35b06 refactor: improve klipper class structure
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-07-01 20:41:56 +02:00
dw-0
7632c3c980 refactor: implement constants for klipper
use ubuntu 22.04 install script

Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-07-01 20:41:54 +02:00
dw-0
c1f600f539 refactor: replace glob with iterdir
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-06-30 21:25:55 +02:00
dw-0
01deab7c64 fix: disallow installing client config if another client config is installed
Signed-off-by: Dominik Willner <th33xitus@gmail.com>
2024-06-30 20:51:04 +02:00
15 changed files with 266 additions and 213 deletions

View File

@@ -13,9 +13,24 @@ from core.backup_manager import BACKUP_ROOT_DIR
MODULE_PATH = Path(__file__).resolve().parent
# names
KLIPPER_LOG_NAME = "klippy.log"
KLIPPER_CFG_NAME = "printer.cfg"
KLIPPER_SERIAL_NAME = "klippy.serial"
KLIPPER_UDS_NAME = "klippy.sock"
KLIPPER_ENV_FILE_NAME = "klipper.env"
KLIPPER_SERVICE_NAME = "klipper.service"
# directories
KLIPPER_DIR = Path.home().joinpath("klipper")
KLIPPER_ENV_DIR = Path.home().joinpath("klippy-env")
KLIPPER_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("klipper-backups")
KLIPPER_REQUIREMENTS_TXT = KLIPPER_DIR.joinpath("scripts/klippy-requirements.txt")
# files
KLIPPER_REQ_FILE = KLIPPER_DIR.joinpath("scripts/klippy-requirements.txt")
KLIPPER_INSTALL_SCRIPT = KLIPPER_DIR.joinpath("scripts/install-ubuntu-22.04.sh")
KLIPPER_SERVICE_TEMPLATE = MODULE_PATH.joinpath(f"assets/{KLIPPER_SERVICE_NAME}")
KLIPPER_ENV_FILE_TEMPLATE = MODULE_PATH.joinpath(f"assets/{KLIPPER_ENV_FILE_NAME}")
EXIT_KLIPPER_SETUP = "Exiting Klipper setup ..."

View File

@@ -8,12 +8,21 @@
# ======================================================================= #
from pathlib import Path
from subprocess import DEVNULL, CalledProcessError, run
from subprocess import CalledProcessError, run
from typing import List
from components.klipper import KLIPPER_DIR, KLIPPER_ENV_DIR, MODULE_PATH
from components.klipper import (
KLIPPER_CFG_NAME,
KLIPPER_DIR,
KLIPPER_ENV_DIR,
KLIPPER_ENV_FILE_NAME,
KLIPPER_ENV_FILE_TEMPLATE,
KLIPPER_LOG_NAME,
KLIPPER_SERIAL_NAME,
KLIPPER_SERVICE_TEMPLATE,
KLIPPER_UDS_NAME,
)
from core.instance_manager.base_instance import BaseInstance
from utils.constants import SYSTEMD
from utils.logger import Logger
@@ -27,10 +36,10 @@ class Klipper(BaseInstance):
super().__init__(instance_type=self, suffix=suffix)
self.klipper_dir: Path = KLIPPER_DIR
self.env_dir: Path = KLIPPER_ENV_DIR
self._cfg_file = self.cfg_dir.joinpath("printer.cfg")
self._log = self.log_dir.joinpath("klippy.log")
self._serial = self.comms_dir.joinpath("klippy.serial")
self._uds = self.comms_dir.joinpath("klippy.sock")
self._cfg_file = self.cfg_dir.joinpath(KLIPPER_CFG_NAME)
self._log = self.log_dir.joinpath(KLIPPER_LOG_NAME)
self._serial = self.comms_dir.joinpath(KLIPPER_SERIAL_NAME)
self._uds = self.comms_dir.joinpath(KLIPPER_UDS_NAME)
@property
def cfg_file(self) -> Path:
@@ -49,23 +58,22 @@ class Klipper(BaseInstance):
return self._uds
def create(self) -> None:
from utils.sys_utils import create_env_file, create_service_file
Logger.print_status("Creating new Klipper Instance ...")
service_template_path = MODULE_PATH.joinpath("assets/klipper.service")
service_file_name = self.get_service_file_name(extension=True)
service_file_target = SYSTEMD.joinpath(service_file_name)
env_template_file_path = MODULE_PATH.joinpath("assets/klipper.env")
env_file_target = self.sysd_dir.joinpath("klipper.env")
try:
self.create_folders()
self._write_service_file(
service_template_path,
service_file_target,
env_file_target,
create_service_file(
name=self.get_service_file_name(extension=True),
content=self._prep_service_file_content(),
)
create_env_file(
path=self.sysd_dir.joinpath(KLIPPER_ENV_FILE_NAME),
content=self._prep_env_file_content(),
)
self._write_env_file(env_template_file_path, env_file_target)
except CalledProcessError as e:
Logger.print_error(f"Error creating instance: {e}")
@@ -83,80 +91,68 @@ class Klipper(BaseInstance):
try:
command = ["sudo", "rm", "-f", service_file_path]
run(command, check=True)
self._delete_logfiles()
self.delete_logfiles(KLIPPER_LOG_NAME)
Logger.print_ok("Instance successfully removed!")
except CalledProcessError as e:
Logger.print_error(f"Error removing instance: {e}")
raise
def _write_service_file(
self,
service_template_path: Path,
service_file_target: Path,
env_file_target: Path,
) -> None:
service_content = self._prep_service_file(
service_template_path, env_file_target
)
command = ["sudo", "tee", service_file_target]
run(
command,
input=service_content.encode(),
stdout=DEVNULL,
check=True,
)
Logger.print_ok(f"Service file created: {service_file_target}")
def _prep_service_file_content(self) -> str:
template = KLIPPER_SERVICE_TEMPLATE
def _write_env_file(
self, env_template_file_path: Path, env_file_target: Path
) -> None:
env_file_content = self._prep_env_file(env_template_file_path)
with open(env_file_target, "w") as env_file:
env_file.write(env_file_content)
Logger.print_ok(f"Env file created: {env_file_target}")
def _prep_service_file(
self, service_template_path: Path, env_file_path: Path
) -> str:
try:
with open(service_template_path, "r") as template_file:
with open(template, "r") as template_file:
template_content = template_file.read()
except FileNotFoundError:
Logger.print_error(
f"Unable to open {service_template_path} - File not found"
)
Logger.print_error(f"Unable to open {template} - File not found")
raise
service_content = template_content.replace("%USER%", self.user)
service_content = service_content.replace(
"%KLIPPER_DIR%", str(self.klipper_dir)
service_content = template_content.replace(
"%USER%",
self.user,
)
service_content = service_content.replace(
"%KLIPPER_DIR%",
self.klipper_dir.as_posix(),
)
service_content = service_content.replace(
"%ENV%",
self.env_dir.as_posix(),
)
service_content = service_content.replace(
"%ENV_FILE%",
self.sysd_dir.joinpath(KLIPPER_ENV_FILE_NAME).as_posix(),
)
service_content = service_content.replace("%ENV%", str(self.env_dir))
service_content = service_content.replace("%ENV_FILE%", str(env_file_path))
return service_content
def _prep_env_file(self, env_template_file_path: Path) -> str:
def _prep_env_file_content(self) -> str:
template = KLIPPER_ENV_FILE_TEMPLATE
try:
with open(env_template_file_path, "r") as env_file:
with open(template, "r") as env_file:
env_template_file_content = env_file.read()
except FileNotFoundError:
Logger.print_error(
f"Unable to open {env_template_file_path} - File not found"
)
Logger.print_error(f"Unable to open {template} - File not found")
raise
env_file_content = env_template_file_content.replace(
"%KLIPPER_DIR%", str(self.klipper_dir)
"%KLIPPER_DIR%", self.klipper_dir.as_posix()
)
env_file_content = env_file_content.replace(
"%CFG%", f"{self.cfg_dir}/printer.cfg"
"%CFG%",
f"{self.cfg_dir}/{KLIPPER_CFG_NAME}",
)
env_file_content = env_file_content.replace("%SERIAL%", str(self.serial))
env_file_content = env_file_content.replace("%LOG%", str(self.log))
env_file_content = env_file_content.replace("%UDS%", str(self.uds))
env_file_content = env_file_content.replace(
"%SERIAL%",
self.serial.as_posix(),
)
env_file_content = env_file_content.replace(
"%LOG%",
self.log.as_posix(),
)
env_file_content = env_file_content.replace(
"%UDS%",
self.uds.as_posix(),
)
return env_file_content
def _delete_logfiles(self) -> None:
from utils.fs_utils import run_remove_routines
for log in list(self.log_dir.glob("klippy.log*")):
Logger.print_status(f"Remove '{log}'")
run_remove_routines(log)

View File

@@ -13,7 +13,8 @@ from components.klipper import (
EXIT_KLIPPER_SETUP,
KLIPPER_DIR,
KLIPPER_ENV_DIR,
KLIPPER_REQUIREMENTS_TXT,
KLIPPER_INSTALL_SCRIPT,
KLIPPER_REQ_FILE,
)
from components.klipper.klipper import Klipper
from components.klipper.klipper_utils import (
@@ -115,21 +116,19 @@ def setup_klipper_prerequesites() -> None:
# install klipper dependencies and create python virtualenv
try:
install_klipper_packages(KLIPPER_DIR)
install_klipper_packages()
create_python_venv(KLIPPER_ENV_DIR)
install_python_requirements(KLIPPER_ENV_DIR, KLIPPER_REQUIREMENTS_TXT)
install_python_requirements(KLIPPER_ENV_DIR, KLIPPER_REQ_FILE)
except Exception:
Logger.print_error("Error during installation of Klipper requirements!")
raise
def install_klipper_packages(klipper_dir: Path) -> None:
script = klipper_dir.joinpath("scripts/install-debian.sh")
def install_klipper_packages() -> None:
script = KLIPPER_INSTALL_SCRIPT
packages = parse_packages_from_file(script)
packages = [pkg.replace("python-dev", "python3-dev") for pkg in packages]
packages.append("python3-venv")
# Add dfu-util for octopi-images
packages.append("dfu-util")
packages.append("python3-venv") # todo: remove once switched to virtualenv
# Add dbus requirement for DietPi distro
if Path("/boot/dietpi/.version").exists():
packages.append("dbus")
@@ -160,9 +159,9 @@ def update_klipper() -> None:
git_pull_wrapper(repo=settings.klipper.repo_url, target_dir=KLIPPER_DIR)
# install possible new system packages
install_klipper_packages(KLIPPER_DIR)
install_klipper_packages()
# install possible new python dependencies
install_python_requirements(KLIPPER_ENV_DIR, KLIPPER_REQUIREMENTS_TXT)
install_python_requirements(KLIPPER_ENV_DIR, KLIPPER_REQ_FILE)
instance_manager.start_all_instance()

View File

@@ -9,8 +9,19 @@
from pathlib import Path
from core.backup_manager import BACKUP_ROOT_DIR
from utils.constants import SYSTEMD
# names
MOBILERAKER_REPO = "https://github.com/Clon1998/mobileraker_companion.git"
MOBILERAKER_UPDATER_SECTION_NAME = "update_manager mobileraker"
MOBILERAKER_LOG_NAME = "mobileraker.log"
# directories
MOBILERAKER_DIR = Path.home().joinpath("mobileraker_companion")
MOBILERAKER_ENV = Path.home().joinpath("mobileraker-env")
MOBILERAKER_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("mobileraker-backups")
# files
MOBILERAKER_ENV = Path.home().joinpath("mobileraker-env")
MOBILERAKER_INSTALL_SCRIPT = MOBILERAKER_DIR.joinpath("scripts/install.sh")
MOBILERAKER_REQ_FILE = MOBILERAKER_DIR.joinpath("scripts/mobileraker-requirements.txt")
MOBILERAKER_SERVICE_FILE = SYSTEMD.joinpath("mobileraker.service")

View File

@@ -16,7 +16,12 @@ from components.mobileraker import (
MOBILERAKER_BACKUP_DIR,
MOBILERAKER_DIR,
MOBILERAKER_ENV,
MOBILERAKER_INSTALL_SCRIPT,
MOBILERAKER_LOG_NAME,
MOBILERAKER_REPO,
MOBILERAKER_REQ_FILE,
MOBILERAKER_SERVICE_FILE,
MOBILERAKER_UPDATER_SECTION_NAME,
)
from components.moonraker.moonraker import Moonraker
from core.backup_manager.backup_manager import BackupManager
@@ -24,7 +29,6 @@ from core.instance_manager.instance_manager import InstanceManager
from core.settings.kiauh_settings import KiauhSettings
from utils.common import check_install_dependencies, get_install_status
from utils.config_utils import add_config_section, remove_config_section
from utils.constants import SYSTEMD
from utils.fs_utils import remove_with_sudo
from utils.git_utils import (
git_clone_wrapper,
@@ -72,8 +76,7 @@ def install_mobileraker() -> None:
git_clone_wrapper(MOBILERAKER_REPO, MOBILERAKER_DIR)
try:
script = f"{MOBILERAKER_DIR}/scripts/install.sh"
run(script, shell=True, check=True)
run(MOBILERAKER_INSTALL_SCRIPT.as_posix(), shell=True, check=True)
if mr_instances:
patch_mobileraker_update_manager(mr_instances)
mr_im.restart_all_instance()
@@ -89,19 +92,18 @@ def install_mobileraker() -> None:
def patch_mobileraker_update_manager(instances: List[Moonraker]) -> None:
env_py = f"{MOBILERAKER_ENV}/bin/python"
add_config_section(
section="update_manager mobileraker",
section=MOBILERAKER_UPDATER_SECTION_NAME,
instances=instances,
options=[
("type", "git_repo"),
("path", "mobileraker_companion"),
("orgin", MOBILERAKER_REPO),
("path", MOBILERAKER_DIR.as_posix()),
("origin", MOBILERAKER_REPO),
("primary_branch", "main"),
("managed_services", "mobileraker"),
("env", env_py),
("requirements", "scripts/mobileraker-requirements.txt"),
("install_script", "scripts/install.sh"),
("env", f"{MOBILERAKER_ENV}/bin/python"),
("requirements", MOBILERAKER_REQ_FILE.as_posix()),
("install_script", MOBILERAKER_INSTALL_SCRIPT.as_posix()),
],
)
@@ -124,8 +126,7 @@ def update_mobileraker() -> None:
git_pull_wrapper(MOBILERAKER_REPO, MOBILERAKER_DIR)
requirements = MOBILERAKER_DIR.joinpath("/scripts/mobileraker-requirements.txt")
install_python_requirements(MOBILERAKER_ENV, requirements)
install_python_requirements(MOBILERAKER_ENV, MOBILERAKER_REQ_FILE)
cmd_sysctl_service("mobileraker", "start")
@@ -139,7 +140,7 @@ def get_mobileraker_status() -> ComponentStatus:
return get_install_status(
MOBILERAKER_DIR,
MOBILERAKER_ENV,
files=[SYSTEMD.joinpath("mobileraker.service")],
files=[MOBILERAKER_SERVICE_FILE],
)
@@ -160,12 +161,11 @@ def remove_mobileraker() -> None:
else:
Logger.print_warn("Mobileraker's companion environment not found!")
service = SYSTEMD.joinpath("mobileraker.service")
if service.exists():
if MOBILERAKER_SERVICE_FILE.exists():
Logger.print_status("Removing mobileraker service ...")
cmd_sysctl_service(service, "stop")
cmd_sysctl_service(service, "disable")
remove_with_sudo(service)
cmd_sysctl_service(MOBILERAKER_SERVICE_FILE, "stop")
cmd_sysctl_service(MOBILERAKER_SERVICE_FILE, "disable")
remove_with_sudo(MOBILERAKER_SERVICE_FILE)
cmd_sysctl_manage("daemon-reload")
cmd_sysctl_manage("reset-failed")
Logger.print_ok("Mobileraker's companion service successfully removed!")
@@ -173,7 +173,7 @@ def remove_mobileraker() -> None:
kl_im = InstanceManager(Klipper)
kl_instances: List[Klipper] = kl_im.instances
for instance in kl_instances:
logfile = instance.log_dir.joinpath("mobileraker.log")
logfile = instance.log_dir.joinpath(MOBILERAKER_LOG_NAME)
if logfile.exists():
Logger.print_status(f"Removing {logfile} ...")
Path(logfile).unlink()
@@ -185,7 +185,7 @@ def remove_mobileraker() -> None:
Logger.print_status(
"Removing Mobileraker's companion from update manager ..."
)
remove_config_section("update_manager mobileraker", mr_instances)
remove_config_section(MOBILERAKER_UPDATER_SECTION_NAME, mr_instances)
Logger.print_ok(
"Mobileraker's companion successfully removed from update manager!"
)
@@ -199,12 +199,12 @@ def remove_mobileraker() -> None:
def backup_mobileraker_dir() -> None:
bm = BackupManager()
bm.backup_directory(
"mobileraker_companion",
MOBILERAKER_DIR.name,
source=MOBILERAKER_DIR,
target=MOBILERAKER_BACKUP_DIR,
)
bm.backup_directory(
"mobileraker-env",
MOBILERAKER_ENV.name,
source=MOBILERAKER_ENV,
target=MOBILERAKER_BACKUP_DIR,
)

View File

@@ -13,15 +13,21 @@ from core.backup_manager import BACKUP_ROOT_DIR
MODULE_PATH = Path(__file__).resolve().parent
# names
MOONRAKER_CFG_NAME = "moonraker.conf"
MOONRAKER_LOG_NAME = "moonraker.log"
MOONRAKER_SERVICE_NAME = "moonraker.service"
MOONRAKER_DEFAULT_PORT = 7125
MOONRAKER_ENV_FILE_NAME = "moonraker.env"
# directories
MOONRAKER_DIR = Path.home().joinpath("moonraker")
MOONRAKER_ENV_DIR = Path.home().joinpath("moonraker-env")
MOONRAKER_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("moonraker-backups")
MOONRAKER_DB_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("moonraker-db-backups")
MOONRAKER_REQUIREMENTS_TXT = MOONRAKER_DIR.joinpath(
"scripts/moonraker-requirements.txt"
)
DEFAULT_MOONRAKER_PORT = 7125
# files
MOONRAKER_REQ_FILE = MOONRAKER_DIR.joinpath("scripts/moonraker-requirements.txt")
# introduced due to
# https://github.com/Arksine/moonraker/issues/349
# https://github.com/Arksine/moonraker/pull/346
@@ -29,5 +35,8 @@ POLKIT_LEGACY_FILE = Path("/etc/polkit-1/localauthority/50-local.d/10-moonraker.
POLKIT_FILE = Path("/etc/polkit-1/rules.d/moonraker.rules")
POLKIT_USR_FILE = Path("/usr/share/polkit-1/rules.d/moonraker.rules")
POLKIT_SCRIPT = Path.home().joinpath("moonraker/scripts/set-policykit-rules.sh")
MOONRAKER_SERVICE_TEMPLATE = MODULE_PATH.joinpath(f"assets/{MOONRAKER_SERVICE_NAME}")
MOONRAKER_ENV_FILE_TEMPLATE = MODULE_PATH.joinpath(f"assets/{MOONRAKER_ENV_FILE_NAME}")
EXIT_MOONRAKER_SETUP = "Exiting Moonraker setup ..."

View File

@@ -9,15 +9,22 @@
from __future__ import annotations
from pathlib import Path
from subprocess import DEVNULL, CalledProcessError, run
from subprocess import CalledProcessError, run
from typing import List
from components.moonraker import MODULE_PATH, MOONRAKER_DIR, MOONRAKER_ENV_DIR
from components.moonraker import (
MOONRAKER_CFG_NAME,
MOONRAKER_DIR,
MOONRAKER_ENV_DIR,
MOONRAKER_ENV_FILE_NAME,
MOONRAKER_ENV_FILE_TEMPLATE,
MOONRAKER_LOG_NAME,
MOONRAKER_SERVICE_TEMPLATE,
)
from core.instance_manager.base_instance import BaseInstance
from core.submodules.simple_config_parser.src.simple_config_parser.simple_config_parser import (
SimpleConfigParser,
)
from utils.constants import SYSTEMD
from utils.logger import Logger
@@ -31,13 +38,13 @@ class Moonraker(BaseInstance):
super().__init__(instance_type=self, suffix=suffix)
self.moonraker_dir: Path = MOONRAKER_DIR
self.env_dir: Path = MOONRAKER_ENV_DIR
self.cfg_file = self.cfg_dir.joinpath("moonraker.conf")
self.cfg_file = self.cfg_dir.joinpath(MOONRAKER_CFG_NAME)
self.port = self._get_port()
self.backup_dir = self.data_dir.joinpath("backup")
self.certs_dir = self.data_dir.joinpath("certs")
self._db_dir = self.data_dir.joinpath("database")
self._comms_dir = self.data_dir.joinpath("comms")
self.log = self.log_dir.joinpath("moonraker.log")
self.log = self.log_dir.joinpath(MOONRAKER_LOG_NAME)
@property
def db_dir(self) -> Path:
@@ -48,23 +55,20 @@ class Moonraker(BaseInstance):
return self._comms_dir
def create(self, create_example_cfg: bool = False) -> None:
from utils.sys_utils import create_env_file, create_service_file
Logger.print_status("Creating new Moonraker Instance ...")
service_template_path = MODULE_PATH.joinpath("assets/moonraker.service")
service_file_name = self.get_service_file_name(extension=True)
service_file_target = SYSTEMD.joinpath(service_file_name)
env_template_file_path = MODULE_PATH.joinpath("assets/moonraker.env")
env_file_target = self.sysd_dir.joinpath("moonraker.env")
try:
self.create_folders([self.backup_dir, self.certs_dir, self._db_dir])
self._write_service_file(
service_template_path,
service_file_target,
env_file_target,
create_service_file(
name=self.get_service_file_name(extension=True),
content=self._prep_service_file_content(),
)
create_env_file(
path=self.sysd_dir.joinpath(MOONRAKER_ENV_FILE_NAME),
content=self._prep_env_file_content(),
)
self._write_env_file(env_template_file_path, env_file_target)
except CalledProcessError as e:
Logger.print_error(f"Error creating instance: {e}")
@@ -82,72 +86,59 @@ class Moonraker(BaseInstance):
try:
command = ["sudo", "rm", "-f", service_file_path]
run(command, check=True)
self._delete_logfiles()
self.delete_logfiles(MOONRAKER_LOG_NAME)
Logger.print_ok("Instance successfully removed!")
except CalledProcessError as e:
Logger.print_error(f"Error removing instance: {e}")
raise
def _write_service_file(
self,
service_template_path: Path,
service_file_target: Path,
env_file_target: Path,
) -> None:
service_content = self._prep_service_file(
service_template_path, env_file_target
)
command = ["sudo", "tee", service_file_target]
run(
command,
input=service_content.encode(),
stdout=DEVNULL,
check=True,
)
Logger.print_ok(f"Service file created: {service_file_target}")
def _prep_service_file_content(self) -> str:
template = MOONRAKER_SERVICE_TEMPLATE
def _write_env_file(
self, env_template_file_path: Path, env_file_target: Path
) -> None:
env_file_content = self._prep_env_file(env_template_file_path)
with open(env_file_target, "w") as env_file:
env_file.write(env_file_content)
Logger.print_ok(f"Env file created: {env_file_target}")
def _prep_service_file(
self, service_template_path: Path, env_file_path: Path
) -> str:
try:
with open(service_template_path, "r") as template_file:
with open(template, "r") as template_file:
template_content = template_file.read()
except FileNotFoundError:
Logger.print_error(
f"Unable to open {service_template_path} - File not found"
)
Logger.print_error(f"Unable to open {template} - File not found")
raise
service_content = template_content.replace("%USER%", self.user)
service_content = service_content.replace(
"%MOONRAKER_DIR%", str(self.moonraker_dir)
service_content = template_content.replace(
"%USER%",
self.user,
)
service_content = service_content.replace(
"%MOONRAKER_DIR%",
self.moonraker_dir.as_posix(),
)
service_content = service_content.replace(
"%ENV%",
self.env_dir.as_posix(),
)
service_content = service_content.replace(
"%ENV_FILE%",
self.sysd_dir.joinpath(MOONRAKER_ENV_FILE_NAME).as_posix(),
)
service_content = service_content.replace("%ENV%", str(self.env_dir))
service_content = service_content.replace("%ENV_FILE%", str(env_file_path))
return service_content
def _prep_env_file(self, env_template_file_path: Path) -> str:
def _prep_env_file_content(self) -> str:
template = MOONRAKER_ENV_FILE_TEMPLATE
try:
with open(env_template_file_path, "r") as env_file:
with open(template, "r") as env_file:
env_template_file_content = env_file.read()
except FileNotFoundError:
Logger.print_error(
f"Unable to open {env_template_file_path} - File not found"
)
Logger.print_error(f"Unable to open {template} - File not found")
raise
env_file_content = env_template_file_content.replace(
"%MOONRAKER_DIR%", str(self.moonraker_dir)
"%MOONRAKER_DIR%",
self.moonraker_dir.as_posix(),
)
env_file_content = env_file_content.replace(
"%PRINTER_DATA%", str(self.data_dir)
"%PRINTER_DATA%",
self.data_dir.as_posix(),
)
return env_file_content
def _get_port(self) -> int | None:
@@ -159,10 +150,3 @@ class Moonraker(BaseInstance):
port = scp.getint("server", "port", fallback=None)
return port
def _delete_logfiles(self) -> None:
from utils.fs_utils import run_remove_routines
for log in list(self.log_dir.glob("moonraker.log*")):
Logger.print_status(f"Remove '{log}'")
run_remove_routines(log)

View File

@@ -15,7 +15,7 @@ from components.moonraker import (
EXIT_MOONRAKER_SETUP,
MOONRAKER_DIR,
MOONRAKER_ENV_DIR,
MOONRAKER_REQUIREMENTS_TXT,
MOONRAKER_REQ_FILE,
POLKIT_FILE,
POLKIT_LEGACY_FILE,
POLKIT_SCRIPT,
@@ -145,7 +145,7 @@ def setup_moonraker_prerequesites() -> None:
# install moonraker dependencies and create python virtualenv
install_moonraker_packages(MOONRAKER_DIR)
create_python_venv(MOONRAKER_ENV_DIR)
install_python_requirements(MOONRAKER_ENV_DIR, MOONRAKER_REQUIREMENTS_TXT)
install_python_requirements(MOONRAKER_ENV_DIR, MOONRAKER_REQ_FILE)
def install_moonraker_packages(moonraker_dir: Path) -> None:
@@ -206,13 +206,11 @@ def update_moonraker() -> None:
instance_manager = InstanceManager(Moonraker)
instance_manager.stop_all_instance()
git_pull_wrapper(
repo=settings.moonraker.repo_url, target_dir=MOONRAKER_DIR
)
git_pull_wrapper(repo=settings.moonraker.repo_url, target_dir=MOONRAKER_DIR)
# install possible new system packages
install_moonraker_packages(MOONRAKER_DIR)
# install possible new python dependencies
install_python_requirements(MOONRAKER_ENV_DIR, MOONRAKER_REQUIREMENTS_TXT)
install_python_requirements(MOONRAKER_ENV_DIR, MOONRAKER_REQ_FILE)
instance_manager.start_all_instance()

View File

@@ -11,10 +11,10 @@ import shutil
from typing import Dict, List, Optional
from components.moonraker import (
DEFAULT_MOONRAKER_PORT,
MODULE_PATH,
MOONRAKER_BACKUP_DIR,
MOONRAKER_DB_BACKUP_DIR,
MOONRAKER_DEFAULT_PORT,
MOONRAKER_DIR,
MOONRAKER_ENV_DIR,
)
@@ -68,7 +68,7 @@ def create_example_moonraker_conf(
# of moonraker-1 is 7125 and moonraker-3 is 7127 and there are moonraker.conf files for moonraker-1
# and moonraker-3 already. though, there does not seem to be a very reliable way of always assigning
# the correct port to each instance and the user will likely be required to correct the value manually.
port = max(ports) + 1 if ports else DEFAULT_MOONRAKER_PORT
port = max(ports) + 1 if ports else MOONRAKER_DEFAULT_PORT
else:
port = ports_map.get(instance.suffix)

View File

@@ -20,7 +20,7 @@ from components.webui_client.client_dialogs import (
)
from components.webui_client.client_utils import (
backup_client_config_data,
config_for_other_client_exist,
detect_client_cfg_conflict,
)
from core.instance_manager.instance_manager import InstanceManager
from core.settings.kiauh_settings import KiauhSettings
@@ -36,7 +36,7 @@ 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_data.client):
if detect_client_cfg_conflict(client_data):
Logger.print_info("Another Client-Config is already installed! Skipped ...")
return

View File

@@ -28,7 +28,7 @@ from components.webui_client.client_dialogs import (
)
from components.webui_client.client_utils import (
backup_mainsail_config_json,
config_for_other_client_exist,
detect_client_cfg_conflict,
enable_mainsail_remotemode,
restore_mainsail_config_json,
symlink_webui_nginx_log,
@@ -90,7 +90,7 @@ def install_client(client: BaseWebClient) -> None:
if (
kl_instances
and not client_config.config_dir.exists()
and not config_for_other_client_exist(client_to_ignore=client.client)
and not detect_client_cfg_conflict(client)
):
print_install_client_config_dialog(client)
question = f"Download the recommended {client_config.display_name}?"

View File

@@ -8,7 +8,7 @@
# ======================================================================= #
from __future__ import annotations
import json # noqa: I001
import json
import shutil
from pathlib import Path
from typing import List, get_args
@@ -16,9 +16,9 @@ from typing import List, get_args
from components.klipper.klipper import Klipper
from components.webui_client.base_data import (
BaseWebClient,
BaseWebClientConfig,
WebClientType,
)
from components.webui_client.fluidd_data import FluiddData
from components.webui_client.mainsail_data import MainsailData
from core.backup_manager.backup_manager import BackupManager
from core.settings.kiauh_settings import KiauhSettings
@@ -187,30 +187,24 @@ def get_existing_clients() -> List[BaseWebClient]:
return installed_clients
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: WebClientType) -> bool:
def detect_client_cfg_conflict(curr_client: BaseWebClient) -> 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.
Multiple client configs are, at least, redundant to have them installed
:param client_to_ignore: The client name to ignore for the check
:param curr_client: The client name to check for the conflict
: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.value}
mainsail_cfg_status: ComponentStatus = get_client_config_status(MainsailData())
fluidd_cfg_status: ComponentStatus = get_client_config_status(FluiddData())
return True if len(clients) > 0 else False
if curr_client.client == WebClientType.MAINSAIL and fluidd_cfg_status.status == 2:
return True
if curr_client.client == WebClientType.FLUIDD and mainsail_cfg_status.status == 2:
return True
return False
def get_download_url(base_url: str, client: BaseWebClient) -> str:

View File

@@ -18,7 +18,6 @@ from components.webui_client.base_data import (
WebClientConfigType,
WebClientType,
)
from components.webui_client.client_utils import get_download_url
from core.backup_manager import BACKUP_ROOT_DIR
@@ -47,6 +46,8 @@ class FluiddData(BaseWebClient):
@property
def download_url(self) -> str:
from components.webui_client.client_utils import get_download_url
return get_download_url(self.BASE_DL_URL, self)
@property

View File

@@ -14,6 +14,7 @@ from pathlib import Path
from typing import List, Optional
from utils.constants import CURRENT_USER, SYSTEMD
from utils.logger import Logger
class BaseInstance(ABC):
@@ -159,3 +160,12 @@ class BaseInstance(ABC):
return f"printer_{self._suffix}"
else:
return self._suffix
def delete_logfiles(self, log_name: str) -> None:
from utils.fs_utils import run_remove_routines
files = self.log_dir.iterdir()
logs = [f for f in files if f.name.startswith(log_name)]
for log in logs:
Logger.print_status(f"Remove '{log}'")
run_remove_routines(log)

View File

@@ -402,3 +402,39 @@ def log_process(process: Popen) -> None:
if process.poll() is not None:
break
def create_service_file(name: str, content: str) -> None:
"""
Creates a service file at the provided path with the provided content.
:param name: the name of the service file
:param content: the content of the service file
:return: None
"""
try:
run(
["sudo", "tee", SYSTEMD.joinpath(name)],
input=content.encode(),
stdout=DEVNULL,
check=True,
)
Logger.print_ok(f"Service file created: {SYSTEMD.joinpath(name)}")
except CalledProcessError as e:
Logger.print_error(f"Error creating service file: {e}")
raise
def create_env_file(path: Path, content: str) -> None:
"""
Creates an env file at the provided path with the provided content.
:param path: the path of the env file
:param content: the content of the env file
:return: None
"""
try:
with open(path, "w") as env_file:
env_file.write(content)
Logger.print_ok(f"Env file created: {path}")
except OSError as e:
Logger.print_error(f"Error creating env file: {e}")
raise