Compare commits

...

7 Commits

Author SHA1 Message Date
Clifford
372bab8847 feat(gcode_shell_command): allowing for expanding env vars (#747)
allowing for expanding env vars
2025-11-23 12:53:52 +01:00
Charlie Lima
d5062d41de refactor: remove dependency on libatlas-base-dev (#744)
Remove dependency on libatlas-base-dev

Co-authored-by: charlie-lima-bean <ktoaster@pm.me>
2025-11-23 09:25:05 +01:00
dw-0
e9459bd68e fix(backup): correct backup folder path display in menu 2025-11-09 11:58:03 +01:00
dw-0
ee460663c9 fix(spoolman): ensure proper file handling when adding Spoolman entry 2025-10-28 12:12:36 +01:00
dw-0
6f0e0146ef fix(client): improve version retrieval logic and handle JSON errors 2025-10-27 19:00:08 +01:00
dw-0
229f317025 fix(backup): do not create redundant subdirectory on single file backup 2025-10-27 09:47:09 +01:00
dw-0
48c0ae7227 fix(backup): allow reusing existing backup directory and enhance copy options 2025-10-27 09:30:33 +01:00
6 changed files with 59 additions and 25 deletions

View File

@@ -237,7 +237,6 @@ def install_input_shaper_deps() -> None:
"If you agree, the following additional system packages will be installed:", "If you agree, the following additional system packages will be installed:",
"● python3-numpy", "● python3-numpy",
"● python3-matplotlib", "● python3-matplotlib",
"● libatlas-base-dev",
"● libopenblas-dev", "● libopenblas-dev",
"\n\n", "\n\n",
"Also, the following Python package will be installed:", "Also, the following Python package will be installed:",
@@ -253,7 +252,6 @@ def install_input_shaper_deps() -> None:
apt_deps = ( apt_deps = (
"python3-numpy", "python3-numpy",
"python3-matplotlib", "python3-matplotlib",
"libatlas-base-dev",
"libopenblas-dev", "libopenblas-dev",
) )
check_install_dependencies({*apt_deps}) check_install_dependencies({*apt_deps})

View File

@@ -11,6 +11,7 @@ from __future__ import annotations
import json import json
import re import re
import shutil import shutil
from json import JSONDecodeError
from pathlib import Path from pathlib import Path
from subprocess import PIPE, CalledProcessError, run from subprocess import PIPE, CalledProcessError, run
from typing import List, get_args from typing import List, get_args
@@ -151,18 +152,36 @@ def symlink_webui_nginx_log(
def get_local_client_version(client: BaseWebClient) -> str | None: def get_local_client_version(client: BaseWebClient) -> str | None:
relinfo_file = client.client_dir.joinpath("release_info.json") relinfo_file = client.client_dir.joinpath("release_info.json")
version_file = client.client_dir.joinpath(".version") version_file = client.client_dir.joinpath(".version")
default = "n/a"
if not client.client_dir.exists(): if not client.client_dir.exists():
return None return default
if not relinfo_file.is_file() and not version_file.is_file():
return "n/a"
# try to get version from release_info.json first
if relinfo_file.is_file(): if relinfo_file.is_file():
with open(relinfo_file, "r") as f: try:
return str(json.load(f)["version"]) if relinfo_file.stat().st_size == 0:
else: raise JSONDecodeError("Empty file", "", 0)
with open(version_file, "r") as f: with open(relinfo_file, "r", encoding="utf-8") as f:
return f.readlines()[0] data = json.load(f)
raw_version = data.get("version")
if raw_version is not None:
parsed = str(raw_version).strip()
if parsed:
return parsed
except (JSONDecodeError, OSError):
Logger.print_error("Invalid 'release_info.json'")
# fallback to .version file
if version_file.is_file():
try:
with open(version_file, "r") as f:
line = f.readline().strip()
return line or default
except OSError:
Logger.print_error("Unable to read '.version'")
return default
def get_remote_client_version(client: BaseWebClient) -> str | None: def get_remote_client_version(client: BaseWebClient) -> str | None:

View File

@@ -58,7 +58,7 @@ class BackupMenu(BaseMenu):
def print_menu(self) -> None: def print_menu(self) -> None:
line1 = Color.apply( line1 = Color.apply(
"INFO: Backups are located in '~/kiauh-backups'", Color.YELLOW "INFO: Backups are located in '~/kiauh_backups'", Color.YELLOW
) )
menu = textwrap.dedent( menu = textwrap.dedent(
f""" f"""

View File

@@ -62,16 +62,16 @@ class BackupService:
target_name target_name
or f"{source_path.stem}_{self.timestamp}{source_path.suffix}" or f"{source_path.stem}_{self.timestamp}{source_path.suffix}"
) )
if target_path is not None:
backup_path = self._backup_root.joinpath(target_path, filename)
else:
backup_path = self._backup_root.joinpath(filename)
backup_path.mkdir(parents=True, exist_ok=True) backup_dir = self._backup_root
shutil.copy2(source_path, backup_path) if target_path is not None:
backup_dir = self._backup_root.joinpath(target_path)
backup_dir.mkdir(parents=True, exist_ok=True)
shutil.copy2(source_path, backup_dir.joinpath(filename))
Logger.print_ok( Logger.print_ok(
f"Successfully backed up '{source_path}' to '{backup_path}'" f"Successfully backed up '{source_path}' to '{backup_dir}'"
) )
return True return True
@@ -109,7 +109,16 @@ class BackupService:
else: else:
backup_path = self._backup_root.joinpath(backup_dir_name) backup_path = self._backup_root.joinpath(backup_dir_name)
shutil.copytree(source_path, backup_path) if backup_path.exists():
Logger.print_info(f"Reusing existing backup directory '{backup_path}'")
shutil.copytree(
source_path,
backup_path,
dirs_exist_ok=True,
symlinks=True,
ignore_dangling_symlinks=True,
)
Logger.print_ok( Logger.print_ok(
f"Successfully backed up '{source_path}' to '{backup_path}'" f"Successfully backed up '{source_path}' to '{backup_path}'"

View File

@@ -16,6 +16,7 @@ class ShellCommand:
self.gcode = self.printer.lookup_object("gcode") self.gcode = self.printer.lookup_object("gcode")
cmd = config.get("command") cmd = config.get("command")
cmd = os.path.expanduser(cmd) cmd = os.path.expanduser(cmd)
cmd = os.path.expandvars(cmd)
self.command = shlex.split(cmd) self.command = shlex.split(cmd)
self.timeout = config.getfloat("timeout", 2.0, above=0.0) self.timeout = config.getfloat("timeout", 2.0, above=0.0)
self.verbose = config.getboolean("verbose", True) self.verbose = config.getboolean("verbose", True)

View File

@@ -8,6 +8,7 @@
# ======================================================================= # # ======================================================================= #
import re import re
from pathlib import Path
from subprocess import CalledProcessError, run from subprocess import CalledProcessError, run
from typing import List, Tuple from typing import List, Tuple
@@ -311,13 +312,19 @@ class SpoolmanExtension(BaseExtension):
mrsvc.load_instances() mrsvc.load_instances()
mr_instances = mrsvc.get_all_instances() mr_instances = mrsvc.get_all_instances()
for instance in mr_instances: for instance in mr_instances:
asvc_path = instance.data_dir.joinpath("moonraker.asvc") asvc_path: Path = instance.data_dir.joinpath("moonraker.asvc")
if asvc_path.exists(): if asvc_path.exists() and asvc_path.is_file():
if "Spoolman" in open(asvc_path).read(): with open(asvc_path, "a+") as f:
Logger.print_info(f"Spoolman already in {asvc_path}. Skipping...") if "Spoolman" in f.read():
continue Logger.print_info(
f"Spoolman already in {asvc_path}. Skipping..."
)
continue
content: List[str] = f.readlines()
if content and not content[-1].endswith("\n"):
f.write("\n")
with open(asvc_path, "a") as f:
f.write("Spoolman\n") f.write("Spoolman\n")
Logger.print_ok(f"Spoolman added to {asvc_path}!") Logger.print_ok(f"Spoolman added to {asvc_path}!")