diff --git a/src/password_manager/backup.py b/src/password_manager/backup.py index b35d62a..ff0009c 100644 --- a/src/password_manager/backup.py +++ b/src/password_manager/backup.py @@ -16,16 +16,18 @@ import os import shutil import time import traceback +import fcntl from pathlib import Path from colorama import Fore from termcolor import colored from utils.file_lock import lock_file -from constants import APP_DIR +from constants import APP_DIR # Instantiate the logger logger = logging.getLogger(__name__) + class BackupManager: """ BackupManager Class @@ -35,7 +37,7 @@ class BackupManager: timestamped filenames to facilitate easy identification and retrieval. """ - BACKUP_FILENAME_TEMPLATE = 'passwords_db_backup_{timestamp}.json.enc' + BACKUP_FILENAME_TEMPLATE = "passwords_db_backup_{timestamp}.json.enc" def __init__(self, fingerprint_dir: Path): """ @@ -45,17 +47,24 @@ class BackupManager: fingerprint_dir (Path): The directory corresponding to the fingerprint. """ self.fingerprint_dir = fingerprint_dir - self.backup_dir = self.fingerprint_dir / 'backups' + self.backup_dir = self.fingerprint_dir / "backups" self.backup_dir.mkdir(parents=True, exist_ok=True) - self.index_file = self.fingerprint_dir / 'seedpass_passwords_db.json.enc' - logger.debug(f"BackupManager initialized with backup directory at {self.backup_dir}") + self.index_file = self.fingerprint_dir / "seedpass_passwords_db.json.enc" + logger.debug( + f"BackupManager initialized with backup directory at {self.backup_dir}" + ) def create_backup(self) -> None: try: index_file = self.index_file if not index_file.exists(): logger.warning("Index file does not exist. No backup created.") - print(colored("Warning: Index file does not exist. No backup created.", 'yellow')) + print( + colored( + "Warning: Index file does not exist. No backup created.", + "yellow", + ) + ) return timestamp = int(time.time()) @@ -64,56 +73,67 @@ class BackupManager: shutil.copy2(index_file, backup_file) logger.info(f"Backup created successfully at '{backup_file}'.") - print(colored(f"Backup created successfully at '{backup_file}'.", 'green')) + print(colored(f"Backup created successfully at '{backup_file}'.", "green")) except Exception as e: logger.error(f"Failed to create backup: {e}") logger.error(traceback.format_exc()) - print(colored(f"Error: Failed to create backup: {e}", 'red')) + print(colored(f"Error: Failed to create backup: {e}", "red")) def restore_latest_backup(self) -> None: try: backup_files = sorted( - self.backup_dir.glob('passwords_db_backup_*.json.enc'), + self.backup_dir.glob("passwords_db_backup_*.json.enc"), key=lambda x: x.stat().st_mtime, - reverse=True + reverse=True, ) if not backup_files: logger.error("No backup files found to restore.") - print(colored("Error: No backup files found to restore.", 'red')) + print(colored("Error: No backup files found to restore.", "red")) return latest_backup = backup_files[0] index_file = self.index_file shutil.copy2(latest_backup, index_file) logger.info(f"Restored the index file from backup '{latest_backup}'.") - print(colored(f"Restored the index file from backup '{latest_backup}'.", 'green')) + print( + colored( + f"Restored the index file from backup '{latest_backup}'.", "green" + ) + ) except Exception as e: logger.error(f"Failed to restore from backup '{latest_backup}': {e}") logger.error(traceback.format_exc()) - print(colored(f"Error: Failed to restore from backup '{latest_backup}': {e}", 'red')) + print( + colored( + f"Error: Failed to restore from backup '{latest_backup}': {e}", + "red", + ) + ) def list_backups(self) -> None: try: backup_files = sorted( - self.backup_dir.glob('passwords_db_backup_*.json.enc'), + self.backup_dir.glob("passwords_db_backup_*.json.enc"), key=lambda x: x.stat().st_mtime, - reverse=True + reverse=True, ) if not backup_files: logger.info("No backup files available.") - print(colored("No backup files available.", 'yellow')) + print(colored("No backup files available.", "yellow")) return - print(colored("Available Backups:", 'cyan')) + print(colored("Available Backups:", "cyan")) for backup in backup_files: - creation_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(backup.stat().st_mtime)) - print(colored(f"- {backup.name} (Created on: {creation_time})", 'cyan')) + creation_time = time.strftime( + "%Y-%m-%d %H:%M:%S", time.localtime(backup.stat().st_mtime) + ) + print(colored(f"- {backup.name} (Created on: {creation_time})", "cyan")) except Exception as e: logger.error(f"Failed to list backups: {e}") logger.error(traceback.format_exc()) - print(colored(f"Error: Failed to list backups: {e}", 'red')) + print(colored(f"Error: Failed to list backups: {e}", "red")) def restore_backup_by_timestamp(self, timestamp: int) -> None: backup_filename = self.BACKUP_FILENAME_TEMPLATE.format(timestamp=timestamp) @@ -121,15 +141,23 @@ class BackupManager: if not backup_file.exists(): logger.error(f"No backup found with timestamp {timestamp}.") - print(colored(f"Error: No backup found with timestamp {timestamp}.", 'red')) + print(colored(f"Error: No backup found with timestamp {timestamp}.", "red")) return try: with lock_file(backup_file, lock_type=fcntl.LOCK_SH): shutil.copy2(backup_file, self.index_file) logger.info(f"Restored the index file from backup '{backup_file}'.") - print(colored(f"Restored the index file from backup '{backup_file}'.", 'green')) + print( + colored( + f"Restored the index file from backup '{backup_file}'.", "green" + ) + ) except Exception as e: logger.error(f"Failed to restore from backup '{backup_file}': {e}") logger.error(traceback.format_exc()) - print(colored(f"Error: Failed to restore from backup '{backup_file}': {e}", 'red')) \ No newline at end of file + print( + colored( + f"Error: Failed to restore from backup '{backup_file}': {e}", "red" + ) + )