- Centralizes backup content view logic into a single BackupContentFrame. - Removes the separate, now obsolete EncryptedBackupContentFrame. - Adds a toggle button within the BackupContentFrame to switch between viewing normal and encrypted backups. - Centralizes the Restore, Delete, and Edit Comment buttons into a single button bar in BackupContentFrame. - Corrects the path resolution logic to find backups and encrypted containers within the /pybackup subdirectory. - Fixes UI bugs where action buttons would disappear when switching tabs.
357 lines
15 KiB
Python
357 lines
15 KiB
Python
from pathlib import Path
|
|
from typing import Dict, Any
|
|
|
|
# Assuming the Translate class exists in shared_libs as per the template
|
|
from shared_libs.common_tools import Translate
|
|
|
|
|
|
class AppConfig:
|
|
"""Central configuration and system setup manager for PyImage Backup."""
|
|
|
|
# --- Core Paths ---
|
|
BASE_DIR: Path = Path.home()
|
|
CONFIG_DIR: Path = BASE_DIR / ".config/lx_pyimage"
|
|
SETTINGS_FILE: Path = CONFIG_DIR / "settings.json"
|
|
GENERATED_EXCLUDE_LIST_PATH: Path = CONFIG_DIR / "rsync-generated-excludes.conf"
|
|
USER_EXCLUDE_LIST_PATH: Path = CONFIG_DIR / \
|
|
"rsync-user-excludes.conf" # Single file
|
|
MANUAL_EXCLUDE_LIST_PATH: Path = CONFIG_DIR / \
|
|
"rsync-manual-excludes.conf" # Single file
|
|
APP_ICONS_DIR: Path = Path(__file__).parent / "lx-icons"
|
|
|
|
# --- Application Info ---
|
|
VERSION: str = "v.1.0.0"
|
|
UPDATE_URL: str = "" # To be defined later
|
|
|
|
# --- UI Configuration ---
|
|
UI_CONFIG: Dict[str, Any] = {
|
|
"window_title": "PyBackup",
|
|
"window_size": "1200x800",
|
|
"font_family": "Ubuntu",
|
|
"font_size": 11,
|
|
}
|
|
|
|
@staticmethod
|
|
def _get_user_dirs() -> Dict[str, Path]:
|
|
"""
|
|
Parses ~/.config/user-dirs.dirs to get localized user folder paths.
|
|
"""
|
|
user_dirs_path = Path.home() / ".config/user-dirs.dirs"
|
|
user_dirs = {}
|
|
if user_dirs_path.exists():
|
|
try:
|
|
with open(user_dirs_path, 'r') as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if line and not line.startswith('#') and '=' in line:
|
|
key, value = line.split('=', 1)
|
|
value = value.strip().strip('"')
|
|
if value.startswith("$HOME"):
|
|
value = value.replace(
|
|
"$HOME", str(Path.home()))
|
|
user_dirs[key] = Path(value)
|
|
except Exception:
|
|
# In case of any error, just return empty dict
|
|
return {}
|
|
return user_dirs
|
|
|
|
user_dirs = _get_user_dirs.__func__()
|
|
|
|
# --- Folder Paths ---
|
|
FOLDER_PATHS: Dict[str, Path] = {
|
|
"Computer": Path("/"),
|
|
"Documents": user_dirs.get("XDG_DOCUMENTS_DIR", Path.home() / "Documents"),
|
|
"Pictures": user_dirs.get("XDG_PICTURES_DIR", Path.home() / "Pictures"),
|
|
"Music": user_dirs.get("XDG_MUSIC_DIR", Path.home() / "Music"),
|
|
"Videos": user_dirs.get("XDG_VIDEOS_DIR", Path.home() / "Videos"),
|
|
}
|
|
|
|
STANDARD_EXCLUDE_CONTENT = """/dev/*
|
|
/proc/*
|
|
/sys/*
|
|
/media/*
|
|
/mnt/*
|
|
**/tmp/
|
|
/run/*
|
|
/var/run/*
|
|
/var/lock/*
|
|
/var/lib/docker/*
|
|
/var/lib/libvirt/images/*
|
|
/var/lib/schroot/*
|
|
/data/*
|
|
/DATA/*
|
|
/cdrom/*
|
|
/sdcard/*
|
|
/lost+found
|
|
/swapfile
|
|
/system/*
|
|
**/root/.gvfs
|
|
/snap/*
|
|
/home/*/.gvfs
|
|
/home/*/.cache/*
|
|
/var/cache/pacman/pkg/*
|
|
/var/cache/apt/archives/*
|
|
/var/cache/yum/*
|
|
/var/cache/dnf/*
|
|
/var/cache/eopkg/*
|
|
/var/cache/xbps/*
|
|
/var/cache/zypp/*
|
|
/var/cache/edb/*
|
|
/home/*/.local/share/gnome_boxes/
|
|
/home/*/leagueoflegends/
|
|
/home/*/.local/share/leagueoflegends/
|
|
/home/*/.config/lutris/
|
|
/home/*/.local/share/lutris/
|
|
/home/*/.minecraft
|
|
/home/*/.thunderbird
|
|
/home/*/.minetest
|
|
/home/*/.steam
|
|
/home/*/.local/share/Steam/
|
|
/home/*/.local/share/supertux2/
|
|
/home/*/.local/share/supertuxkart/
|
|
/home/*/.cache/supertuxkart/
|
|
/home/*/.config/supertuxkart/
|
|
/home/*/.local/share/applications/wine/
|
|
/home/*/.wine/
|
|
/home/*/rsynclog
|
|
/home/*/rsynclog.old
|
|
/home/*/.local/share/[Tt]rash
|
|
/home/*/.opera/cache
|
|
/home/*/.kde/share/apps/kio_http/cache
|
|
/home/*/.kde/share/cache/http
|
|
/home/*/.var/*
|
|
/home/*/.lmstudio"""
|
|
|
|
@classmethod
|
|
def ensure_directories(cls) -> None:
|
|
"""Ensures that all required application directories exist."""
|
|
if not cls.CONFIG_DIR.exists():
|
|
cls.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
|
# In the future, we can create a default settings file here
|
|
|
|
# Generate/update the final exclude list on every start
|
|
cls.generate_and_write_final_exclude_list()
|
|
|
|
# Create default user excludes only if the file doesn't exist
|
|
if not cls.USER_EXCLUDE_LIST_PATH.exists():
|
|
cls.create_default_user_excludes()
|
|
|
|
@classmethod
|
|
def create_default_user_excludes(cls) -> None:
|
|
"""
|
|
Creates the user exclude file with default entries (visible home folders).
|
|
Overwrites the file if it exists.
|
|
"""
|
|
home_dir = Path.home()
|
|
try:
|
|
with open(cls.USER_EXCLUDE_LIST_PATH, 'w') as f:
|
|
for item in home_dir.iterdir():
|
|
if item.is_dir() and not item.name.startswith('.'):
|
|
f.write(f"{str(item.absolute())}/*\n")
|
|
except IOError as e:
|
|
# Using print for now, as logger might not be available here
|
|
print(f"Error creating default user exclude list: {e}")
|
|
|
|
@classmethod
|
|
def generate_and_write_final_exclude_list(cls) -> None:
|
|
"""
|
|
Generates and writes the final rsync exclude list (rsync-exclude.conf)
|
|
containing standard patterns.
|
|
"""
|
|
# Write standard excludes to generated list
|
|
try:
|
|
with open(cls.GENERATED_EXCLUDE_LIST_PATH, 'w') as f:
|
|
f.write(cls.STANDARD_EXCLUDE_CONTENT)
|
|
except IOError as e:
|
|
pass # Handle error in caller
|
|
|
|
|
|
# --- Translation Setup ---
|
|
# Initialize translations for the app domain "pyimage_backup"
|
|
_ = Translate.setup_translations("pyimage_backup")
|
|
|
|
|
|
class Msg:
|
|
"""Provides centralized access to all translated UI strings."""
|
|
|
|
TTIP: Dict[str, str] = {
|
|
"theme_toggle": "",
|
|
"tooltips_toggle": "",
|
|
"updates_toggle": "",
|
|
"show_log": "",
|
|
"about_app": "",
|
|
"updates_disabled": "",
|
|
"no_server_conn_tt": "",
|
|
"up_to_date": "",
|
|
"install_new_version": "",
|
|
}
|
|
STR: Dict[str, str] = {
|
|
# General
|
|
"app_title": _("Lx Tools Pybackup"),
|
|
"welcome_msg": _("Please select an action from the menu."),
|
|
"app_started": _("Application started successfully."),
|
|
"app_quit": _("Application is shutting down."),
|
|
"browse": _("Browse..."),
|
|
"start_backup": _("Start Backup"),
|
|
"restore": _("Restore"),
|
|
"error": _("Error"),
|
|
"confirm": _("Confirm"),
|
|
"warning": _("Warning"),
|
|
"cancel": _("Cancel"),
|
|
"yes": _("Yes"),
|
|
"no": _("No"),
|
|
"apply": _("Apply"),
|
|
"delete": _("Delete"),
|
|
"add": _("Add"),
|
|
"remove": _("Remove"),
|
|
"back": _("Back"),
|
|
"active": _("Active"),
|
|
"source": _("Source"),
|
|
"select_source": _("Select Source"),
|
|
"sources": _("Sources"),
|
|
"destination": _("Destination"),
|
|
"system_backup_info": _("System Backup"),
|
|
"system_restore_info": _("System Restore"),
|
|
"system_restore": _("System Restore"),
|
|
"select_source_first": _("Please select a source first"),
|
|
"user_backup_info": _("User Backup"),
|
|
"user_restore_info": _("User Restore"),
|
|
"select_destination_first": _("Please select a destination first"),
|
|
"calculating_size": _("Calculating size..."),
|
|
"select_destination": _("Select Destination"),
|
|
"settings_reset_title": _("Settings Reset"),
|
|
"settings_reset_text": _("Settings have been reset to default values."),
|
|
"system_backup_in_home_error": _("System backups cannot be saved in the /home directory."),
|
|
"path_not_found": _("Path not found: {path}"),
|
|
"warning_source_larger_than_partition": _("Note: Source size > partition size. Check exclusions in advanced settings if necessary."),
|
|
"warning_not_enough_space": _("WARNING: Not enough space for the backup.\nPlease free up space or choose another location."),
|
|
"warning_space_over_90_percent": _("WARNING: The storage space will be over 90% full. Backup at your own risk!"),
|
|
"ready_for_first_backup": _("Everything is ready for your first backup."),
|
|
"backup_mode_info": _("Backup Mode: You can start a backup here."),
|
|
"restore_mode_info": _("Restore Mode: You can start a restore here."),
|
|
"advanced_settings_title": _("Advanced Settings"),
|
|
"animation_settings_title": _("Animation Settings"),
|
|
"backup_animation_label": _("Backup/Restore Animation:"),
|
|
"calc_animation_label": _("Size Calculation Animation:"),
|
|
"advanced_settings_warning": _("WARNING: Changing these settings is recommended for experienced users only. Incorrect configurations can lead to an unreliable backup.\n\nThe backup destination is always excluded for security reasons and cannot be changed here."),
|
|
"exclude_system_folders": _("Exclude system folders"),
|
|
"in_backup": _("In Backup"),
|
|
"name": _("Name"),
|
|
"path": _("Path"),
|
|
"date": _("Date"),
|
|
"time": _("Time"),
|
|
"size": _("Size"),
|
|
"type": _("Type"),
|
|
"folder": _("Folder"),
|
|
"backup_content": _("Backup Content"),
|
|
"scheduled_jobs": _("Scheduled Jobs"),
|
|
"err_no_job_selected": _("No job selected."),
|
|
"user_defined_folder_settings": _("User-defined folder settings"),
|
|
"hidden_files_and_folders": _("Hidden files and folders"),
|
|
"advanced": _("Advanced"),
|
|
"default_settings": _("Default settings"),
|
|
"scheduling": _("Scheduling"),
|
|
"settings": _("Settings"),
|
|
"log": _("Log"),
|
|
"full_backup": _("Full backup"),
|
|
"incremental": _("Incremental"),
|
|
"test_run": _("Test run"),
|
|
"start": _("Start"),
|
|
"cancel_backup": _("Cancel"),
|
|
"backup_cancelled_and_deleted_msg": _("Backup cancelled and partially completed backup deleted."),
|
|
"info_text_placeholder": _("Info text about the current view."),
|
|
"backup_finished_successfully": _("Backup finished successfully."),
|
|
"backup_finished_with_warnings": _("Backup finished with warnings. See log for details."),
|
|
"backup_failed": _("Backup failed. See log for details."),
|
|
"backup_cancelled_by_user": _("Backup was cancelled by the user."),
|
|
"accurate_size_cb_label": _("Accurate inkrem. size"),
|
|
"accurate_size_info_label": _("(Calculation may take longer)"),
|
|
"accurate_size_success": _("Accurate size calculated successfully."),
|
|
"accurate_size_failed": _("Failed to calculate size. See log for details."),
|
|
"please_wait": _("Please wait, calculating..."),
|
|
"accurate_calc_cancelled": _("Calculate size cancelled."),
|
|
"add_to_exclude_list": _("Add to exclude list"),
|
|
"exclude_dialog_text": _("Do you want to add a folder or a file?"),
|
|
"add_folder_button": _("Folder"),
|
|
"add_file_button": _("File"),
|
|
"system_excludes": _("System Excludes"),
|
|
"manual_excludes": _("Manual Excludes"),
|
|
"manual_excludes_info": _("Here, manually add files or folders to be excluded from the backup. Each entry should be on a new line."),
|
|
|
|
# Menus
|
|
"file_menu": _("File"),
|
|
"exit_menu": _("Exit"),
|
|
"backup_menu": _("Backup"),
|
|
"system_backup_menu": _("System Backup"),
|
|
"user_backup_menu": _("User Data Backup"),
|
|
"restore_menu": _("Restore"),
|
|
"browse_backups_menu": _("Browse Backups"),
|
|
"help_menu": _("Help"),
|
|
"info_menu": _("Info"),
|
|
|
|
# Backup Views
|
|
"source_folders": _("Folders to back up"),
|
|
"dest_folder": _("Destination Folder"),
|
|
"backup_type": _("Backup Type"),
|
|
"type_incremental": _("Incremental (Recommended, saves space)"),
|
|
"type_full": _("Full (Forces a new, complete backup)"),
|
|
"cat_images": _("Pictures"),
|
|
"cat_documents": _("Documents"),
|
|
"cat_music": _("Music"),
|
|
"cat_videos": _("Videos"),
|
|
"show_encrypted_backups": _("Show Encrypted Backups"),
|
|
"show_normal_backups": _("Show Normal Backups"),
|
|
|
|
# Browser View
|
|
"backup_location": _("Backup Location"),
|
|
"found_backups": _("Found Backups"),
|
|
"col_backup_name": _("Backup Name"),
|
|
"col_type": _("Type"),
|
|
"col_date": _("Date"),
|
|
"type_system": _("System"),
|
|
"type_user": _("User Data"),
|
|
|
|
# Dialogs & Messages
|
|
"select_dest_folder_title": _("Select destination folder for backup"),
|
|
"select_backup_location_title": _("Select backup location"),
|
|
"err_no_dest_folder": _("Please select a destination folder."),
|
|
"err_no_source_folder": _("Please select at least one source folder."),
|
|
"err_no_backup_selected": _("Please select a backup from the list."),
|
|
"err_unlock_failed": _("Failed to unlock the container. Please check the password and try again."),
|
|
"err_encrypted_not_mounted": _("Encrypted container is not unlocked. Please unlock it first from the header bar."),
|
|
"confirm_user_restore_title": _("Confirm User Data Restore"),
|
|
"confirm_user_restore_msg": _("Do you really want to restore the backup of '{backup_name}' to its original location? Any newer files may be overwritten."),
|
|
"confirm_delete_title": _("Confirm Deletion"),
|
|
"confirm_delete_text": _("Do you really want to delete the backup '{folder_name}'? This action cannot be undone."),
|
|
"final_warning_system_restore_title": _("FINAL WARNING"),
|
|
"final_warning_system_restore_msg": _("ATTENTION: You are about to restore the system. This process cannot be safely interrupted. All changes since the backup will be lost. \n\nThe computer will automatically restart upon completion. \n\nREALLY PROCEED?"),
|
|
"btn_continue": _("PROCEED"),
|
|
"deleting_backup_in_progress": _("Deletion in progress... Please wait."),
|
|
"select_restore_source_title": _("Select Restore Source"),
|
|
"select_restore_destination_title": _("Select Restore Destination"),
|
|
|
|
# Lock Screen
|
|
"lock_title": _("System Restore in Progress"),
|
|
"lock_msg1": _("Please do not interrupt this process."),
|
|
"lock_msg2": _("The computer will automatically restart upon completion."),
|
|
"add_job_title": _("Add New Job"),
|
|
"frequency": _("Frequency"),
|
|
"freq_daily": _("Daily"),
|
|
"freq_weekly": _("Weekly"),
|
|
"freq_monthly": _("Monthly"),
|
|
"save": _("Save"),
|
|
"projected_usage_label": _("Projected usage after backup"),
|
|
"header_title": _("Lx Tools Py-Backup"),
|
|
"header_subtitle": _("Simple GUI for rsync"),
|
|
"encrypted_backup_content": _("Encrypted Backups"),
|
|
"compressed": _("Compressed"),
|
|
"encrypted": _("Encrypted"),
|
|
"bypass_security": _("Bypass security"),
|
|
"comment": _("Kommentar"),
|
|
"force_full_backup": _("Always force full backup"),
|
|
"force_incremental_backup": _("Always force incremental backup (except first)"),
|
|
"force_compression": _("Always compress backup"),
|
|
"force_encryption": _("Always encrypt backup"),
|
|
"encryption_note_system_backup": _("Note: For system backups, encryption only applies to files directly within the /home directory. Folders are not automatically encrypted unless explicitly included in the backup."),
|
|
}
|