diff --git a/files/backups/backup-all.py b/files/backups/backup-all.py index c6cd829..279e305 100644 --- a/files/backups/backup-all.py +++ b/files/backups/backup-all.py @@ -14,7 +14,6 @@ from pathlib import Path from typing import List, Tuple, Optional import requests import configparser -import itertools # Configure logging @@ -126,14 +125,60 @@ class BackupManager: return False def get_backup_directories(self) -> List[str]: - """Get all backup directories that exist""" - backup_dirs = [] + """Collect backup targets according to backup-targets rules""" + backup_dirs: List[str] = [] app_dirs = self.get_application_directories() - for app_dir, _ in app_dirs: - backup_path = os.path.join(app_dir, "backups") - if os.path.exists(backup_path) and os.path.isdir(backup_path): - backup_dirs.append(backup_path) + def parse_targets_file(targets_file: Path) -> List[str]: + """Parse backup-targets file, skipping comments and empty lines.""" + targets: List[str] = [] + try: + for raw_line in targets_file.read_text(encoding="utf-8").splitlines(): + line = raw_line.strip() + if not line or line.startswith("#"): + continue + targets.append(line) + except OSError as e: + warning_msg = f"Could not read backup targets file {targets_file}: {e}" + logger.warning(warning_msg) + self.warnings.append(warning_msg) + return targets + + for app_dir_str, _ in app_dirs: + app_dir = Path(app_dir_str) + targets_file = app_dir / "backup-targets" + resolved_targets: List[Path] = [] + + if targets_file.exists(): + # Read custom targets defined by the application. + for target_line in parse_targets_file(targets_file): + target_path = Path(target_line) + if not target_path.is_absolute(): + target_path = (app_dir / target_path).resolve() + else: + target_path = target_path.resolve() + if target_path.exists(): + resolved_targets.append(target_path) + else: + warning_msg = ( + f"Backup target does not exist for {app_dir}: {target_path}" + ) + logger.warning(warning_msg) + self.warnings.append(warning_msg) + else: + # Fallback to default backups directory when no list is provided. + default_target = (app_dir / "backups").resolve() + if default_target.exists(): + resolved_targets.append(default_target) + else: + warning_msg = f"Default backup path does not exist for {app_dir}: {default_target}" + logger.warning(warning_msg) + self.warnings.append(warning_msg) + + for target in resolved_targets: + target_str = str(target) + if target_str not in backup_dirs: + backup_dirs.append(target_str) return backup_dirs