Python Snippets

Automatic Backup Manager with Compression and Rotation

import os
import shutil
import tarfile
from datetime import datetime, timedelta
from pathlib import Path
import logging

class BackupManager:
    def __init__(self, source_dir, backup_dir, max_backups=5, compression=True):
        self.source_dir = Path(source_dir)
        self.backup_dir = Path(backup_dir)
        self.max_backups = max_backups
        self.compression = compression
        
        # Create backup directory if it doesn't exist
        self.backup_dir.mkdir(parents=True, exist_ok=True)
        
        # Setup logging
        logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
        self.logger = logging.getLogger(__name__)
    
    def create_backup(self):
        """Create a new backup of the source directory"""
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_name = f"backup_{timestamp}"
        
        if self.compression:
            backup_path = self.backup_dir / f"{backup_name}.tar.gz"
            self._create_compressed_backup(backup_path)
        else:
            backup_path = self.backup_dir / backup_name
            self._create_uncompressed_backup(backup_path)
        
        self.logger.info(f"Backup created: {backup_path}")
        self._cleanup_old_backups()
    
    def _create_compressed_backup(self, backup_path):
        """Create a compressed backup using tar.gz format"""
        try:
            with tarfile.open(backup_path, "w:gz") as tar:
                tar.add(self.source_dir, arcname=self.source_dir.name)
        except Exception as e:
            self.logger.error(f"Failed to create compressed backup: {e}")
            raise
    
    def _create_uncompressed_backup(self, backup_path):
        """Create an uncompressed backup by copying directory"""
        try:
            if backup_path.exists():
                shutil.rmtree(backup_path)
            shutil.copytree(self.source_dir, backup_path)
        except Exception as e:
            self.logger.error(f"Failed to create uncompressed backup: {e}")
            raise
    
    def _cleanup_old_backups(self):
        """Remove old backups exceeding max_backups limit"""
        backups = []
        for file in self.backup_dir.iterdir():
            if file.is_file() and (file.suffix == '.gz' or 'backup_' in file.name):
                backups.append((file.stat().st_mtime, file))
        
        # Sort by modification time (newest first)
        backups.sort(reverse=True)
        
        # Remove excess backups
        for mtime, backup in backups[self.max_backups:]:
            try:
                if backup.is_file():
                    backup.unlink()
                else:
                    shutil.rmtree(backup)
                self.logger.info(f"Removed old backup: {backup}")
            except Exception as e:
                self.logger.error(f"Failed to remove old backup {backup}: {e}")

# Usage example
if __name__ == "__main__":
    # Initialize backup manager
    # Replace paths with your actual directories
    backup_manager = BackupManager(
        source_dir="./important_files",  # Directory to backup
        backup_dir="./backups",           # Where to store backups
        max_backups=3,                    # Keep only 3 most recent backups
        compression=True                  # Compress backups
    )
    
    # Create a backup
    backup_manager.create_backup()

What This Code Does

This is a complete backup management system that automatically creates timestamped backups of important directories with the following features:

  1. Automatic Compression: Creates compressed .tar.gz backups to save disk space
  2. Backup Rotation: Automatically deletes old backups to maintain only the specified number of recent backups
  3. Flexible Storage: Works with any source directory and backup destination
  4. Error Handling: Includes proper error handling and logging for troubleshooting
  5. Timestamp Management: Names backups with timestamps for easy identification

Why This Is Useful

Managing backups manually is time-consuming and error-prone. This script automates the entire process, ensuring you always have recent backups while preventing your storage from filling up with old copies. It’s especially useful for:

How to Run It

  1. Install Requirements: No external packages needed - uses only Python standard library
  2. Modify Paths: Update source_dir and backup_dir with your actual paths
  3. Configure Settings: Adjust max_backups and compression options as needed
  4. Execute: Run the script directly or import the BackupManager class

You can easily integrate this into automated workflows by:

The script will automatically handle compression, timestamping, and cleanup of old backups while providing detailed logging of all operations.