diff --git a/kiauh/__init__.py b/kiauh/__init__.py index 3a58dc0..91fd073 100644 --- a/kiauh/__init__.py +++ b/kiauh/__init__.py @@ -13,4 +13,3 @@ from pathlib import Path APPLICATION_ROOT = Path(__file__).resolve().parent.parent KIAUH_CFG = APPLICATION_ROOT.joinpath("kiauh.cfg") -KIAUH_BACKUP_DIR = Path.home().joinpath("kiauh-backups") diff --git a/kiauh/components/klipper/__init__.py b/kiauh/components/klipper/__init__.py index 6b87989..ff3ae20 100644 --- a/kiauh/components/klipper/__init__.py +++ b/kiauh/components/klipper/__init__.py @@ -11,10 +11,13 @@ from pathlib import Path +from kiauh.core.backup_manager import BACKUP_ROOT_DIR + MODULE_PATH = Path(__file__).resolve().parent 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") DEFAULT_KLIPPER_REPO_URL = "https://github.com/Klipper3D/klipper" diff --git a/kiauh/components/klipper/klipper_setup.py b/kiauh/components/klipper/klipper_setup.py index bed720d..05cfb1c 100644 --- a/kiauh/components/klipper/klipper_setup.py +++ b/kiauh/components/klipper/klipper_setup.py @@ -12,16 +12,13 @@ from pathlib import Path from kiauh import KIAUH_CFG -from kiauh.core.backup_manager.backup_manager import BackupManager -from kiauh.core.config_manager.config_manager import ConfigManager -from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.components.klipper import ( EXIT_KLIPPER_SETUP, DEFAULT_KLIPPER_REPO_URL, KLIPPER_DIR, KLIPPER_ENV_DIR, KLIPPER_REQUIREMENTS_TXT, -) + ) from kiauh.components.klipper.klipper import Klipper from kiauh.components.klipper.klipper_dialogs import print_update_warn_dialog from kiauh.components.klipper.klipper_utils import ( @@ -35,9 +32,12 @@ from kiauh.components.klipper.klipper_utils import ( check_is_single_to_multi_conversion, update_name_scheme, handle_instance_naming, -) -from kiauh.core.repo_manager.repo_manager import RepoManager + backup_klipper_dir, + ) from kiauh.components.moonraker.moonraker import Moonraker +from kiauh.core.config_manager.config_manager import ConfigManager +from kiauh.core.instance_manager.instance_manager import InstanceManager +from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.utils.input_utils import get_confirm from kiauh.utils.logger import Logger from kiauh.utils.system_utils import ( @@ -46,7 +46,7 @@ from kiauh.utils.system_utils import ( install_python_requirements, update_system_package_lists, install_system_packages, -) + ) def install_klipper() -> None: @@ -149,9 +149,7 @@ def update_klipper() -> None: cm = ConfigManager(cfg_file=KIAUH_CFG) if cm.get_value("kiauh", "backup_before_update"): - bm = BackupManager() - bm.backup_directory("klipper", KLIPPER_DIR) - bm.backup_directory("klippy-env", KLIPPER_ENV_DIR) + backup_klipper_dir() instance_manager = InstanceManager(Klipper) instance_manager.stop_all_instance() diff --git a/kiauh/components/klipper/klipper_utils.py b/kiauh/components/klipper/klipper_utils.py index f49cdec..373afc3 100644 --- a/kiauh/components/klipper/klipper_utils.py +++ b/kiauh/components/klipper/klipper_utils.py @@ -9,31 +9,36 @@ # This file may be distributed under the terms of the GNU GPLv3 license # # ======================================================================= # +import grp import os import re -import grp import shutil import subprocess import textwrap from pathlib import Path - from typing import List, Union, Literal, Dict -from kiauh.core.config_manager.config_manager import ConfigManager -from kiauh.core.instance_manager.base_instance import BaseInstance -from kiauh.core.instance_manager.instance_manager import InstanceManager -from kiauh.core.instance_manager.name_scheme import NameScheme -from kiauh.core.repo_manager.repo_manager import RepoManager -from kiauh.components.klipper import MODULE_PATH, KLIPPER_DIR, KLIPPER_ENV_DIR +from kiauh.components.klipper import ( + MODULE_PATH, + KLIPPER_DIR, + KLIPPER_ENV_DIR, + KLIPPER_BACKUP_DIR, + ) from kiauh.components.klipper.klipper import Klipper from kiauh.components.klipper.klipper_dialogs import ( print_missing_usergroup_dialog, print_instance_overview, print_select_instance_count_dialog, print_select_custom_name_dialog, -) + ) from kiauh.components.moonraker.moonraker import Moonraker from kiauh.components.moonraker.moonraker_utils import moonraker_to_multi_conversion +from kiauh.core.backup_manager.backup_manager import BackupManager +from kiauh.core.config_manager.config_manager import ConfigManager +from kiauh.core.instance_manager.base_instance import BaseInstance +from kiauh.core.instance_manager.instance_manager import InstanceManager +from kiauh.core.instance_manager.name_scheme import NameScheme +from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.utils.common import get_install_status_common from kiauh.utils.constants import CURRENT_USER from kiauh.utils.input_utils import get_confirm, get_string_input, get_number_input @@ -276,3 +281,9 @@ def create_example_printer_cfg(instance: Klipper) -> None: cm.set_value("virtual_sdcard", "path", str(instance.gcodes_dir)) cm.write_config() Logger.print_ok(f"Example printer.cfg created in '{instance.cfg_dir}'") + + +def backup_klipper_dir() -> None: + bm = BackupManager() + bm.backup_directory("klipper", source=KLIPPER_DIR, target=KLIPPER_BACKUP_DIR) + bm.backup_directory("klippy-env", source=KLIPPER_ENV_DIR, target=KLIPPER_BACKUP_DIR) diff --git a/kiauh/components/mainsail/__init__.py b/kiauh/components/mainsail/__init__.py index 9c01f87..0b2d2af 100644 --- a/kiauh/components/mainsail/__init__.py +++ b/kiauh/components/mainsail/__init__.py @@ -11,10 +11,13 @@ from pathlib import Path +from kiauh.core.backup_manager import BACKUP_ROOT_DIR + MODULE_PATH = Path(__file__).resolve().parent -MAINSAIL_DIR = Path(Path.home(), "mainsail") -MAINSAIL_CONFIG_DIR = Path(Path.home(), "mainsail-config") -MAINSAIL_CONFIG_JSON = Path(MAINSAIL_DIR, "config.json") +MAINSAIL_DIR = Path.home().joinpath("mainsail") +MAINSAIL_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("mainsail-backups") +MAINSAIL_CONFIG_DIR = Path.home().joinpath("mainsail-config") +MAINSAIL_CONFIG_JSON = MAINSAIL_DIR.joinpath("config.json") MAINSAIL_URL = ( "https://github.com/mainsail-crew/mainsail/releases/latest/download/mainsail.zip" ) diff --git a/kiauh/components/mainsail/mainsail_utils.py b/kiauh/components/mainsail/mainsail_utils.py index de54941..9a01e9d 100644 --- a/kiauh/components/mainsail/mainsail_utils.py +++ b/kiauh/components/mainsail/mainsail_utils.py @@ -11,13 +11,18 @@ import json import shutil -import requests from pathlib import Path from typing import List -from kiauh.core.backup_manager.backup_manager import BackupManager +import requests + from kiauh.components.klipper.klipper import Klipper -from kiauh.components.mainsail import MAINSAIL_CONFIG_JSON, MAINSAIL_DIR +from kiauh.components.mainsail import ( + MAINSAIL_CONFIG_JSON, + MAINSAIL_DIR, + MAINSAIL_BACKUP_DIR, + ) +from kiauh.core.backup_manager.backup_manager import BackupManager from kiauh.utils import NGINX_SITES_AVAILABLE, NGINX_CONFD from kiauh.utils.common import get_install_status_webui from kiauh.utils.logger import Logger @@ -97,3 +102,12 @@ def get_mainsail_remote_version() -> str: response = requests.get(url) data = json.loads(response.text) return data[0]["name"] + + +def backup_mainsail_data() -> None: + with open(MAINSAIL_DIR.joinpath(".version"), "r") as v: + version = v.readlines()[0] + bm = BackupManager() + bm.backup_directory(f"mainsail-{version}", MAINSAIL_DIR, MAINSAIL_BACKUP_DIR) + bm.backup_file(MAINSAIL_CONFIG_JSON, MAINSAIL_BACKUP_DIR) + bm.backup_file(NGINX_SITES_AVAILABLE.joinpath("mainsail"), MAINSAIL_BACKUP_DIR) diff --git a/kiauh/components/moonraker/__init__.py b/kiauh/components/moonraker/__init__.py index 14cdac0..e42f3e9 100644 --- a/kiauh/components/moonraker/__init__.py +++ b/kiauh/components/moonraker/__init__.py @@ -11,10 +11,14 @@ from pathlib import Path +from kiauh.core.backup_manager import BACKUP_ROOT_DIR + MODULE_PATH = Path(__file__).resolve().parent 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" ) diff --git a/kiauh/components/moonraker/moonraker.py b/kiauh/components/moonraker/moonraker.py index f33d039..c2a9d29 100644 --- a/kiauh/components/moonraker/moonraker.py +++ b/kiauh/components/moonraker/moonraker.py @@ -13,9 +13,9 @@ import subprocess from pathlib import Path from typing import List, Union +from kiauh.components.moonraker import MOONRAKER_DIR, MOONRAKER_ENV_DIR, MODULE_PATH from kiauh.core.config_manager.config_manager import ConfigManager from kiauh.core.instance_manager.base_instance import BaseInstance -from kiauh.components.moonraker import MOONRAKER_DIR, MOONRAKER_ENV_DIR, MODULE_PATH from kiauh.utils.constants import SYSTEMD from kiauh.utils.logger import Logger @@ -34,9 +34,13 @@ class Moonraker(BaseInstance): 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._db_dir = self.data_dir.joinpath("database") self.log = self.log_dir.joinpath("moonraker.log") + @property + def db_dir(self) -> Path: + return self._db_dir + def create(self, create_example_cfg: bool = False) -> None: Logger.print_status("Creating new Moonraker Instance ...") service_template_path = MODULE_PATH.joinpath("assets/moonraker.service") @@ -46,7 +50,7 @@ class Moonraker(BaseInstance): env_file_target = self.sysd_dir.joinpath("moonraker.env") try: - self.create_folders([self.backup_dir, self.certs_dir, self.db_dir]) + 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 ) diff --git a/kiauh/components/moonraker/moonraker_setup.py b/kiauh/components/moonraker/moonraker_setup.py index 066d627..9ed8fa0 100644 --- a/kiauh/components/moonraker/moonraker_setup.py +++ b/kiauh/components/moonraker/moonraker_setup.py @@ -15,12 +15,8 @@ from pathlib import Path from typing import List from kiauh import KIAUH_CFG -from kiauh.core.backup_manager.backup_manager import BackupManager -from kiauh.core.config_manager.config_manager import ConfigManager -from kiauh.core.instance_manager.instance_manager import InstanceManager from kiauh.components.klipper.klipper import Klipper from kiauh.components.klipper.klipper_dialogs import print_instance_overview -from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.components.mainsail import MAINSAIL_DIR from kiauh.components.mainsail.mainsail_utils import enable_mainsail_remotemode from kiauh.components.moonraker import ( @@ -33,15 +29,21 @@ from kiauh.components.moonraker import ( POLKIT_FILE, POLKIT_USR_FILE, POLKIT_SCRIPT, -) + ) from kiauh.components.moonraker.moonraker import Moonraker from kiauh.components.moonraker.moonraker_dialogs import print_moonraker_overview -from kiauh.components.moonraker.moonraker_utils import create_example_moonraker_conf +from kiauh.components.moonraker.moonraker_utils import ( + create_example_moonraker_conf, + backup_moonraker_dir, + ) +from kiauh.core.config_manager.config_manager import ConfigManager +from kiauh.core.instance_manager.instance_manager import InstanceManager +from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.utils.filesystem_utils import check_file_exist from kiauh.utils.input_utils import ( get_confirm, get_selection_input, -) + ) from kiauh.utils.logger import Logger from kiauh.utils.system_utils import ( parse_packages_from_file, @@ -49,7 +51,7 @@ from kiauh.utils.system_utils import ( install_python_requirements, update_system_package_lists, install_system_packages, -) + ) def install_moonraker() -> None: @@ -206,9 +208,7 @@ def update_moonraker() -> None: cm = ConfigManager(cfg_file=KIAUH_CFG) if cm.get_value("kiauh", "backup_before_update"): - bm = BackupManager() - bm.backup_directory("moonraker", MOONRAKER_DIR) - bm.backup_directory("moonraker-env", MOONRAKER_ENV_DIR) + backup_moonraker_dir() instance_manager = InstanceManager(Moonraker) instance_manager.stop_all_instance() diff --git a/kiauh/components/moonraker/moonraker_utils.py b/kiauh/components/moonraker/moonraker_utils.py index 017e00a..e3db3c6 100644 --- a/kiauh/components/moonraker/moonraker_utils.py +++ b/kiauh/components/moonraker/moonraker_utils.py @@ -12,9 +12,6 @@ import shutil from typing import Dict, Literal, List, Union -from kiauh.core.config_manager.config_manager import ConfigManager -from kiauh.core.instance_manager.instance_manager import InstanceManager -from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.components.mainsail import MAINSAIL_DIR from kiauh.components.mainsail.mainsail_utils import enable_mainsail_remotemode from kiauh.components.moonraker import ( @@ -22,13 +19,19 @@ from kiauh.components.moonraker import ( MODULE_PATH, MOONRAKER_DIR, MOONRAKER_ENV_DIR, -) + MOONRAKER_BACKUP_DIR, + MOONRAKER_DB_BACKUP_DIR, + ) from kiauh.components.moonraker.moonraker import Moonraker +from kiauh.core.backup_manager.backup_manager import BackupManager +from kiauh.core.config_manager.config_manager import ConfigManager +from kiauh.core.instance_manager.instance_manager import InstanceManager +from kiauh.core.repo_manager.repo_manager import RepoManager from kiauh.utils.common import get_install_status_common from kiauh.utils.logger import Logger from kiauh.utils.system_utils import ( get_ipv4_addr, -) + ) def get_moonraker_status() -> ( @@ -132,3 +135,23 @@ def moonraker_to_multi_conversion(new_name: str) -> None: # if mainsail is installed, we enable mainsails remote mode if MAINSAIL_DIR.exists() and len(im.instances) > 1: enable_mainsail_remotemode() + + +def backup_moonraker_dir(): + bm = BackupManager() + bm.backup_directory("moonraker", source=MOONRAKER_DIR, target=MOONRAKER_BACKUP_DIR) + bm.backup_directory( + "moonraker-env", source=MOONRAKER_ENV_DIR, target=MOONRAKER_BACKUP_DIR + ) + + +def backup_moonraker_db_dir() -> None: + im = InstanceManager(Moonraker) + instances: List[Moonraker] = im.instances + bm = BackupManager() + + for instance in instances: + name = f"database-{instance.data_dir_name}" + bm.backup_directory( + name, source=instance.db_dir, target=MOONRAKER_DB_BACKUP_DIR + ) diff --git a/kiauh/core/backup_manager/__init__.py b/kiauh/core/backup_manager/__init__.py index e69de29..7bbbe1e 100644 --- a/kiauh/core/backup_manager/__init__.py +++ b/kiauh/core/backup_manager/__init__.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python3 + +# ======================================================================= # +# Copyright (C) 2020 - 2024 Dominik Willner # +# # +# This file is part of KIAUH - Klipper Installation And Update Helper # +# https://github.com/dw-0/kiauh # +# # +# This file may be distributed under the terms of the GNU GPLv3 license # +# ======================================================================= # + +from pathlib import Path + +BACKUP_ROOT_DIR = Path.home().joinpath("kiauh-backups") diff --git a/kiauh/core/menus/backup_menu.py b/kiauh/core/menus/backup_menu.py new file mode 100644 index 0000000..ffc246b --- /dev/null +++ b/kiauh/core/menus/backup_menu.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python3 + +# ======================================================================= # +# Copyright (C) 2020 - 2024 Dominik Willner # +# # +# This file is part of KIAUH - Klipper Installation And Update Helper # +# https://github.com/dw-0/kiauh # +# # +# This file may be distributed under the terms of the GNU GPLv3 license # +# ======================================================================= # + +import textwrap + +from kiauh.components.klipper.klipper_utils import backup_klipper_dir +from kiauh.components.mainsail.mainsail_utils import backup_mainsail_data +from kiauh.components.moonraker.moonraker_utils import ( + backup_moonraker_dir, + backup_moonraker_db_dir, + ) +from kiauh.core.menus import BACK_FOOTER +from kiauh.core.menus.base_menu import BaseMenu +from kiauh.utils.common import backup_printer_config_dir +from kiauh.utils.constants import COLOR_CYAN, RESET_FORMAT, COLOR_YELLOW + + +# noinspection PyUnusedLocal +# noinspection PyMethodMayBeStatic +class BackupMenu(BaseMenu): + def __init__(self): + super().__init__( + header=True, + options={ + "1": self.backup_klipper, + "2": self.backup_moonraker, + "3": self.backup_printer_config, + "4": self.backup_moonraker_db, + "5": self.backup_mainsail + }, + footer_type=BACK_FOOTER, + ) + + def print_menu(self): + header = " [ Backup Menu ] " + line1 = f"{COLOR_YELLOW}INFO: Backups are located in '~/kiauh-backups'{RESET_FORMAT}" + color = COLOR_CYAN + count = 62 - len(color) - len(RESET_FORMAT) + menu = textwrap.dedent( + f""" + /=======================================================\\ + | {color}{header:~^{count}}{RESET_FORMAT} | + |-------------------------------------------------------| + | {line1:^62} | + |-------------------------------------------------------| + | Klipper & Moonraker API: | Touchscreen GUI: | + | 1) [Klipper] | 7) [KlipperScreen] | + | 2) [Moonraker] | | + | 3) [Config Folder] | Other: | + | 4) [Moonraker Database] | 9) [Telegram Bot] | + | | | + | Klipper Webinterface: | | + | 5) [Mainsail] | | + | 6) [Fluidd] | | + """ + )[1:] + print(menu, end="") + + def backup_klipper(self, **kwargs): + backup_klipper_dir() + + def backup_moonraker(self, **kwargs): + backup_moonraker_dir() + + def backup_printer_config(self, **kwargs): + backup_printer_config_dir() + + def backup_moonraker_db(self, **kwargs): + backup_moonraker_db_dir() + + def backup_mainsail(self, **kwargs): + backup_mainsail_data() + + def backup_fluidd(self, **kwargs): + pass + + def backup_klipperscreen(self, **kwargs): + pass + + def backup_telegram_bot(self, **kwargs): + pass diff --git a/kiauh/core/menus/main_menu.py b/kiauh/core/menus/main_menu.py index 366b99a..14c80cc 100644 --- a/kiauh/core/menus/main_menu.py +++ b/kiauh/core/menus/main_menu.py @@ -11,18 +11,19 @@ import textwrap +from kiauh.components.klipper.klipper_utils import get_klipper_status +from kiauh.components.log_uploads.menus.log_upload_menu import LogUploadMenu +from kiauh.components.mainsail.mainsail_utils import get_mainsail_status +from kiauh.components.moonraker.moonraker_utils import get_moonraker_status from kiauh.core.menus import QUIT_FOOTER from kiauh.core.menus.advanced_menu import AdvancedMenu +from kiauh.core.menus.backup_menu import BackupMenu from kiauh.core.menus.base_menu import BaseMenu from kiauh.core.menus.extensions_menu import ExtensionsMenu from kiauh.core.menus.install_menu import InstallMenu from kiauh.core.menus.remove_menu import RemoveMenu from kiauh.core.menus.settings_menu import SettingsMenu from kiauh.core.menus.update_menu import UpdateMenu -from kiauh.components.klipper.klipper_utils import get_klipper_status -from kiauh.components.log_uploads.menus.log_upload_menu import LogUploadMenu -from kiauh.components.mainsail.mainsail_utils import get_mainsail_status -from kiauh.components.moonraker.moonraker_utils import get_moonraker_status from kiauh.utils.constants import ( COLOR_MAGENTA, COLOR_CYAN, @@ -30,9 +31,10 @@ from kiauh.utils.constants import ( COLOR_RED, COLOR_GREEN, COLOR_YELLOW, -) + ) +# noinspection PyMethodMayBeStatic class MainMenu(BaseMenu): def __init__(self): super().__init__( @@ -43,7 +45,7 @@ class MainMenu(BaseMenu): "2": UpdateMenu, "3": RemoveMenu, "4": AdvancedMenu, - "5": None, + "5": BackupMenu, "e": ExtensionsMenu, "s": SettingsMenu, }, diff --git a/kiauh/utils/__init__.py b/kiauh/utils/__init__.py index f097b5d..319fc15 100644 --- a/kiauh/utils/__init__.py +++ b/kiauh/utils/__init__.py @@ -11,8 +11,11 @@ from pathlib import Path +from kiauh.core.backup_manager import BACKUP_ROOT_DIR + MODULE_PATH = Path(__file__).resolve().parent INVALID_CHOICE = "Invalid choice. Please select a valid value." +PRINTER_CFG_BACKUP_DIR = BACKUP_ROOT_DIR.joinpath("printer-cfg-backups") # ================== NGINX =====================# NGINX_SITES_AVAILABLE = Path("/etc/nginx/sites-available") diff --git a/kiauh/utils/common.py b/kiauh/utils/common.py index fbae241..222b58d 100644 --- a/kiauh/utils/common.py +++ b/kiauh/utils/common.py @@ -13,15 +13,17 @@ from datetime import datetime from pathlib import Path from typing import Dict, Literal, List, Type, Union +from kiauh.components.klipper.klipper import Klipper from kiauh.core.instance_manager.base_instance import BaseInstance from kiauh.core.instance_manager.instance_manager import InstanceManager +from kiauh.utils import PRINTER_CFG_BACKUP_DIR from kiauh.utils.constants import ( COLOR_CYAN, RESET_FORMAT, COLOR_YELLOW, COLOR_GREEN, COLOR_RED, -) + ) from kiauh.utils.filesystem_utils import check_file_exist from kiauh.utils.logger import Logger from kiauh.utils.system_utils import check_package_install, install_system_packages @@ -116,3 +118,20 @@ def get_install_status_webui( return f"{COLOR_RED}Not installed!{RESET_FORMAT}" else: return f"{COLOR_YELLOW}Incomplete!{RESET_FORMAT}" + + +def backup_printer_config_dir(): + # local import to prevent circular import + from kiauh.core.backup_manager.backup_manager import BackupManager + + im = InstanceManager(Klipper) + instances: List[Klipper] = im.instances + bm = BackupManager() + + for instance in instances: + name = f"config-{instance.data_dir_name}" + bm.backup_directory( + name, + source=instance.cfg_dir, + target=PRINTER_CFG_BACKUP_DIR, + )