""" AutoBackups - Aplicación Principal Sistema automatizado de backup para proyectos Simatic S7 """ import sys import os import logging from pathlib import Path from datetime import datetime # Agregar el directorio src al path para imports current_dir = Path(__file__).parent src_dir = current_dir sys.path.insert(0, str(src_dir)) # Imports de módulos propios from models.config_model import Config from models.project_model import ProjectManager from utils.file_utils import DiskSpaceChecker from services.basic_backup_service import BasicBackupService class AutoBackupsApp: """Aplicación principal de AutoBackups""" def __init__(self): self.config = None self.project_manager = None self.discovery_service = None self.disk_checker = None self.logger = None # Inicializar aplicación self._setup_logging() self._load_configuration() self._initialize_services() def _setup_logging(self): """Configurar sistema de logging""" try: # Crear directorio de logs si no existe logs_dir = Path(__file__).parent / ".logs" logs_dir.mkdir(exist_ok=True) # Nombre del archivo de log con timestamp timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") log_filename = logs_dir / f"autobackups_{timestamp}.log" # Configurar logging logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler(log_filename, encoding='utf-8'), logging.StreamHandler(sys.stdout) ] ) self.logger = logging.getLogger(__name__) self.logger.info(f"AutoBackups iniciado - Log: {log_filename}") except Exception as e: print(f"Error configurando logging: {e}") sys.exit(1) def _load_configuration(self): """Cargar configuración del sistema""" try: self.logger.info("Cargando configuración...") self.config = Config() self.logger.info("Configuración cargada exitosamente") # Mostrar información básica de configuración self.logger.info(f"Directorios de observación: {len(self.config.observation_directories)}") self.logger.info(f"Destino de backups: {self.config.backup_destination}") except Exception as e: self.logger.error(f"Error cargando configuración: {e}") sys.exit(1) def _initialize_services(self): """Inicializar servicios principales""" try: self.logger.info("Inicializando servicios...") # Project Manager self.project_manager = ProjectManager() self.logger.info("Project Manager inicializado") # Disk Space Checker self.disk_checker = DiskSpaceChecker() self.logger.info("Disk Space Checker inicializado") # Basic Backup Service (Fase 1) self.backup_service = BasicBackupService(self.config) self.logger.info("Basic Backup Service inicializado") # Project Discovery Service (temporalmente comentado) # self.discovery_service = ProjectDiscoveryService(self.config, self.project_manager) # self.logger.info("Project Discovery Service inicializado") self.logger.info("Todos los servicios inicializados correctamente") except Exception as e: self.logger.error(f"Error inicializando servicios: {e}") sys.exit(1) def check_system_requirements(self) -> bool: """Verificar requerimientos del sistema""" try: self.logger.info("Verificando requerimientos del sistema...") # Verificar espacio en disco backup_destination = self.config.backup_destination min_space_mb = self.config.get_min_free_space_mb() free_space_mb = self.disk_checker.get_free_space_mb(backup_destination) if free_space_mb < min_space_mb: self.logger.error( f"Espacio insuficiente en destino de backup. " f"Disponible: {free_space_mb:.1f}MB, " f"Requerido: {min_space_mb}MB" ) return False self.logger.info(f"Espacio en disco OK: {free_space_mb:.1f}MB disponibles") # Verificar Everything API (opcional en Fase 1) if hasattr(self, 'backup_service'): if self.backup_service.check_system_requirements(): self.logger.info("Requerimientos del sistema verificados") else: self.logger.warning("Algunos requerimientos fallaron") else: self.logger.warning("Backup service no disponible") # Verificar directorios de observación missing_dirs = [] for obs_dir in self.config.observation_directories: if not Path(obs_dir["path"]).exists(): missing_dirs.append(obs_dir["path"]) if missing_dirs: self.logger.warning(f"Directorios de observación no encontrados: {missing_dirs}") self.logger.info("Verificación de requerimientos completada") return True except Exception as e: self.logger.error(f"Error verificando requerimientos del sistema: {e}") return False def discover_projects(self) -> int: """Descubrir proyectos en directorios de observación""" try: self.logger.info("Iniciando descubrimiento de proyectos...") # Usar el servicio básico de backup if hasattr(self, 'backup_service'): projects = self.backup_service.discover_projects_basic() else: projects = [] # Agregar proyectos al manager for project_info in projects: self.project_manager.add_or_update_project(project_info) msg = f"Descubrimiento completado: {len(projects)} proyectos" self.logger.info(msg) return len(projects) except Exception as e: self.logger.error(f"Error en descubrimiento de proyectos: {e}") return 0 def show_system_status(self): """Mostrar estado actual del sistema""" try: self.logger.info("=== ESTADO DEL SISTEMA ===") # Información de configuración self.logger.info(f"Directorios de observación configurados: {len(self.config.observation_directories)}") self.logger.info(f"Destino de backups: {self.config.backup_destination}") # Información de proyectos all_projects = self.project_manager.get_all_projects() enabled_projects = self.project_manager.get_enabled_projects() self.logger.info(f"Total de proyectos: {len(all_projects)}") self.logger.info(f"Proyectos habilitados: {len(enabled_projects)}") # Información de espacio en disco backup_dest = self.config.backup_destination total_mb, used_mb, free_mb = self.disk_checker.get_disk_usage_info(backup_dest) self.logger.info(f"Espacio en disco (destino backup):") self.logger.info(f" Total: {total_mb:.1f}MB") self.logger.info(f" Usado: {used_mb:.1f}MB") self.logger.info(f" Libre: {free_mb:.1f}MB") # Información de Everything API if self.discovery_service.everything_searcher: self.logger.info("Everything API: Disponible") else: self.logger.info("Everything API: No disponible") self.logger.info("=== FIN ESTADO DEL SISTEMA ===") except Exception as e: self.logger.error(f"Error mostrando estado del sistema: {e}") def run_initial_setup(self): """Ejecutar configuración inicial de la aplicación""" try: self.logger.info("=== CONFIGURACIÓN INICIAL DE AUTOBACKUPS ===") # Verificar requerimientos del sistema if not self.check_system_requirements(): self.logger.error("Los requerimientos del sistema no se cumplen") return False # Descubrir proyectos projects_found = self.discover_projects() if projects_found == 0: self.logger.warning("No se encontraron proyectos para backup") # Mostrar estado del sistema self.show_system_status() self.logger.info("=== CONFIGURACIÓN INICIAL COMPLETADA ===") return True except Exception as e: self.logger.error(f"Error en configuración inicial: {e}") return False def main(): """Función principal""" try: print("AutoBackups - Sistema de Backup Automatizado") print("=" * 50) # Crear y configurar aplicación app = AutoBackupsApp() # Ejecutar configuración inicial if app.run_initial_setup(): app.logger.info("AutoBackups configurado correctamente") # TODO: En las siguientes fases: # - Iniciar scheduler de backups # - Iniciar interfaz web Flask # - Configurar tareas en background print("\nConfiguración inicial completada.") print("Revisa el archivo de log para más detalles.") else: print("Error en la configuración inicial. Revisa los logs.") sys.exit(1) except KeyboardInterrupt: print("\nAplicación interrumpida por el usuario") except Exception as e: print(f"Error inesperado: {e}") sys.exit(1) if __name__ == "__main__": main()