From c8ceb8fddde8d2627a1c3d4350b30860b5bf9fdf Mon Sep 17 00:00:00 2001 From: Miguel Date: Mon, 1 Sep 2025 17:20:34 +0200 Subject: [PATCH] Modificada directorio base del proyecto --- .docs/README.md | 72 --- .docs/SPECIFICATION.md | 258 --------- .docs/TECHNICAL_QUESTIONS.md | 124 ----- .docs/config.json | 60 -- .docs/projects.json | 62 --- .docs/requirements.txt | 32 -- README.md | 525 ++++++++++++++++++ SPECIFICATION.md | 245 -------- TECHNICAL_QUESTIONS.md | 111 ---- autobackups/.gitignore | 216 ------- autobackups/README.md | 72 --- autobackups/SPECIFICATION.md | 258 --------- autobackups/TECHNICAL_QUESTIONS.md | 124 ----- autobackups/config.json | 60 -- autobackups/projects.json | 62 --- autobackups/requirements.txt | 32 -- autobackups/src/app.py | 275 --------- autobackups/src/models/__init__.py | 9 - autobackups/src/services/__init__.py | 12 - autobackups/src/utils/__init__.py | 10 - config.json | 19 +- projects.json | 14 +- requirements.txt | 12 +- src/app.py | 295 +++++++++- src/models/__init__.py | 10 +- .../src => src}/models/config_model.py | 0 .../src => src}/models/project_model.py | 0 src/routes/__init__.py | 5 - src/services/__init__.py | 13 +- .../services/basic_backup_service.py | 0 .../services/project_discovery_service.py | 0 src/utils/__init__.py | 25 +- .../src => src}/utils/everything_wrapper.py | 0 {autobackups/src => src}/utils/file_utils.py | 0 {autobackups/src => src}/utils/hash_utils.py | 0 static/css | 1 - static/js | 1 - templates/index.html | 32 -- 38 files changed, 849 insertions(+), 2197 deletions(-) delete mode 100644 .docs/README.md delete mode 100644 .docs/SPECIFICATION.md delete mode 100644 .docs/TECHNICAL_QUESTIONS.md delete mode 100644 .docs/config.json delete mode 100644 .docs/projects.json delete mode 100644 .docs/requirements.txt create mode 100644 README.md delete mode 100644 SPECIFICATION.md delete mode 100644 TECHNICAL_QUESTIONS.md delete mode 100644 autobackups/.gitignore delete mode 100644 autobackups/README.md delete mode 100644 autobackups/SPECIFICATION.md delete mode 100644 autobackups/TECHNICAL_QUESTIONS.md delete mode 100644 autobackups/config.json delete mode 100644 autobackups/projects.json delete mode 100644 autobackups/requirements.txt delete mode 100644 autobackups/src/app.py delete mode 100644 autobackups/src/models/__init__.py delete mode 100644 autobackups/src/services/__init__.py delete mode 100644 autobackups/src/utils/__init__.py rename {autobackups/src => src}/models/config_model.py (100%) rename {autobackups/src => src}/models/project_model.py (100%) delete mode 100644 src/routes/__init__.py rename {autobackups/src => src}/services/basic_backup_service.py (100%) rename {autobackups/src => src}/services/project_discovery_service.py (100%) rename {autobackups/src => src}/utils/everything_wrapper.py (100%) rename {autobackups/src => src}/utils/file_utils.py (100%) rename {autobackups/src => src}/utils/hash_utils.py (100%) delete mode 100644 static/css delete mode 100644 static/js delete mode 100644 templates/index.html diff --git a/.docs/README.md b/.docs/README.md deleted file mode 100644 index 4ea8ed7..0000000 --- a/.docs/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# AutoBackups Project - -## Overview -AutoBackups is a Python application designed to automate the backup of Simatic S7 projects and other user-defined directories. The application leverages the Everything API to efficiently locate files and manage backups based on user-defined configurations. - -## Features -- Monitors specified directories for Simatic S7 files (*.s7p) and other user-defined directories. -- Automatically compresses and backs up projects on a configurable schedule (daily, hourly, 3-hour, 7-hour intervals, startup, or manual). -- Supports manual backup triggers. -- Skips projects with files in use and retries after one hour. -- Maintains a two-stage hash system: first checking *.s7p files, then all files to avoid unnecessary backups. -- User-friendly web interface built with Flask for configuration and status monitoring. -- Comprehensive logging system with timestamped log files. - -## Project Structure -``` -autobackups -├── .logs/ # Application logs with startup timestamps -├── src -│ ├── app.py # Main entry point of the Flask application -│ ├── models -│ │ └── __init__.py # Data models for configuration and directories -│ ├── routes -│ │ └── __init__.py # API routes for backup operations -│ ├── services -│ │ └── __init__.py # Business logic for backups -│ └── utils -│ └── __init__.py # Utility functions for hashing and file access -├── static -│ ├── css # CSS files for styling -│ └── js # JavaScript files for client-side functionality -├── templates -│ └── index.html # Main HTML template for the web interface -├── config.json # Global configuration settings for the application -├── projects.json # Per-project configuration, schedules, and hash storage -├── requirements.txt # Python dependencies -└── README.md # Project documentation -``` - -## Installation -1. Clone the repository: - ``` - git clone - cd autobackups - ``` - -2. Create a Miniconda environment: - ``` - conda create --name autobackups python=3.12 - conda activate autobackups - ``` - -3. Install the required packages: - ``` - pip install -r requirements.txt - ``` - -4. Configure the application by editing `config.json` to specify directories to monitor and backup settings. - -## Usage -- Start the Flask application: - ``` - python src/app.py - ``` - -- Access the web interface at `http://localhost:5000` to configure settings and monitor backup statuses. - -## Contributing -Contributions are welcome! Please submit a pull request or open an issue for any enhancements or bug fixes. - -## License -This project is licensed under the MIT License. See the LICENSE file for details. \ No newline at end of file diff --git a/.docs/SPECIFICATION.md b/.docs/SPECIFICATION.md deleted file mode 100644 index c3e7a33..0000000 --- a/.docs/SPECIFICATION.md +++ /dev/null @@ -1,258 +0,0 @@ -# AutoBackups - Especificación Técnica Detallada - -## Resumen Ejecutivo -AutoBackups es una aplicación Python que automatiza el backup de proyectos Simatic S7 y directorios definidos por el usuario, utilizando la API de Everything para búsqueda eficiente de archivos y un sistema de hash inteligente para evitar backups innecesarios. - -## Arquitectura del Sistema - -### 1. Componentes Principales - -#### 1.1 Motor de Búsqueda (Everything API) -- **Librería**: PyEverything wrapper -- **DLL Local**: `Everything-SDK\dll\Everything64.dll` -- **Función**: Localizar archivos *.s7p en directorios de observación -- **Optimización**: Evitar último nivel del árbol para archivos .s7p -- **Ventaja**: Aprovecha el índice existente de Everything para búsquedas instantáneas - -#### 1.2 Sistema de Hash en Dos Etapas -**Etapa 1**: Hash rápido de archivos *.s7p -- Solo verifica MD5 de (timestamp + tamaño) de archivos .s7p -- Si no hay cambios → no se procede con backup -- Si hay cambios → procede a Etapa 2 - -**Etapa 2**: Hash completo del proyecto -- Calcula MD5 de (timestamp + tamaño) de todos los archivos del directorio -- Compara con último hash almacenado -- Solo hace backup si hay diferencias - -#### 1.3 Scheduler de Background -- **daily**: Una vez al día a hora configurada -- **hourly**: Cada hora -- **3-hour**: Cada 3 horas -- **7-hour**: Cada 7 horas -- **startup**: Al iniciar la aplicación -- **manual**: Solo bajo demanda del usuario -- **Escaneos**: Automáticos cada 1 hora -- **Backups**: Mínimo cada 10 minutos -- **Prioridad**: Baja prioridad de sistema - -### 2. Estructura de Datos - -#### 2.1 config.json (Configuración Global) -```json -{ - "observation_directories": [ - { - "path": "C:\\Projects\\Siemens", - "type": "siemens_s7", - "enabled": true - }, - { - "path": "D:\\Engineering\\Projects", - "type": "siemens_s7", - "enabled": true - }, - { - "path": "C:\\Important\\Docs", - "type": "manual", - "enabled": true - } - ], - "backup_destination": "D:\\Backups\\AutoBackups", - "default_schedule": "daily", - "default_schedule_time": "02:00", - "retry_delay_hours": 1, - "web_interface": { - "host": "127.0.0.1", - "port": 5000 - }, - "logging": { - "level": "INFO", - "max_log_files": 30 - } -} -``` - -#### 2.2 projects.json (Estado de Proyectos) -```json -{ - "projects": [ - { - "id": "project_001", - "name": "PLC_MainLine", - "path": "C:\\Projects\\Siemens\\PLC_MainLine", - "type": "siemens_s7", - "s7p_file": "C:\\Projects\\Siemens\\PLC_MainLine\\PLC_MainLine.s7p", - "schedule": "daily", - "schedule_time": "02:00", - "enabled": true, - "last_backup": "2025-09-01T02:15:30", - "last_s7p_hash": "abc123def456", - "last_full_hash": "def789ghi012", - "last_s7p_timestamp": "2025-08-31T14:30:00", - "status": "ready", - "retry_count": 0, - "next_retry": null, - "error_message": null - } - ] -} -``` - -### 3. Flujo de Operación - -#### 3.1 Inicio de Aplicación -1. Cargar configuración desde `config.json` -2. Cargar estado de proyectos desde `projects.json` -3. Inicializar logger con timestamp de inicio -4. Escanear directorios de observación usando Everything API -5. Actualizar lista de proyectos detectados -6. Iniciar scheduler -7. Iniciar interfaz web Flask - -#### 4.2 Proceso de Backup -1. **Verificación de Espacio**: Verificar mínimo 100MB libres -2. **Verificación de Acceso .s7p**: Intentar comprimir solo archivo .s7p -3. **Hash Etapa 1**: Verificar MD5 de (timestamp + tamaño) del archivo .s7p -4. **Hash Etapa 2**: Si Etapa 1 detecta cambios, verificar hash completo -5. **Compresión**: Crear archivo ZIP con estructura específica preservada -6. **Almacenamiento**: Guardar en `backup_destination/ProjectPath/YYYY-MM-DD/HH-MM-SS_projects.zip` -7. **Actualización**: Actualizar hashes y timestamps en `projects.json` - -#### 3.3 Gestión de Errores -- **Archivos en uso**: Marcar proyecto para reintento en 1 hora -- **Errores de permisos**: Log de error y notificación en interfaz -- **Errores de espacio**: Verificar espacio disponible antes de backup - -### 4. Interfaz Web - -#### 4.1 Dashboard Principal -- **Lista de Proyectos**: Tabla con estado, último backup, próximo backup -- **Controles Globales**: Backup manual global, pausar/reanudar scheduler -- **Estadísticas**: Total de proyectos, backups exitosos, errores - -#### 4.2 Configuración de Proyectos -- **Habilitación/Deshabilitación**: Toggle por proyecto -- **Configuración de Schedule**: Dropdown con opciones de frecuencia -- **Backup Manual**: Botón de backup inmediato por proyecto - -#### 4.3 Logs y Monitoreo -- **Log Viewer**: Mostrar logs recientes con filtros por nivel -- **Estado del Sistema**: Información de Everything API, espacio en disco - -### 5. Estructura de Backup - -#### 5.1 Nomenclatura de Archivos (Estructura Específica) -``` -backup_destination/ -├── LineA/ -│ └── Project1/ -│ ├── 2025-09-01/ -│ │ ├── 02-15-30_projects.zip -│ │ └── 14-30-15_projects.zip -│ └── 2025-09-02/ -│ └── 02-15-45_projects.zip -└── LineB/ - └── Project2/ - └── 2025-09-01/ - └── 08-20-10_projects.zip -``` - -#### 5.2 Contenido del ZIP -``` -02-15-30_projects.zip -└── LineA/ - └── Project1/ - ├── project.s7p - ├── subfolder1/ - └── subfolder2/ -``` - -### 6. Tecnologías y Librerías - -#### 6.1 Python Core -- **Python**: 3.12 -- **Framework Web**: Flask -- **Scheduler**: APScheduler -- **Compresión**: zipfile (biblioteca estándar) - -#### 6.2 Librerías Específicas -- **Everything API**: PyEverything wrapper con DLL local -- **Hashing**: hashlib MD5 para (timestamp + tamaño) -- **Config**: json (biblioteca estándar) -- **Logging**: logging (biblioteca estándar) -- **File Access Check**: Intento de compresión + verificación .s7p -- **Process Priority**: pywin32 para baja prioridad -- **Disk Space**: psutil para monitoreo de espacio libre - -#### 6.3 Frontend -- **HTML/CSS/JavaScript**: Vanilla (sin React por simplicidad) -- **AJAX**: Para comunicación con Flask API -- **Bootstrap**: Para estilizado responsivo - -### 7. Consideraciones de Seguridad - -#### 7.1 Acceso a Archivos -- Verificación de permisos antes de backup -- Manejo seguro de rutas para evitar path traversal -- Logs de todos los accesos a archivos - -#### 7.2 Interfaz Web -- Solo acceso local (127.0.0.1) -- No autenticación requerida (uso local únicamente) -- Validación de inputs en formularios - -### 8. Logging y Monitoreo - -#### 8.1 Estructura de Logs -``` -.logs/ -├── autobackups_2025-09-01_08-30-15.log -├── autobackups_2025-09-02_08-30-22.log -└── ... -``` - -#### 8.2 Niveles de Log -- **INFO**: Inicio/fin de backups, descubrimiento de proyectos -- **WARNING**: Archivos en uso, reintentos -- **ERROR**: Fallos de backup, errores de configuración -- **DEBUG**: Detalles de hashes, operaciones de archivos - -### 9. Instalación y Despliegue - -#### 9.1 Entorno Miniconda -```bash -conda create --name autobackups python=3.12 -conda activate autobackups -pip install -r requirements.txt -``` - -#### 9.2 Ejecución -- **Desarrollo**: `python src/app.py` -- **Producción**: `pythonw.exe src/app.py` (sin consola) -- **Como servicio**: Futuro enhancement con `python-windows-service` - -### 10. Roadmap de Desarrollo - -#### Fase 1: Core Backend -- [ ] Integración con Everything API -- [ ] Sistema de hash en dos etapas -- [ ] Motor de backup básico -- [ ] Scheduler con APScheduler - -#### Fase 2: Interfaz Web -- [ ] Dashboard básico con Flask -- [ ] API REST para operaciones CRUD -- [ ] Frontend con HTML/JS/Bootstrap - -#### Fase 3: Características Avanzadas -- [ ] Logs web viewer -- [ ] Configuración avanzada de directorios -- [ ] Estadísticas y reportes - -#### Fase 4: Optimizaciones -- [ ] Ejecución como servicio Windows -- [ ] Notificaciones por email -- [ ] Backup incremental - -Este documento será la base para el desarrollo del proyecto AutoBackups. diff --git a/.docs/TECHNICAL_QUESTIONS.md b/.docs/TECHNICAL_QUESTIONS.md deleted file mode 100644 index f9a93f6..0000000 --- a/.docs/TECHNICAL_QUESTIONS.md +++ /dev/null @@ -1,124 +0,0 @@ -# AutoBackups - Preguntas Técnicas Pendientes - -## Preguntas Críticas para el Desarrollo - -### 1. Everything API - Integración -**Pregunta**: ¿Everything está instalado y funcionando en el sistema objetivo? -**Impacto**: Si no está disponible, necesitaremos un método alternativo de búsqueda de archivos. -**Opciones**: -- Usar `python-everything` si Everything está disponible -- Implementar búsqueda recursiva con `os.walk()` como fallback -- Usar `pathlib` con `glob` patterns - -**Decisión necesaria**: ¿Podemos asumir que Everything estará disponible o necesitamos fallback? - -### 2. Estructura de Backup - Clarificación de Rutas -**Pregunta**: Si tenemos un archivo en `C:\Projects\Siemens\LineA\Project1\project.s7p`, ¿el backup debe ser? -**Opción A**: -``` -backup_destination/2025-09-01_14-30-15/Projects_Siemens_LineA_Project1.zip -└── Projects/Siemens/LineA/Project1/... -``` -**Opción B**: -``` -backup_destination/2025-09-01_14-30-15/LineA_Project1.zip -└── LineA/Project1/... -``` - -**Decisión necesaria**: ¿Qué estructura prefieres? - -### 3. Configuración de Schedules - Granularidad -**Pregunta**: ¿Los schedules deben ser configurables a nivel de: -- Por directorio de observación (todos los proyectos de un directorio) -- Por proyecto individual -- Ambos (global con override por proyecto) - -**Decisión necesaria**: ¿Qué nivel de granularidad necesitas? - -### 4. Hash de Archivos - Algoritmo y Almacenamiento -**Pregunta**: Para el sistema de hash en dos etapas: -- ¿Usamos MD5 (rápido) o SHA256 (más seguro) para los hashes? -- ¿El hash incluye solo timestamp o también tamaño de archivo? -- ¿Cómo manejamos archivos que se mueven dentro del proyecto? - -**Decisión necesaria**: ¿Qué balance entre velocidad y precisión prefieres? - -### 5. Detección de Archivos en Uso - Método -**Pregunta**: Para detectar archivos bloqueados, ¿prefieres: -**Opción A**: Intentar abrir cada archivo en modo escritura exclusiva -**Opción B**: Usar `lsof` (Linux) / `handle.exe` (Windows) para listar archivos abiertos -**Opción C**: Solo verificar el archivo .s7p principal - -**Decisión necesaria**: ¿Qué método consideras más apropiado? - -### 6. Manejo de Proyectos Grandes - Performance -**Pregunta**: ¿Hay límites que debamos considerar? -- Tamaño máximo de proyecto para backup -- Tiempo máximo de backup -- Número máximo de archivos por proyecto - -**Decisión necesaria**: ¿Necesitamos algún tipo de throttling o límites? - -### 7. Configuración de Directorios - Recursividad -**Pregunta**: Cuando especificamos un directorio de observación como `C:\Projects`, ¿debemos: -- Buscar solo en subdirectorios inmediatos -- Buscar recursivamente en toda la jerarquía -- Permitir configurar la profundidad de búsqueda - -**Decisión necesaria**: ¿Qué comportamiento prefieres por defecto? - -### 8. Backup Incremental vs Completo -**Pregunta**: ¿Todos los backups deben ser completos o consideras backup incremental? -- Backup completo: Todo el proyecto cada vez -- Backup incremental: Solo archivos modificados - -**Decisión necesaria**: ¿Preferencia por simplicidad o eficiencia de espacio? - -### 9. Web Interface - Características Específicas -**Pregunta**: ¿Qué funcionalidades son prioritarias en la interfaz web? -**Must-have**: -- Lista de proyectos con estado -- Trigger manual de backup -- Ver logs básicos - -**Nice-to-have**: -- Configurar schedules por proyecto -- Ver progreso de backup en tiempo real -- Estadísticas históricas -- Configurar nuevos directorios - -**Decisión necesaria**: ¿Cuáles son must-have vs nice-to-have? - -### 10. Error Handling - Estrategias de Recuperación -**Pregunta**: ¿Cómo manejar errores específicos? -- Espacio insuficiente en destino de backup -- Pérdida de conexión con Everything -- Corrupción de archivos de configuración -- Falla durante compresión - -**Decisión necesaria**: ¿Qué nivel de robustez necesitas? - -### 11. Startup Behavior - Inicialización -**Pregunta**: Al iniciar la aplicación: -- ¿Debe hacer un escaneo completo inmediatamente? -- ¿Debe esperar al primer schedule programado? -- ¿Debe permitir configurar el comportamiento de startup? - -**Decisión necesaria**: ¿Qué comportamiento prefieres al iniciar? - -### 12. Multi-threading - Concurrencia -**Pregunta**: ¿Los backups deben ejecutarse: -- Secuencialmente (uno por vez) -- En paralelo (múltiples simultáneos) -- Con límite configurable de concurrencia - -**Decisión necesaria**: ¿Qué balance entre velocidad y recursos del sistema? - -## Próximos Pasos -Una vez que tengas respuestas a estas preguntas, podremos: -1. Finalizar el diseño técnico -2. Crear el `requirements.txt` definitivo -3. Comenzar con la implementación por fases -4. Definir el plan de testing - -¿Podrías revisar estas preguntas y darme tus preferencias para cada una? diff --git a/.docs/config.json b/.docs/config.json deleted file mode 100644 index 97748ef..0000000 --- a/.docs/config.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "observation_directories": [ - { - "path": "C:\\Projects\\Siemens", - "type": "siemens_s7", - "enabled": true, - "description": "Directorio principal de proyectos Siemens" - }, - { - "path": "D:\\Engineering\\Projects", - "type": "siemens_s7", - "enabled": true, - "description": "Proyectos de ingeniería adicionales" - }, - { - "path": "C:\\Important\\Documentation", - "type": "manual", - "enabled": true, - "description": "Documentación importante para backup manual" - } - ], - "backup_destination": "D:\\Backups\\AutoBackups", - "global_settings": { - "default_schedule": "daily", - "default_schedule_time": "02:00", - "retry_delay_hours": 1, - "backup_timeout_minutes": 0, - "min_free_space_mb": 100, - "scan_interval_minutes": 60, - "min_backup_interval_minutes": 10 - }, - "everything_api": { - "dll_path": "Everything-SDK\\dll\\Everything64.dll", - "enabled": true, - "search_depth": -1, - "skip_last_level_for_s7p": true - }, - "web_interface": { - "host": "127.0.0.1", - "port": 5000, - "debug": false - }, - "logging": { - "level": "INFO", - "max_log_files": 30, - "log_rotation_days": 30 - }, - "backup_options": { - "compression_level": 6, - "include_subdirectories": true, - "preserve_directory_structure": true, - "hash_algorithm": "md5", - "hash_includes": ["timestamp", "size"], - "backup_type": "complete", - "process_priority": "low", - "sequential_execution": true, - "filename_format": "HH-MM-SS_projects.zip", - "date_format": "YYYY-MM-DD" - } -} diff --git a/.docs/projects.json b/.docs/projects.json deleted file mode 100644 index 3c68e69..0000000 --- a/.docs/projects.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "metadata": { - "version": "1.0", - "last_updated": "2025-09-01T08:30:15Z", - "total_projects": 0 - }, - "projects": [ - { - "id": "example_project_001", - "name": "PLC_MainLine_Example", - "path": "C:\\Projects\\Siemens\\LineA\\Project1", - "type": "siemens_s7", - "s7p_file": "C:\\Projects\\Siemens\\LineA\\Project1\\project.s7p", - "observation_directory": "C:\\Projects\\Siemens", - "relative_path": "LineA\\Project1", - "backup_path": "LineA\\Project1", - "schedule_config": { - "schedule": "daily", - "schedule_time": "02:00", - "enabled": true, - "next_scheduled_backup": "2025-09-02T02:00:00Z" - }, - "backup_history": { - "last_backup_date": "2025-09-01T02:15:30Z", - "last_backup_file": "D:\\Backups\\AutoBackups\\LineA\\Project1\\2025-09-01\\02-15-30_projects.zip", - "backup_count": 5, - "last_successful_backup": "2025-09-01T02:15:30Z" - }, - "hash_info": { - "last_s7p_hash": "abc123def456789", - "last_full_hash": "def789ghi012345", - "last_s7p_timestamp": "2025-08-31T14:30:00Z", - "last_s7p_size": 2048576, - "last_scan_timestamp": "2025-09-01T02:10:00Z", - "file_count": 1247, - "total_size_bytes": 125847296 - }, - "status": { - "current_status": "ready", - "last_error": null, - "retry_count": 0, - "next_retry": null, - "files_in_use": false, - "exclusivity_check_passed": true, - "last_status_update": "2025-09-01T02:15:35Z" - }, - "discovery_info": { - "discovered_date": "2025-09-01T08:30:15Z", - "discovery_method": "everything_api", - "auto_discovered": true - } - } - ], - "statistics": { - "total_backups_created": 15, - "total_backup_size_mb": 2450.5, - "average_backup_time_seconds": 45.2, - "last_global_scan": "2025-09-01T08:30:15Z", - "projects_with_errors": 0, - "projects_pending_retry": 0 - } -} diff --git a/.docs/requirements.txt b/.docs/requirements.txt deleted file mode 100644 index c0139b7..0000000 --- a/.docs/requirements.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Core Framework -Flask==2.3.3 -Werkzeug==2.3.7 - -# Scheduling -APScheduler==3.10.4 - -# Everything API Integration -PyEverything==1.0.1 # Wrapper para Everything SDK - -# File Operations and Utilities -pathlib2==2.3.7.post1 # Enhanced pathlib for Python 3.12 -psutil==5.9.5 # System utilities (disk space monitoring) -filelock==3.12.4 # File locking for concurrent access - -# Web Interface -Jinja2==3.1.2 # Template engine for Flask - -# Configuration and Data -jsonschema==4.19.1 # JSON schema validation - -# Logging -colorlog==6.7.0 # Colored logging output - -# Windows-specific dependencies -pywin32==306; sys_platform == "win32" # Windows API access for low priority - -# Development and Testing (opcional, remove for production) -pytest==7.4.2 -pytest-flask==1.2.0 -black==23.9.1 # Code formatting -flake8==6.1.0 # Code linting diff --git a/README.md b/README.md new file mode 100644 index 0000000..9c5a7d5 --- /dev/null +++ b/README.md @@ -0,0 +1,525 @@ +# AutoBackups Project + +## Overview +AutoBackups is a Python application designed to automate the backup of Simatic S7 projects and other user-defined directories. The application leverages the Everything API to efficiently locate files and manage backups based on user-defined configurations. + +## Features +- Monitors specified directories for Simatic S7 files (*.s7p) and other user-defined directories. +- Automatically compresses and backs up projects on a configurable schedule (daily, hourly, 3-hour, 7-hour intervals, startup, or manual). +- Supports manual backup triggers. +- Skips projects with files in use and retries after one hour. +- Maintains a two-stage hash system: first checking *.s7p files, then all files to avoid unnecessary backups. +- User-friendly web interface built with Flask for configuration and status monitoring. +- Comprehensive logging system with timestamped log files. + +## Project Structure +``` +├── .logs/ # Application logs with startup timestamps +├── src +│ ├── app.py # Main entry point of the Flask application +│ ├── models +│ │ └── __init__.py # Data models for configuration and directories +│ ├── routes +│ │ └── __init__.py # API routes for backup operations +│ ├── services +│ │ └── __init__.py # Business logic for backups +│ └── utils +│ └── __init__.py # Utility functions for hashing and file access +├── static +│ ├── css # CSS files for styling +│ └── js # JavaScript files for client-side functionality +├── templates +│ └── index.html # Main HTML template for the web interface +├── config.json # Global configuration settings for the application +├── projects.json # Per-project configuration, schedules, and hash storage +├── requirements.txt # Python dependencies +└── README.md # Project documentation +``` + +## Installation +1. Clone the repository: + ``` + git clone + cd autobackups + ``` + +2. Create a Miniconda environment: + ``` + conda create --name autobackups python=3.12 + conda activate autobackups + ``` + +3. Install the required packages: + ``` + pip install -r requirements.txt + ``` + +4. Configure the application by editing `config.json` to specify directories to monitor and backup settings. + +## Usage +- Start the Flask application: + ``` + python src/app.py + ``` + +- Access the web interface at `http://localhost:5120` to configure settings and monitor backup statuses. + +## Contributing +Contributions are welcome! Please submit a pull request or open an issue for any enhancements or bug fixes. + +## License +This project is licensed under the MIT License. See the LICENSE file for details. + +# AutoBackups - Especificación Técnica Detallada + +## Resumen Ejecutivo +AutoBackups es una aplicación Python que automatiza el backup de proyectos Simatic S7 y directorios definidos por el usuario, utilizando la API de Everything para búsqueda eficiente de archivos y un sistema de hash inteligente para evitar backups innecesarios. + +## Arquitectura del Sistema + +### 1. Componentes Principales + +#### 1.1 Motor de Búsqueda (Everything API) +- **Librería**: PyEverything wrapper +- **DLL Local**: `Everything-SDK\dll\Everything64.dll` +- **Función**: Localizar archivos *.s7p en directorios de observación +- **Optimización**: Evitar último nivel del árbol para archivos .s7p +- **Ventaja**: Aprovecha el índice existente de Everything para búsquedas instantáneas + +#### 1.2 Sistema de Hash en Dos Etapas +**Etapa 1**: Hash rápido de archivos *.s7p +- Solo verifica MD5 de (timestamp + tamaño) de archivos .s7p +- Si no hay cambios → no se procede con backup +- Si hay cambios → procede a Etapa 2 + +**Etapa 2**: Hash completo del proyecto +- Calcula MD5 de (timestamp + tamaño) de todos los archivos del directorio +- Compara con último hash almacenado +- Solo hace backup si hay diferencias + +#### 1.3 Scheduler de Background +- **daily**: Una vez al día a hora configurada +- **hourly**: Cada hora +- **3-hour**: Cada 3 horas +- **7-hour**: Cada 7 horas +- **startup**: Al iniciar la aplicación +- **manual**: Solo bajo demanda del usuario +- **Escaneos**: Automáticos cada 1 hora +- **Backups**: Mínimo cada 10 minutos +- **Prioridad**: Baja prioridad de sistema + +### 2. Estructura de Datos + +#### 2.1 config.json (Configuración Global) +```json +{ + "observation_directories": [ + { + "path": "C:\\Projects\\Siemens", + "type": "siemens_s7", + "enabled": true, + "description": "Directorio principal de proyectos Siemens" + }, + { + "path": "D:\\Engineering\\Projects", + "type": "siemens_s7", + "enabled": true, + "description": "Proyectos de ingeniería adicionales" + }, + { + "path": "C:\\Important\\Documentation", + "type": "manual", + "enabled": true, + "description": "Documentación importante para backup manual" + } + ], + "backup_destination": "D:\\Backups\\AutoBackups", + "global_settings": { + "default_schedule": "daily", + "default_schedule_time": "02:00", + "retry_delay_hours": 1, + "backup_timeout_minutes": 0, + "min_free_space_mb": 100, + "scan_interval_minutes": 60, + "min_backup_interval_minutes": 10 + }, + "everything_api": { + "dll_path": "Everything-SDK\\dll\\Everything64.dll", + "enabled": true, + "search_depth": -1, + "skip_last_level_for_s7p": true + }, + "web_interface": { + "host": "127.0.0.1", + "port": 5000, + "debug": false + }, + "logging": { + "level": "INFO", + "max_log_files": 30, + "log_rotation_days": 30 + }, + "backup_options": { + "compression_level": 6, + "include_subdirectories": true, + "preserve_directory_structure": true, + "hash_algorithm": "md5", + "hash_includes": ["timestamp", "size"], + "backup_type": "complete", + "process_priority": "low", + "sequential_execution": true, + "filename_format": "HH-MM-SS_projects.zip", + "date_format": "YYYY-MM-DD" + } +} +``` + +#### 2.2 projects.json (Estado de Proyectos) +```json +{ + "metadata": { + "version": "1.0", + "last_updated": "2025-09-01T08:30:15Z", + "total_projects": 0 + }, + "projects": [ + { + "id": "example_project_001", + "name": "PLC_MainLine_Example", + "path": "C:\\Projects\\Siemens\\LineA\\Project1", + "type": "siemens_s7", + "s7p_file": "C:\\Projects\\Siemens\\LineA\\Project1\\project.s7p", + "observation_directory": "C:\\Projects\\Siemens", + "relative_path": "LineA\\Project1", + "backup_path": "LineA\\Project1", + "schedule_config": { + "schedule": "daily", + "schedule_time": "02:00", + "enabled": true, + "next_scheduled_backup": "2025-09-02T02:00:00Z" + }, + "backup_history": { + "last_backup_date": "2025-09-01T02:15:30Z", + "last_backup_file": "D:\\Backups\\AutoBackups\\LineA\\Project1\\2025-09-01\\02-15-30_projects.zip", + "backup_count": 5, + "last_successful_backup": "2025-09-01T02:15:30Z" + }, + "hash_info": { + "last_s7p_hash": "abc123def456789", + "last_full_hash": "def789ghi012345", + "last_s7p_timestamp": "2025-08-31T14:30:00Z", + "last_s7p_size": 2048576, + "last_scan_timestamp": "2025-09-01T02:10:00Z", + "file_count": 1247, + "total_size_bytes": 125847296 + }, + "status": { + "current_status": "ready", + "last_error": null, + "retry_count": 0, + "next_retry": null, + "files_in_use": false, + "exclusivity_check_passed": true, + "last_status_update": "2025-09-01T02:15:35Z" + }, + "discovery_info": { + "discovered_date": "2025-09-01T08:30:15Z", + "discovery_method": "everything_api", + "auto_discovered": true + } + } + ], + "statistics": { + "total_backups_created": 15, + "total_backup_size_mb": 2450.5, + "average_backup_time_seconds": 45.2, + "last_global_scan": "2025-09-01T08:30:15Z", + "projects_with_errors": 0, + "projects_pending_retry": 0 + } +} +``` + +### 3. Flujo de Operación + +#### 3.1 Inicio de Aplicación +1. Cargar configuración desde `config.json` +2. Cargar estado de proyectos desde `projects.json` +3. Inicializar logger con timestamp de inicio +4. Escanear directorios de observación usando Everything API +5. Actualizar lista de proyectos detectados +6. Iniciar scheduler +7. Iniciar interfaz web Flask + +#### 4.2 Proceso de Backup +1. **Verificación de Espacio**: Verificar mínimo 100MB libres +2. **Verificación de Acceso .s7p**: Intentar comprimir solo archivo .s7p +3. **Hash Etapa 1**: Verificar MD5 de (timestamp + tamaño) del archivo .s7p +4. **Hash Etapa 2**: Si Etapa 1 detecta cambios, verificar hash completo +5. **Compresión**: Crear archivo ZIP con estructura específica preservada +6. **Almacenamiento**: Guardar en `backup_destination/ProjectPath/YYYY-MM-DD/HH-MM-SS_projects.zip` +7. **Actualización**: Actualizar hashes y timestamps en `projects.json` + +#### 3.3 Gestión de Errores +- **Archivos en uso**: Marcar proyecto para reintento en 1 hora +- **Errores de permisos**: Log de error y notificación en interfaz +- **Errores de espacio**: Verificar espacio disponible antes de backup + +### 4. Interfaz Web + +#### 4.1 Dashboard Principal +- **Lista de Proyectos**: Tabla con estado, último backup, próximo backup +- **Controles Globales**: Backup manual global, pausar/reanudar scheduler +- **Estadísticas**: Total de proyectos, backups exitosos, errores + +#### 4.2 Configuración de Proyectos +- **Habilitación/Deshabilitación**: Toggle por proyecto +- **Configuración de Schedule**: Dropdown con opciones de frecuencia +- **Backup Manual**: Botón de backup inmediato por proyecto + +#### 4.3 Logs y Monitoreo +- **Log Viewer**: Mostrar logs recientes con filtros por nivel +- **Estado del Sistema**: Información de Everything API, espacio en disco + +### 5. Estructura de Backup + +#### 5.1 Nomenclatura de Archivos (Estructura Específica) +``` +backup_destination/ +├── LineA/ +│ └── Project1/ +│ ├── 2025-09-01/ +│ │ ├── 02-15-30_projects.zip +│ │ └── 14-30-15_projects.zip +│ └── 2025-09-02/ +│ └── 02-15-45_projects.zip +└── LineB/ + └── Project2/ + └── 2025-09-01/ + └── 08-20-10_projects.zip +``` + +#### 5.2 Contenido del ZIP +``` +02-15-30_projects.zip +└── LineA/ + └── Project1/ + ├── project.s7p + ├── subfolder1/ + └── subfolder2/ +``` + +### 6. Tecnologías y Librerías + +#### 6.1 Python Core +- **Python**: 3.12 +- **Framework Web**: Flask +- **Scheduler**: APScheduler +- **Compresión**: zipfile (biblioteca estándar) + +#### 6.2 Librerías Específicas +- **Everything API**: PyEverything wrapper con DLL local +- **Hashing**: hashlib MD5 para (timestamp + tamaño) +- **Config**: json (biblioteca estándar) +- **Logging**: logging (biblioteca estándar) +- **File Access Check**: Intento de compresión + verificación .s7p +- **Process Priority**: pywin32 para baja prioridad +- **Disk Space**: psutil para monitoreo de espacio libre + +#### 6.3 Frontend +- **HTML/CSS/JavaScript**: Vanilla (sin React por simplicidad) +- **AJAX**: Para comunicación con Flask API +- **Bootstrap**: Para estilizado responsivo + +### 7. Consideraciones de Seguridad + +#### 7.1 Acceso a Archivos +- Verificación de permisos antes de backup +- Manejo seguro de rutas para evitar path traversal +- Logs de todos los accesos a archivos + +#### 7.2 Interfaz Web +- Solo acceso local (127.0.0.1) +- No autenticación requerida (uso local únicamente) +- Validación de inputs en formularios + +### 8. Logging y Monitoreo + +#### 8.1 Estructura de Logs +``` +.logs/ +├── autobackups_2025-09-01_08-30-15.log +├── autobackups_2025-09-02_08-30-22.log +└── ... +``` + +#### 8.2 Niveles de Log +- **INFO**: Inicio/fin de backups, descubrimiento de proyectos +- **WARNING**: Archivos en uso, reintentos +- **ERROR**: Fallos de backup, errores de configuración +- **DEBUG**: Detalles de hashes, operaciones de archivos + +### 9. Instalación y Despliegue + +#### 9.1 Entorno Miniconda +```bash +conda create --name autobackups python=3.12 +conda activate autobackups +pip install -r requirements.txt +``` + +#### 9.2 Ejecución +- **Desarrollo**: `python src/app.py` +- **Producción**: `pythonw.exe src/app.py` (sin consola) +- **Como servicio**: Futuro enhancement con `python-windows-service` + +### 10. Roadmap de Desarrollo + +#### Fase 1: Core Backend +- [ ] Integración con Everything API +- [ ] Sistema de hash en dos etapas +- [ ] Motor de backup básico +- [ ] Scheduler con APScheduler + +#### Fase 2: Interfaz Web +- [ ] Dashboard básico con Flask +- [ ] API REST para operaciones CRUD +- [ ] Frontend con HTML/JS/Bootstrap + +#### Fase 3: Características Avanzadas +- [ ] Logs web viewer +- [ ] Configuración avanzada de directorios +- [ ] Estadísticas y reportes + +#### Fase 4: Optimizaciones +- [ ] Ejecución como servicio Windows +- [ ] Notificaciones por email +- [ ] Backup incremental + +Este documento será la base para el desarrollo del proyecto AutoBackups. + + +# AutoBackups - Preguntas Técnicas Pendientes + +## Preguntas Críticas para el Desarrollo + +### 1. Everything API - Integración +**Pregunta**: ¿Everything está instalado y funcionando en el sistema objetivo? +**Impacto**: Si no está disponible, necesitaremos un método alternativo de búsqueda de archivos. +**Opciones**: +- Usar `python-everything` si Everything está disponible +- Implementar búsqueda recursiva con `os.walk()` como fallback +- Usar `pathlib` con `glob` patterns + +**Decisión necesaria**: ¿Podemos asumir que Everything estará disponible o necesitamos fallback? + +### 2. Estructura de Backup - Clarificación de Rutas +**Pregunta**: Si tenemos un archivo en `C:\Projects\Siemens\LineA\Project1\project.s7p`, ¿el backup debe ser? +**Opción A**: +``` +backup_destination/2025-09-01_14-30-15/Projects_Siemens_LineA_Project1.zip +└── Projects/Siemens/LineA/Project1/... +``` +**Opción B**: +``` +backup_destination/2025-09-01_14-30-15/LineA_Project1.zip +└── LineA/Project1/... +``` + +**Decisión necesaria**: ¿Qué estructura prefieres? + +### 3. Configuración de Schedules - Granularidad +**Pregunta**: ¿Los schedules deben ser configurables a nivel de: +- Por directorio de observación (todos los proyectos de un directorio) +- Por proyecto individual +- Ambos (global con override por proyecto) + +**Decisión necesaria**: ¿Qué nivel de granularidad necesitas? + +### 4. Hash de Archivos - Algoritmo y Almacenamiento +**Pregunta**: Para el sistema de hash en dos etapas: +- ¿Usamos MD5 (rápido) o SHA256 (más seguro) para los hashes? +- ¿El hash incluye solo timestamp o también tamaño de archivo? +- ¿Cómo manejamos archivos que se mueven dentro del proyecto? + +**Decisión necesaria**: ¿Qué balance entre velocidad y precisión prefieres? + +### 5. Detección de Archivos en Uso - Método +**Pregunta**: Para detectar archivos bloqueados, ¿prefieres: +**Opción A**: Intentar abrir cada archivo en modo escritura exclusiva +**Opción B**: Usar `lsof` (Linux) / `handle.exe` (Windows) para listar archivos abiertos +**Opción C**: Solo verificar el archivo .s7p principal + +**Decisión necesaria**: ¿Qué método consideras más apropiado? + +### 6. Manejo de Proyectos Grandes - Performance +**Pregunta**: ¿Hay límites que debamos considerar? +- Tamaño máximo de proyecto para backup +- Tiempo máximo de backup +- Número máximo de archivos por proyecto + +**Decisión necesaria**: ¿Necesitamos algún tipo de throttling o límites? + +### 7. Configuración de Directorios - Recursividad +**Pregunta**: Cuando especificamos un directorio de observación como `C:\Projects`, ¿debemos: +- Buscar solo en subdirectorios inmediatos +- Buscar recursivamente en toda la jerarquía +- Permitir configurar la profundidad de búsqueda + +**Decisión necesaria**: ¿Qué comportamiento prefieres por defecto? + +### 8. Backup Incremental vs Completo +**Pregunta**: ¿Todos los backups deben ser completos o consideras backup incremental? +- Backup completo: Todo el proyecto cada vez +- Backup incremental: Solo archivos modificados + +**Decisión necesaria**: ¿Preferencia por simplicidad o eficiencia de espacio? + +### 9. Web Interface - Características Específicas +**Pregunta**: ¿Qué funcionalidades son prioritarias en la interfaz web? +**Must-have**: +- Lista de proyectos con estado +- Trigger manual de backup +- Ver logs básicos + +**Nice-to-have**: +- Configurar schedules por proyecto +- Ver progreso de backup en tiempo real +- Estadísticas históricas +- Configurar nuevos directorios + +**Decisión necesaria**: ¿Cuáles son must-have vs nice-to-have? + +### 10. Error Handling - Estrategias de Recuperación +**Pregunta**: ¿Cómo manejar errores específicos? +- Espacio insuficiente en destino de backup +- Pérdida de conexión con Everything +- Corrupción de archivos de configuración +- Falla durante compresión + +**Decisión necesaria**: ¿Qué nivel de robustez necesitas? + +### 11. Startup Behavior - Inicialización +**Pregunta**: Al iniciar la aplicación: +- ¿Debe hacer un escaneo completo inmediatamente? +- ¿Debe esperar al primer schedule programado? +- ¿Debe permitir configurar el comportamiento de startup? + +**Decisión necesaria**: ¿Qué comportamiento prefieres al iniciar? + +### 12. Multi-threading - Concurrencia +**Pregunta**: ¿Los backups deben ejecutarse: +- Secuencialmente (uno por vez) +- En paralelo (múltiples simultáneos) +- Con límite configurable de concurrencia + +**Decisión necesaria**: ¿Qué balance entre velocidad y recursos del sistema? + +## Próximos Pasos +Una vez que tengas respuestas a estas preguntas, podremos: +1. Finalizar el diseño técnico +2. Crear el `requirements.txt` definitivo +3. Comenzar con la implementación por fases +4. Definir el plan de testing + +¿Podrías revisar estas preguntas y darme tus preferencias para cada una? diff --git a/SPECIFICATION.md b/SPECIFICATION.md deleted file mode 100644 index 74cb315..0000000 --- a/SPECIFICATION.md +++ /dev/null @@ -1,245 +0,0 @@ -# AutoBackups - Especificación Técnica Detallada - -## Resumen Ejecutivo -AutoBackups es una aplicación Python que automatiza el backup de proyectos Simatic S7 y directorios definidos por el usuario, utilizando la API de Everything para búsqueda eficiente de archivos y un sistema de hash inteligente para evitar backups innecesarios. - -## Arquitectura del Sistema - -### 1. Componentes Principales - -#### 1.1 Motor de Búsqueda (Everything API) -- **Librería**: `python-everything` o integración directa con Everything SDK -- **Función**: Localizar archivos *.s7p en directorios de observación -- **Ventaja**: Aprovecha el índice existente de Everything para búsquedas instantáneas - -#### 1.2 Sistema de Hash en Dos Etapas -**Etapa 1**: Hash rápido de archivos *.s7p -- Solo verifica timestamps de archivos .s7p -- Si no hay cambios → no se procede con backup -- Si hay cambios → procede a Etapa 2 - -**Etapa 2**: Hash completo del proyecto -- Calcula hash de todos los archivos del directorio del proyecto -- Compara con último hash almacenado -- Solo hace backup si hay diferencias - -#### 1.3 Scheduler Flexible -- **daily**: Una vez al día a hora configurada -- **hourly**: Cada hora -- **3-hour**: Cada 3 horas -- **7-hour**: Cada 7 horas -- **startup**: Al iniciar la aplicación -- **manual**: Solo bajo demanda del usuario - -### 2. Estructura de Datos - -#### 2.1 config.json (Configuración Global) -```json -{ - "observation_directories": [ - { - "path": "C:\\Projects\\Siemens", - "type": "siemens_s7", - "enabled": true - }, - { - "path": "D:\\Engineering\\Projects", - "type": "siemens_s7", - "enabled": true - }, - { - "path": "C:\\Important\\Docs", - "type": "manual", - "enabled": true - } - ], - "backup_destination": "D:\\Backups\\AutoBackups", - "default_schedule": "daily", - "default_schedule_time": "02:00", - "retry_delay_hours": 1, - "web_interface": { - "host": "127.0.0.1", - "port": 5000 - }, - "logging": { - "level": "INFO", - "max_log_files": 30 - } -} -``` - -#### 2.2 projects.json (Estado de Proyectos) -```json -{ - "projects": [ - { - "id": "project_001", - "name": "PLC_MainLine", - "path": "C:\\Projects\\Siemens\\PLC_MainLine", - "type": "siemens_s7", - "s7p_file": "C:\\Projects\\Siemens\\PLC_MainLine\\PLC_MainLine.s7p", - "schedule": "daily", - "schedule_time": "02:00", - "enabled": true, - "last_backup": "2025-09-01T02:15:30", - "last_s7p_hash": "abc123def456", - "last_full_hash": "def789ghi012", - "last_s7p_timestamp": "2025-08-31T14:30:00", - "status": "ready", - "retry_count": 0, - "next_retry": null, - "error_message": null - } - ] -} -``` - -### 3. Flujo de Operación - -#### 3.1 Inicio de Aplicación -1. Cargar configuración desde `config.json` -2. Cargar estado de proyectos desde `projects.json` -3. Inicializar logger con timestamp de inicio -4. Escanear directorios de observación usando Everything API -5. Actualizar lista de proyectos detectados -6. Iniciar scheduler -7. Iniciar interfaz web Flask - -#### 3.2 Proceso de Backup -1. **Verificación de Acceso**: Intentar abrir archivos en modo lectura -2. **Hash Etapa 1**: Verificar timestamp del archivo .s7p -3. **Hash Etapa 2**: Si Etapa 1 detecta cambios, verificar hash completo -4. **Compresión**: Crear archivo ZIP con estructura de directorios preservada -5. **Almacenamiento**: Guardar en `backup_destination/YYYY-MM-DD_HH-MM-SS/` -6. **Actualización**: Actualizar hashes y timestamps en `projects.json` - -#### 3.3 Gestión de Errores -- **Archivos en uso**: Marcar proyecto para reintento en 1 hora -- **Errores de permisos**: Log de error y notificación en interfaz -- **Errores de espacio**: Verificar espacio disponible antes de backup - -### 4. Interfaz Web - -#### 4.1 Dashboard Principal -- **Lista de Proyectos**: Tabla con estado, último backup, próximo backup -- **Controles Globales**: Backup manual global, pausar/reanudar scheduler -- **Estadísticas**: Total de proyectos, backups exitosos, errores - -#### 4.2 Configuración de Proyectos -- **Habilitación/Deshabilitación**: Toggle por proyecto -- **Configuración de Schedule**: Dropdown con opciones de frecuencia -- **Backup Manual**: Botón de backup inmediato por proyecto - -#### 4.3 Logs y Monitoreo -- **Log Viewer**: Mostrar logs recientes con filtros por nivel -- **Estado del Sistema**: Información de Everything API, espacio en disco - -### 5. Estructura de Backup - -#### 5.1 Nomenclatura de Archivos -``` -backup_destination/ -├── 2025-09-01_02-15-30/ -│ ├── Projects_Siemens_PLC_MainLine.zip -│ └── Important_Docs_Documentation.zip -└── 2025-09-02_02-15-45/ - └── Projects_Siemens_PLC_SecondaryLine.zip -``` - -#### 5.2 Contenido del ZIP -``` -PLC_MainLine.zip -└── Projects/ - └── Siemens/ - └── PLC_MainLine/ - ├── PLC_MainLine.s7p - ├── subfolder1/ - └── subfolder2/ -``` - -### 6. Tecnologías y Librerías - -#### 6.1 Python Core -- **Python**: 3.12 -- **Framework Web**: Flask -- **Scheduler**: APScheduler -- **Compresión**: zipfile (biblioteca estándar) - -#### 6.2 Librerías Específicas -- **Everything API**: `python-everything` o implementación custom -- **Hashing**: hashlib (biblioteca estándar) -- **Config**: json (biblioteca estándar) -- **Logging**: logging (biblioteca estándar) -- **File Access Check**: Implementación custom con try/except - -#### 6.3 Frontend -- **HTML/CSS/JavaScript**: Vanilla (sin React por simplicidad) -- **AJAX**: Para comunicación con Flask API -- **Bootstrap**: Para estilizado responsivo - -### 7. Consideraciones de Seguridad - -#### 7.1 Acceso a Archivos -- Verificación de permisos antes de backup -- Manejo seguro de rutas para evitar path traversal -- Logs de todos los accesos a archivos - -#### 7.2 Interfaz Web -- Solo acceso local (127.0.0.1) -- No autenticación requerida (uso local únicamente) -- Validación de inputs en formularios - -### 8. Logging y Monitoreo - -#### 8.1 Estructura de Logs -``` -.logs/ -├── autobackups_2025-09-01_08-30-15.log -├── autobackups_2025-09-02_08-30-22.log -└── ... -``` - -#### 8.2 Niveles de Log -- **INFO**: Inicio/fin de backups, descubrimiento de proyectos -- **WARNING**: Archivos en uso, reintentos -- **ERROR**: Fallos de backup, errores de configuración -- **DEBUG**: Detalles de hashes, operaciones de archivos - -### 9. Instalación y Despliegue - -#### 9.1 Entorno Miniconda -```bash -conda create --name autobackups python=3.12 -conda activate autobackups -pip install -r requirements.txt -``` - -#### 9.2 Ejecución -- **Desarrollo**: `python src/app.py` -- **Producción**: `pythonw.exe src/app.py` (sin consola) -- **Como servicio**: Futuro enhancement con `python-windows-service` - -### 10. Roadmap de Desarrollo - -#### Fase 1: Core Backend -- [ ] Integración con Everything API -- [ ] Sistema de hash en dos etapas -- [ ] Motor de backup básico -- [ ] Scheduler con APScheduler - -#### Fase 2: Interfaz Web -- [ ] Dashboard básico con Flask -- [ ] API REST para operaciones CRUD -- [ ] Frontend con HTML/JS/Bootstrap - -#### Fase 3: Características Avanzadas -- [ ] Logs web viewer -- [ ] Configuración avanzada de directorios -- [ ] Estadísticas y reportes - -#### Fase 4: Optimizaciones -- [ ] Ejecución como servicio Windows -- [ ] Notificaciones por email -- [ ] Backup incremental - -Este documento será la base para el desarrollo del proyecto AutoBackups. diff --git a/TECHNICAL_QUESTIONS.md b/TECHNICAL_QUESTIONS.md deleted file mode 100644 index 4ba2094..0000000 --- a/TECHNICAL_QUESTIONS.md +++ /dev/null @@ -1,111 +0,0 @@ -# AutoBackups - Decisiones Técnicas Finalizadas - -## Decisiones Técnicas Confirmadas - -### 1. Everything API - Integración ✅ -**Decisión**: Everything SDK está instalado bajo `Everything-SDK\dll\Everything64.dll` -**Implementación**: Usar PyEverything (Wrapper) sin fallback -**Ruta DLL**: `Everything-SDK\dll\Everything64.dll` - -### 2. Estructura de Backup - Clarificación de Rutas ✅ -**Decisión**: Estructura específica con formato de fecha personalizado -**Ejemplo**: -- Directorio base: `C:\Projects\Siemens` -- Proyecto: `C:\Projects\Siemens\LineA\Project1\project.s7p` -- Backup: `backup_destination/LineA/Project1/2025-09-01/14-30-15_projects.zip` -**Formato**: YYYY-MM-DD para fechas, HH-MM-SS formato 24 horas - -### 3. Configuración de Schedules - Granularidad ✅ -**Decisión**: Ambos niveles (global con override por proyecto) -**Implementación**: -- Configuración global por defecto -- Override individual por proyecto -- Interfaz web para modificar ambos niveles - -### 4. Hash de Archivos - Algoritmo y Almacenamiento ✅ -**Decisión**: Hash de timestamps + tamaño (NO contenido) -**Algoritmo**: MD5 para velocidad -**Incluye**: timestamp + tamaño de archivo -**Prioridad**: Velocidad sobre seguridad criptográfica - -### 5. Detección de Archivos en Uso - Método ✅ -**Decisión**: Detección por intento de compresión -**Método Primario**: Intentar comprimir y detectar errores de exclusividad -**Método Rápido**: Verificar archivo .s7p antes de comprimir proyecto completo -**Manejo de Errores**: Marcar como problema de exclusividad si falla - -### 6. Manejo de Proyectos Grandes - Performance ✅ -**Decisión**: Sin límites de tamaño, tiempo o archivos -**Implementación**: Sin throttling, procesar cualquier tamaño de proyecto -**Prioridad**: Baja prioridad de sistema para no interferir - -### 7. Configuración de Directorios - Recursividad ✅ -**Decisión**: Búsqueda recursiva con optimización para .s7p -**Implementación**: -- Búsqueda recursiva en toda la jerarquía -- Optimización: evitar último nivel para archivos .s7p -- Razón: archivos .s7p no pueden estar en el último nivel del árbol - -### 8. Backup Incremental vs Completo ✅ -**Decisión**: Siempre backup completo -**Implementación**: Todo el proyecto cada vez -**Razón**: Simplicidad y asegurar integridad completa - -### 9. Web Interface - Características Específicas ✅ -**Must-have**: -- Lista de proyectos con estado ✅ -- Trigger manual de backup ✅ -- Ver logs básicos ✅ -- Configurar schedules por proyecto ✅ -- **Modificar configuración general (config.json) ✅** - -**Nice-to-have**: -- Ver progreso de backup en tiempo real -- Estadísticas históricas -- Configurar nuevos directorios - -### 10. Error Handling - Estrategias de Recuperación ✅ -**Espacio Insuficiente**: -- Área de status en página web mostrando espacio libre -- Límite mínimo: 100MB libres para ejecutar backups -- Sin backups si espacio < 100MB - -**Otros Errores**: -- Marcar para reintento en 1 hora -- Log de errores para diagnóstico - -### 11. Startup Behavior - Inicialización ✅ -**Decisión**: Aplicación de background con timers específicos -**Comportamiento**: -- Escaneos programados: cada 1 hora -- Backups mínimo: cada 10 minutos -- Aplicación siempre en background -- Baja prioridad de sistema - -### 12. Multi-threading - Concurrencia ✅ -**Decisión**: Ejecución secuencial (uno por vez) -**Implementación**: -- Backups secuenciales para economizar recursos -- Baja prioridad de sistema -- Orientado a operación en background sin interferir - -## Especificación Técnica Finalizada ✅ - -### Resumen de Decisiones Clave: -1. **Everything SDK**: PyEverything wrapper con DLL local -2. **Estructura de Backup**: `backup_destination/ProjectPath/YYYY-MM-DD/HH-MM-SS_projects.zip` -3. **Hash**: MD5 de (timestamp + tamaño) para velocidad -4. **Detección de Uso**: Por intento de compresión + verificación .s7p -5. **Performance**: Sin límites, baja prioridad, secuencial -6. **Búsqueda**: Recursiva evitando último nivel para .s7p -7. **Backups**: Siempre completos -8. **Interfaz**: Flask con configuración de config.json -9. **Espacio**: Mínimo 100MB libres, status visible -10. **Background**: Escaneos 1h, backups min 10min -11. **Concurrencia**: Secuencial, baja prioridad - -### Próximos Pasos: -1. ✅ Finalizar diseño técnico basado en decisiones -2. ⏳ Actualizar `requirements.txt` con PyEverything -3. ⏳ Comenzar implementación por fases -4. ⏳ Crear estructura básica del proyecto diff --git a/autobackups/.gitignore b/autobackups/.gitignore deleted file mode 100644 index 5290d13..0000000 --- a/autobackups/.gitignore +++ /dev/null @@ -1,216 +0,0 @@ -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[codz] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py.cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# UV -# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -#uv.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock -#poetry.toml - -# pdm -# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. -# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python. -# https://pdm-project.org/en/latest/usage/project/#working-with-version-control -#pdm.lock -#pdm.toml -.pdm-python -.pdm-build/ - -# pixi -# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control. -#pixi.lock -# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one -# in the .venv directory. It is recommended not to include this directory in version control. -.pixi - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# Redis -*.rdb -*.aof -*.pid - -# RabbitMQ -mnesia/ -rabbitmq/ -rabbitmq-data/ - -# ActiveMQ -activemq-data/ - -# SageMath parsed files -*.sage.py - -# Environments -.env -.envrc -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintained in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -# Abstra -# Abstra is an AI-powered process automation framework. -# Ignore directories containing user credentials, local state, and settings. -# Learn more at https://abstra.io/docs -.abstra/ - -# Visual Studio Code -# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore -# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore -# and can be added to the global gitignore or merged into this file. However, if you prefer, -# you could uncomment the following to ignore the entire vscode folder -# .vscode/ - -# Ruff stuff: -.ruff_cache/ - -# PyPI configuration file -.pypirc - -# Marimo -marimo/_static/ -marimo/_lsp/ -__marimo__/ - -# Streamlit -.streamlit/secrets.toml diff --git a/autobackups/README.md b/autobackups/README.md deleted file mode 100644 index 4ea8ed7..0000000 --- a/autobackups/README.md +++ /dev/null @@ -1,72 +0,0 @@ -# AutoBackups Project - -## Overview -AutoBackups is a Python application designed to automate the backup of Simatic S7 projects and other user-defined directories. The application leverages the Everything API to efficiently locate files and manage backups based on user-defined configurations. - -## Features -- Monitors specified directories for Simatic S7 files (*.s7p) and other user-defined directories. -- Automatically compresses and backs up projects on a configurable schedule (daily, hourly, 3-hour, 7-hour intervals, startup, or manual). -- Supports manual backup triggers. -- Skips projects with files in use and retries after one hour. -- Maintains a two-stage hash system: first checking *.s7p files, then all files to avoid unnecessary backups. -- User-friendly web interface built with Flask for configuration and status monitoring. -- Comprehensive logging system with timestamped log files. - -## Project Structure -``` -autobackups -├── .logs/ # Application logs with startup timestamps -├── src -│ ├── app.py # Main entry point of the Flask application -│ ├── models -│ │ └── __init__.py # Data models for configuration and directories -│ ├── routes -│ │ └── __init__.py # API routes for backup operations -│ ├── services -│ │ └── __init__.py # Business logic for backups -│ └── utils -│ └── __init__.py # Utility functions for hashing and file access -├── static -│ ├── css # CSS files for styling -│ └── js # JavaScript files for client-side functionality -├── templates -│ └── index.html # Main HTML template for the web interface -├── config.json # Global configuration settings for the application -├── projects.json # Per-project configuration, schedules, and hash storage -├── requirements.txt # Python dependencies -└── README.md # Project documentation -``` - -## Installation -1. Clone the repository: - ``` - git clone - cd autobackups - ``` - -2. Create a Miniconda environment: - ``` - conda create --name autobackups python=3.12 - conda activate autobackups - ``` - -3. Install the required packages: - ``` - pip install -r requirements.txt - ``` - -4. Configure the application by editing `config.json` to specify directories to monitor and backup settings. - -## Usage -- Start the Flask application: - ``` - python src/app.py - ``` - -- Access the web interface at `http://localhost:5000` to configure settings and monitor backup statuses. - -## Contributing -Contributions are welcome! Please submit a pull request or open an issue for any enhancements or bug fixes. - -## License -This project is licensed under the MIT License. See the LICENSE file for details. \ No newline at end of file diff --git a/autobackups/SPECIFICATION.md b/autobackups/SPECIFICATION.md deleted file mode 100644 index c3e7a33..0000000 --- a/autobackups/SPECIFICATION.md +++ /dev/null @@ -1,258 +0,0 @@ -# AutoBackups - Especificación Técnica Detallada - -## Resumen Ejecutivo -AutoBackups es una aplicación Python que automatiza el backup de proyectos Simatic S7 y directorios definidos por el usuario, utilizando la API de Everything para búsqueda eficiente de archivos y un sistema de hash inteligente para evitar backups innecesarios. - -## Arquitectura del Sistema - -### 1. Componentes Principales - -#### 1.1 Motor de Búsqueda (Everything API) -- **Librería**: PyEverything wrapper -- **DLL Local**: `Everything-SDK\dll\Everything64.dll` -- **Función**: Localizar archivos *.s7p en directorios de observación -- **Optimización**: Evitar último nivel del árbol para archivos .s7p -- **Ventaja**: Aprovecha el índice existente de Everything para búsquedas instantáneas - -#### 1.2 Sistema de Hash en Dos Etapas -**Etapa 1**: Hash rápido de archivos *.s7p -- Solo verifica MD5 de (timestamp + tamaño) de archivos .s7p -- Si no hay cambios → no se procede con backup -- Si hay cambios → procede a Etapa 2 - -**Etapa 2**: Hash completo del proyecto -- Calcula MD5 de (timestamp + tamaño) de todos los archivos del directorio -- Compara con último hash almacenado -- Solo hace backup si hay diferencias - -#### 1.3 Scheduler de Background -- **daily**: Una vez al día a hora configurada -- **hourly**: Cada hora -- **3-hour**: Cada 3 horas -- **7-hour**: Cada 7 horas -- **startup**: Al iniciar la aplicación -- **manual**: Solo bajo demanda del usuario -- **Escaneos**: Automáticos cada 1 hora -- **Backups**: Mínimo cada 10 minutos -- **Prioridad**: Baja prioridad de sistema - -### 2. Estructura de Datos - -#### 2.1 config.json (Configuración Global) -```json -{ - "observation_directories": [ - { - "path": "C:\\Projects\\Siemens", - "type": "siemens_s7", - "enabled": true - }, - { - "path": "D:\\Engineering\\Projects", - "type": "siemens_s7", - "enabled": true - }, - { - "path": "C:\\Important\\Docs", - "type": "manual", - "enabled": true - } - ], - "backup_destination": "D:\\Backups\\AutoBackups", - "default_schedule": "daily", - "default_schedule_time": "02:00", - "retry_delay_hours": 1, - "web_interface": { - "host": "127.0.0.1", - "port": 5000 - }, - "logging": { - "level": "INFO", - "max_log_files": 30 - } -} -``` - -#### 2.2 projects.json (Estado de Proyectos) -```json -{ - "projects": [ - { - "id": "project_001", - "name": "PLC_MainLine", - "path": "C:\\Projects\\Siemens\\PLC_MainLine", - "type": "siemens_s7", - "s7p_file": "C:\\Projects\\Siemens\\PLC_MainLine\\PLC_MainLine.s7p", - "schedule": "daily", - "schedule_time": "02:00", - "enabled": true, - "last_backup": "2025-09-01T02:15:30", - "last_s7p_hash": "abc123def456", - "last_full_hash": "def789ghi012", - "last_s7p_timestamp": "2025-08-31T14:30:00", - "status": "ready", - "retry_count": 0, - "next_retry": null, - "error_message": null - } - ] -} -``` - -### 3. Flujo de Operación - -#### 3.1 Inicio de Aplicación -1. Cargar configuración desde `config.json` -2. Cargar estado de proyectos desde `projects.json` -3. Inicializar logger con timestamp de inicio -4. Escanear directorios de observación usando Everything API -5. Actualizar lista de proyectos detectados -6. Iniciar scheduler -7. Iniciar interfaz web Flask - -#### 4.2 Proceso de Backup -1. **Verificación de Espacio**: Verificar mínimo 100MB libres -2. **Verificación de Acceso .s7p**: Intentar comprimir solo archivo .s7p -3. **Hash Etapa 1**: Verificar MD5 de (timestamp + tamaño) del archivo .s7p -4. **Hash Etapa 2**: Si Etapa 1 detecta cambios, verificar hash completo -5. **Compresión**: Crear archivo ZIP con estructura específica preservada -6. **Almacenamiento**: Guardar en `backup_destination/ProjectPath/YYYY-MM-DD/HH-MM-SS_projects.zip` -7. **Actualización**: Actualizar hashes y timestamps en `projects.json` - -#### 3.3 Gestión de Errores -- **Archivos en uso**: Marcar proyecto para reintento en 1 hora -- **Errores de permisos**: Log de error y notificación en interfaz -- **Errores de espacio**: Verificar espacio disponible antes de backup - -### 4. Interfaz Web - -#### 4.1 Dashboard Principal -- **Lista de Proyectos**: Tabla con estado, último backup, próximo backup -- **Controles Globales**: Backup manual global, pausar/reanudar scheduler -- **Estadísticas**: Total de proyectos, backups exitosos, errores - -#### 4.2 Configuración de Proyectos -- **Habilitación/Deshabilitación**: Toggle por proyecto -- **Configuración de Schedule**: Dropdown con opciones de frecuencia -- **Backup Manual**: Botón de backup inmediato por proyecto - -#### 4.3 Logs y Monitoreo -- **Log Viewer**: Mostrar logs recientes con filtros por nivel -- **Estado del Sistema**: Información de Everything API, espacio en disco - -### 5. Estructura de Backup - -#### 5.1 Nomenclatura de Archivos (Estructura Específica) -``` -backup_destination/ -├── LineA/ -│ └── Project1/ -│ ├── 2025-09-01/ -│ │ ├── 02-15-30_projects.zip -│ │ └── 14-30-15_projects.zip -│ └── 2025-09-02/ -│ └── 02-15-45_projects.zip -└── LineB/ - └── Project2/ - └── 2025-09-01/ - └── 08-20-10_projects.zip -``` - -#### 5.2 Contenido del ZIP -``` -02-15-30_projects.zip -└── LineA/ - └── Project1/ - ├── project.s7p - ├── subfolder1/ - └── subfolder2/ -``` - -### 6. Tecnologías y Librerías - -#### 6.1 Python Core -- **Python**: 3.12 -- **Framework Web**: Flask -- **Scheduler**: APScheduler -- **Compresión**: zipfile (biblioteca estándar) - -#### 6.2 Librerías Específicas -- **Everything API**: PyEverything wrapper con DLL local -- **Hashing**: hashlib MD5 para (timestamp + tamaño) -- **Config**: json (biblioteca estándar) -- **Logging**: logging (biblioteca estándar) -- **File Access Check**: Intento de compresión + verificación .s7p -- **Process Priority**: pywin32 para baja prioridad -- **Disk Space**: psutil para monitoreo de espacio libre - -#### 6.3 Frontend -- **HTML/CSS/JavaScript**: Vanilla (sin React por simplicidad) -- **AJAX**: Para comunicación con Flask API -- **Bootstrap**: Para estilizado responsivo - -### 7. Consideraciones de Seguridad - -#### 7.1 Acceso a Archivos -- Verificación de permisos antes de backup -- Manejo seguro de rutas para evitar path traversal -- Logs de todos los accesos a archivos - -#### 7.2 Interfaz Web -- Solo acceso local (127.0.0.1) -- No autenticación requerida (uso local únicamente) -- Validación de inputs en formularios - -### 8. Logging y Monitoreo - -#### 8.1 Estructura de Logs -``` -.logs/ -├── autobackups_2025-09-01_08-30-15.log -├── autobackups_2025-09-02_08-30-22.log -└── ... -``` - -#### 8.2 Niveles de Log -- **INFO**: Inicio/fin de backups, descubrimiento de proyectos -- **WARNING**: Archivos en uso, reintentos -- **ERROR**: Fallos de backup, errores de configuración -- **DEBUG**: Detalles de hashes, operaciones de archivos - -### 9. Instalación y Despliegue - -#### 9.1 Entorno Miniconda -```bash -conda create --name autobackups python=3.12 -conda activate autobackups -pip install -r requirements.txt -``` - -#### 9.2 Ejecución -- **Desarrollo**: `python src/app.py` -- **Producción**: `pythonw.exe src/app.py` (sin consola) -- **Como servicio**: Futuro enhancement con `python-windows-service` - -### 10. Roadmap de Desarrollo - -#### Fase 1: Core Backend -- [ ] Integración con Everything API -- [ ] Sistema de hash en dos etapas -- [ ] Motor de backup básico -- [ ] Scheduler con APScheduler - -#### Fase 2: Interfaz Web -- [ ] Dashboard básico con Flask -- [ ] API REST para operaciones CRUD -- [ ] Frontend con HTML/JS/Bootstrap - -#### Fase 3: Características Avanzadas -- [ ] Logs web viewer -- [ ] Configuración avanzada de directorios -- [ ] Estadísticas y reportes - -#### Fase 4: Optimizaciones -- [ ] Ejecución como servicio Windows -- [ ] Notificaciones por email -- [ ] Backup incremental - -Este documento será la base para el desarrollo del proyecto AutoBackups. diff --git a/autobackups/TECHNICAL_QUESTIONS.md b/autobackups/TECHNICAL_QUESTIONS.md deleted file mode 100644 index f9a93f6..0000000 --- a/autobackups/TECHNICAL_QUESTIONS.md +++ /dev/null @@ -1,124 +0,0 @@ -# AutoBackups - Preguntas Técnicas Pendientes - -## Preguntas Críticas para el Desarrollo - -### 1. Everything API - Integración -**Pregunta**: ¿Everything está instalado y funcionando en el sistema objetivo? -**Impacto**: Si no está disponible, necesitaremos un método alternativo de búsqueda de archivos. -**Opciones**: -- Usar `python-everything` si Everything está disponible -- Implementar búsqueda recursiva con `os.walk()` como fallback -- Usar `pathlib` con `glob` patterns - -**Decisión necesaria**: ¿Podemos asumir que Everything estará disponible o necesitamos fallback? - -### 2. Estructura de Backup - Clarificación de Rutas -**Pregunta**: Si tenemos un archivo en `C:\Projects\Siemens\LineA\Project1\project.s7p`, ¿el backup debe ser? -**Opción A**: -``` -backup_destination/2025-09-01_14-30-15/Projects_Siemens_LineA_Project1.zip -└── Projects/Siemens/LineA/Project1/... -``` -**Opción B**: -``` -backup_destination/2025-09-01_14-30-15/LineA_Project1.zip -└── LineA/Project1/... -``` - -**Decisión necesaria**: ¿Qué estructura prefieres? - -### 3. Configuración de Schedules - Granularidad -**Pregunta**: ¿Los schedules deben ser configurables a nivel de: -- Por directorio de observación (todos los proyectos de un directorio) -- Por proyecto individual -- Ambos (global con override por proyecto) - -**Decisión necesaria**: ¿Qué nivel de granularidad necesitas? - -### 4. Hash de Archivos - Algoritmo y Almacenamiento -**Pregunta**: Para el sistema de hash en dos etapas: -- ¿Usamos MD5 (rápido) o SHA256 (más seguro) para los hashes? -- ¿El hash incluye solo timestamp o también tamaño de archivo? -- ¿Cómo manejamos archivos que se mueven dentro del proyecto? - -**Decisión necesaria**: ¿Qué balance entre velocidad y precisión prefieres? - -### 5. Detección de Archivos en Uso - Método -**Pregunta**: Para detectar archivos bloqueados, ¿prefieres: -**Opción A**: Intentar abrir cada archivo en modo escritura exclusiva -**Opción B**: Usar `lsof` (Linux) / `handle.exe` (Windows) para listar archivos abiertos -**Opción C**: Solo verificar el archivo .s7p principal - -**Decisión necesaria**: ¿Qué método consideras más apropiado? - -### 6. Manejo de Proyectos Grandes - Performance -**Pregunta**: ¿Hay límites que debamos considerar? -- Tamaño máximo de proyecto para backup -- Tiempo máximo de backup -- Número máximo de archivos por proyecto - -**Decisión necesaria**: ¿Necesitamos algún tipo de throttling o límites? - -### 7. Configuración de Directorios - Recursividad -**Pregunta**: Cuando especificamos un directorio de observación como `C:\Projects`, ¿debemos: -- Buscar solo en subdirectorios inmediatos -- Buscar recursivamente en toda la jerarquía -- Permitir configurar la profundidad de búsqueda - -**Decisión necesaria**: ¿Qué comportamiento prefieres por defecto? - -### 8. Backup Incremental vs Completo -**Pregunta**: ¿Todos los backups deben ser completos o consideras backup incremental? -- Backup completo: Todo el proyecto cada vez -- Backup incremental: Solo archivos modificados - -**Decisión necesaria**: ¿Preferencia por simplicidad o eficiencia de espacio? - -### 9. Web Interface - Características Específicas -**Pregunta**: ¿Qué funcionalidades son prioritarias en la interfaz web? -**Must-have**: -- Lista de proyectos con estado -- Trigger manual de backup -- Ver logs básicos - -**Nice-to-have**: -- Configurar schedules por proyecto -- Ver progreso de backup en tiempo real -- Estadísticas históricas -- Configurar nuevos directorios - -**Decisión necesaria**: ¿Cuáles son must-have vs nice-to-have? - -### 10. Error Handling - Estrategias de Recuperación -**Pregunta**: ¿Cómo manejar errores específicos? -- Espacio insuficiente en destino de backup -- Pérdida de conexión con Everything -- Corrupción de archivos de configuración -- Falla durante compresión - -**Decisión necesaria**: ¿Qué nivel de robustez necesitas? - -### 11. Startup Behavior - Inicialización -**Pregunta**: Al iniciar la aplicación: -- ¿Debe hacer un escaneo completo inmediatamente? -- ¿Debe esperar al primer schedule programado? -- ¿Debe permitir configurar el comportamiento de startup? - -**Decisión necesaria**: ¿Qué comportamiento prefieres al iniciar? - -### 12. Multi-threading - Concurrencia -**Pregunta**: ¿Los backups deben ejecutarse: -- Secuencialmente (uno por vez) -- En paralelo (múltiples simultáneos) -- Con límite configurable de concurrencia - -**Decisión necesaria**: ¿Qué balance entre velocidad y recursos del sistema? - -## Próximos Pasos -Una vez que tengas respuestas a estas preguntas, podremos: -1. Finalizar el diseño técnico -2. Crear el `requirements.txt` definitivo -3. Comenzar con la implementación por fases -4. Definir el plan de testing - -¿Podrías revisar estas preguntas y darme tus preferencias para cada una? diff --git a/autobackups/config.json b/autobackups/config.json deleted file mode 100644 index 97748ef..0000000 --- a/autobackups/config.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "observation_directories": [ - { - "path": "C:\\Projects\\Siemens", - "type": "siemens_s7", - "enabled": true, - "description": "Directorio principal de proyectos Siemens" - }, - { - "path": "D:\\Engineering\\Projects", - "type": "siemens_s7", - "enabled": true, - "description": "Proyectos de ingeniería adicionales" - }, - { - "path": "C:\\Important\\Documentation", - "type": "manual", - "enabled": true, - "description": "Documentación importante para backup manual" - } - ], - "backup_destination": "D:\\Backups\\AutoBackups", - "global_settings": { - "default_schedule": "daily", - "default_schedule_time": "02:00", - "retry_delay_hours": 1, - "backup_timeout_minutes": 0, - "min_free_space_mb": 100, - "scan_interval_minutes": 60, - "min_backup_interval_minutes": 10 - }, - "everything_api": { - "dll_path": "Everything-SDK\\dll\\Everything64.dll", - "enabled": true, - "search_depth": -1, - "skip_last_level_for_s7p": true - }, - "web_interface": { - "host": "127.0.0.1", - "port": 5000, - "debug": false - }, - "logging": { - "level": "INFO", - "max_log_files": 30, - "log_rotation_days": 30 - }, - "backup_options": { - "compression_level": 6, - "include_subdirectories": true, - "preserve_directory_structure": true, - "hash_algorithm": "md5", - "hash_includes": ["timestamp", "size"], - "backup_type": "complete", - "process_priority": "low", - "sequential_execution": true, - "filename_format": "HH-MM-SS_projects.zip", - "date_format": "YYYY-MM-DD" - } -} diff --git a/autobackups/projects.json b/autobackups/projects.json deleted file mode 100644 index 3c68e69..0000000 --- a/autobackups/projects.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "metadata": { - "version": "1.0", - "last_updated": "2025-09-01T08:30:15Z", - "total_projects": 0 - }, - "projects": [ - { - "id": "example_project_001", - "name": "PLC_MainLine_Example", - "path": "C:\\Projects\\Siemens\\LineA\\Project1", - "type": "siemens_s7", - "s7p_file": "C:\\Projects\\Siemens\\LineA\\Project1\\project.s7p", - "observation_directory": "C:\\Projects\\Siemens", - "relative_path": "LineA\\Project1", - "backup_path": "LineA\\Project1", - "schedule_config": { - "schedule": "daily", - "schedule_time": "02:00", - "enabled": true, - "next_scheduled_backup": "2025-09-02T02:00:00Z" - }, - "backup_history": { - "last_backup_date": "2025-09-01T02:15:30Z", - "last_backup_file": "D:\\Backups\\AutoBackups\\LineA\\Project1\\2025-09-01\\02-15-30_projects.zip", - "backup_count": 5, - "last_successful_backup": "2025-09-01T02:15:30Z" - }, - "hash_info": { - "last_s7p_hash": "abc123def456789", - "last_full_hash": "def789ghi012345", - "last_s7p_timestamp": "2025-08-31T14:30:00Z", - "last_s7p_size": 2048576, - "last_scan_timestamp": "2025-09-01T02:10:00Z", - "file_count": 1247, - "total_size_bytes": 125847296 - }, - "status": { - "current_status": "ready", - "last_error": null, - "retry_count": 0, - "next_retry": null, - "files_in_use": false, - "exclusivity_check_passed": true, - "last_status_update": "2025-09-01T02:15:35Z" - }, - "discovery_info": { - "discovered_date": "2025-09-01T08:30:15Z", - "discovery_method": "everything_api", - "auto_discovered": true - } - } - ], - "statistics": { - "total_backups_created": 15, - "total_backup_size_mb": 2450.5, - "average_backup_time_seconds": 45.2, - "last_global_scan": "2025-09-01T08:30:15Z", - "projects_with_errors": 0, - "projects_pending_retry": 0 - } -} diff --git a/autobackups/requirements.txt b/autobackups/requirements.txt deleted file mode 100644 index c0139b7..0000000 --- a/autobackups/requirements.txt +++ /dev/null @@ -1,32 +0,0 @@ -# Core Framework -Flask==2.3.3 -Werkzeug==2.3.7 - -# Scheduling -APScheduler==3.10.4 - -# Everything API Integration -PyEverything==1.0.1 # Wrapper para Everything SDK - -# File Operations and Utilities -pathlib2==2.3.7.post1 # Enhanced pathlib for Python 3.12 -psutil==5.9.5 # System utilities (disk space monitoring) -filelock==3.12.4 # File locking for concurrent access - -# Web Interface -Jinja2==3.1.2 # Template engine for Flask - -# Configuration and Data -jsonschema==4.19.1 # JSON schema validation - -# Logging -colorlog==6.7.0 # Colored logging output - -# Windows-specific dependencies -pywin32==306; sys_platform == "win32" # Windows API access for low priority - -# Development and Testing (opcional, remove for production) -pytest==7.4.2 -pytest-flask==1.2.0 -black==23.9.1 # Code formatting -flake8==6.1.0 # Code linting diff --git a/autobackups/src/app.py b/autobackups/src/app.py deleted file mode 100644 index f890e2c..0000000 --- a/autobackups/src/app.py +++ /dev/null @@ -1,275 +0,0 @@ -""" -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() diff --git a/autobackups/src/models/__init__.py b/autobackups/src/models/__init__.py deleted file mode 100644 index 695ef75..0000000 --- a/autobackups/src/models/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -AutoBackups - Data Models -Modelos de datos para configuración y manejo de proyectos -""" - -from .config_model import Config -from .project_model import Project, ProjectStatus - -__all__ = ['Config', 'Project', 'ProjectStatus'] diff --git a/autobackups/src/services/__init__.py b/autobackups/src/services/__init__.py deleted file mode 100644 index cd57328..0000000 --- a/autobackups/src/services/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -AutoBackups - Services -Servicios principales para backup y descubrimiento de proyectos -""" - -# Imports comentados temporalmente para evitar problemas de dependencias circulares -# from .project_discovery_service import ProjectDiscoveryService -# from .backup_service import BackupService -# from .scheduler_service import SchedulerService -from .basic_backup_service import BasicBackupService - -__all__ = ['BasicBackupService'] diff --git a/autobackups/src/utils/__init__.py b/autobackups/src/utils/__init__.py deleted file mode 100644 index 5af83ed..0000000 --- a/autobackups/src/utils/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -""" -AutoBackups - Utilities -Funciones de utilidad para hashing, manejo de archivos y otras operaciones -""" - -from .hash_utils import HashCalculator -from .file_utils import FileChecker, DiskSpaceChecker -from .everything_wrapper import EverythingSearcher - -__all__ = ['HashCalculator', 'FileChecker', 'DiskSpaceChecker', 'EverythingSearcher'] diff --git a/config.json b/config.json index 26bcbd7..97748ef 100644 --- a/config.json +++ b/config.json @@ -24,13 +24,16 @@ "default_schedule": "daily", "default_schedule_time": "02:00", "retry_delay_hours": 1, - "max_concurrent_backups": 2, - "backup_timeout_minutes": 60 + "backup_timeout_minutes": 0, + "min_free_space_mb": 100, + "scan_interval_minutes": 60, + "min_backup_interval_minutes": 10 }, "everything_api": { + "dll_path": "Everything-SDK\\dll\\Everything64.dll", "enabled": true, - "fallback_to_filesystem_search": true, - "search_depth": -1 + "search_depth": -1, + "skip_last_level_for_s7p": true }, "web_interface": { "host": "127.0.0.1", @@ -46,6 +49,12 @@ "compression_level": 6, "include_subdirectories": true, "preserve_directory_structure": true, - "hash_algorithm": "md5" + "hash_algorithm": "md5", + "hash_includes": ["timestamp", "size"], + "backup_type": "complete", + "process_priority": "low", + "sequential_execution": true, + "filename_format": "HH-MM-SS_projects.zip", + "date_format": "YYYY-MM-DD" } } diff --git a/projects.json b/projects.json index 8820777..3c68e69 100644 --- a/projects.json +++ b/projects.json @@ -8,11 +8,12 @@ { "id": "example_project_001", "name": "PLC_MainLine_Example", - "path": "C:\\Projects\\Siemens\\PLC_MainLine", + "path": "C:\\Projects\\Siemens\\LineA\\Project1", "type": "siemens_s7", - "s7p_file": "C:\\Projects\\Siemens\\PLC_MainLine\\PLC_MainLine.s7p", + "s7p_file": "C:\\Projects\\Siemens\\LineA\\Project1\\project.s7p", "observation_directory": "C:\\Projects\\Siemens", - "relative_path": "PLC_MainLine", + "relative_path": "LineA\\Project1", + "backup_path": "LineA\\Project1", "schedule_config": { "schedule": "daily", "schedule_time": "02:00", @@ -21,7 +22,7 @@ }, "backup_history": { "last_backup_date": "2025-09-01T02:15:30Z", - "last_backup_file": "D:\\Backups\\AutoBackups\\2025-09-01_02-15-30\\Projects_Siemens_PLC_MainLine.zip", + "last_backup_file": "D:\\Backups\\AutoBackups\\LineA\\Project1\\2025-09-01\\02-15-30_projects.zip", "backup_count": 5, "last_successful_backup": "2025-09-01T02:15:30Z" }, @@ -29,8 +30,10 @@ "last_s7p_hash": "abc123def456789", "last_full_hash": "def789ghi012345", "last_s7p_timestamp": "2025-08-31T14:30:00Z", + "last_s7p_size": 2048576, "last_scan_timestamp": "2025-09-01T02:10:00Z", - "file_count": 1247 + "file_count": 1247, + "total_size_bytes": 125847296 }, "status": { "current_status": "ready", @@ -38,6 +41,7 @@ "retry_count": 0, "next_retry": null, "files_in_use": false, + "exclusivity_check_passed": true, "last_status_update": "2025-09-01T02:15:35Z" }, "discovery_info": { diff --git a/requirements.txt b/requirements.txt index 7c45843..c0139b7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -5,12 +5,12 @@ Werkzeug==2.3.7 # Scheduling APScheduler==3.10.4 -# Everything API Integration (si está disponible) -# python-everything==1.0.1 # Descomenta si existe la librería +# Everything API Integration +PyEverything==1.0.1 # Wrapper para Everything SDK # File Operations and Utilities pathlib2==2.3.7.post1 # Enhanced pathlib for Python 3.12 -psutil==5.9.5 # System and process utilities +psutil==5.9.5 # System utilities (disk space monitoring) filelock==3.12.4 # File locking for concurrent access # Web Interface @@ -22,11 +22,11 @@ jsonschema==4.19.1 # JSON schema validation # Logging colorlog==6.7.0 # Colored logging output +# Windows-specific dependencies +pywin32==306; sys_platform == "win32" # Windows API access for low priority + # Development and Testing (opcional, remove for production) pytest==7.4.2 pytest-flask==1.2.0 black==23.9.1 # Code formatting flake8==6.1.0 # Code linting - -# Windows-specific dependencies -pywin32==306; sys_platform == "win32" # Windows API access diff --git a/src/app.py b/src/app.py index def15cb..f890e2c 100644 --- a/src/app.py +++ b/src/app.py @@ -1,38 +1,275 @@ -from flask import Flask -from apscheduler.schedulers.background import BackgroundScheduler -import json +""" +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 -app = Flask(__name__) +# Agregar el directorio src al path para imports +current_dir = Path(__file__).parent +src_dir = current_dir +sys.path.insert(0, str(src_dir)) -# Load configuration from config.json -with open('config.json') as config_file: - config = json.load(config_file) +# 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 -# Initialize the scheduler -scheduler = BackgroundScheduler() -def backup_projects(): - # Logic to scan directories and perform backups - pass +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 -# Schedule the backup task -scheduler.add_job(backup_projects, 'interval', hours=config.get('backup_interval_hours', 24)) -scheduler.start() -@app.route('/') -def index(): - return "Welcome to the Auto Backup System" +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) -@app.route('/backup', methods=['POST']) -def trigger_backup(): - # Logic to manually trigger a backup - return "Backup triggered" -@app.route('/status', methods=['GET']) -def backup_status(): - # Logic to check the status of backups - return "Backup status" - -if __name__ == '__main__': - app.run(host='0.0.0.0', port=5000) \ No newline at end of file +if __name__ == "__main__": + main() diff --git a/src/models/__init__.py b/src/models/__init__.py index 82789f2..695ef75 100644 --- a/src/models/__init__.py +++ b/src/models/__init__.py @@ -1 +1,9 @@ -# This file is intentionally left blank. \ No newline at end of file +""" +AutoBackups - Data Models +Modelos de datos para configuración y manejo de proyectos +""" + +from .config_model import Config +from .project_model import Project, ProjectStatus + +__all__ = ['Config', 'Project', 'ProjectStatus'] diff --git a/autobackups/src/models/config_model.py b/src/models/config_model.py similarity index 100% rename from autobackups/src/models/config_model.py rename to src/models/config_model.py diff --git a/autobackups/src/models/project_model.py b/src/models/project_model.py similarity index 100% rename from autobackups/src/models/project_model.py rename to src/models/project_model.py diff --git a/src/routes/__init__.py b/src/routes/__init__.py deleted file mode 100644 index f46db5b..0000000 --- a/src/routes/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from flask import Blueprint - -bp = Blueprint('routes', __name__) - -from . import backup_routes, status_routes, config_routes \ No newline at end of file diff --git a/src/services/__init__.py b/src/services/__init__.py index 82789f2..cd57328 100644 --- a/src/services/__init__.py +++ b/src/services/__init__.py @@ -1 +1,12 @@ -# This file is intentionally left blank. \ No newline at end of file +""" +AutoBackups - Services +Servicios principales para backup y descubrimiento de proyectos +""" + +# Imports comentados temporalmente para evitar problemas de dependencias circulares +# from .project_discovery_service import ProjectDiscoveryService +# from .backup_service import BackupService +# from .scheduler_service import SchedulerService +from .basic_backup_service import BasicBackupService + +__all__ = ['BasicBackupService'] diff --git a/autobackups/src/services/basic_backup_service.py b/src/services/basic_backup_service.py similarity index 100% rename from autobackups/src/services/basic_backup_service.py rename to src/services/basic_backup_service.py diff --git a/autobackups/src/services/project_discovery_service.py b/src/services/project_discovery_service.py similarity index 100% rename from autobackups/src/services/project_discovery_service.py rename to src/services/project_discovery_service.py diff --git a/src/utils/__init__.py b/src/utils/__init__.py index e73904d..5af83ed 100644 --- a/src/utils/__init__.py +++ b/src/utils/__init__.py @@ -1,19 +1,10 @@ -def hash_timestamps(file_paths): - # Implement hashing logic for file timestamps - pass +""" +AutoBackups - Utilities +Funciones de utilidad para hashing, manejo de archivos y otras operaciones +""" -def check_file_access(file_path): - # Implement logic to check if a file is in use - pass +from .hash_utils import HashCalculator +from .file_utils import FileChecker, DiskSpaceChecker +from .everything_wrapper import EverythingSearcher -def get_everything_results(query): - # Implement interaction with the Everything API - pass - -def compress_files(file_paths, destination): - # Implement file compression logic - pass - -def log_backup_status(project_name, status): - # Implement logging of backup status - pass \ No newline at end of file +__all__ = ['HashCalculator', 'FileChecker', 'DiskSpaceChecker', 'EverythingSearcher'] diff --git a/autobackups/src/utils/everything_wrapper.py b/src/utils/everything_wrapper.py similarity index 100% rename from autobackups/src/utils/everything_wrapper.py rename to src/utils/everything_wrapper.py diff --git a/autobackups/src/utils/file_utils.py b/src/utils/file_utils.py similarity index 100% rename from autobackups/src/utils/file_utils.py rename to src/utils/file_utils.py diff --git a/autobackups/src/utils/hash_utils.py b/src/utils/hash_utils.py similarity index 100% rename from autobackups/src/utils/hash_utils.py rename to src/utils/hash_utils.py diff --git a/static/css b/static/css deleted file mode 100644 index ff6c787..0000000 --- a/static/css +++ /dev/null @@ -1 +0,0 @@ -/* This file is intentionally left blank. */ \ No newline at end of file diff --git a/static/js b/static/js deleted file mode 100644 index 559825e..0000000 --- a/static/js +++ /dev/null @@ -1 +0,0 @@ -// This file is intentionally left blank. \ No newline at end of file diff --git a/templates/index.html b/templates/index.html deleted file mode 100644 index a4d33d5..0000000 --- a/templates/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - Auto Backups - - - -
-

Auto Backups

-
-

Backup Status

-
    - -
-
-
-

Backup Controls

- - - - -
-
- - - \ No newline at end of file