# profile_handler.py import logging # Assuming ConfigManager handles its own constants now from config_manager import ConfigManager, DEFAULT_PROFILE, DEFAULT_BACKUP_DIR class ProfileHandler: """Handles loading, saving, adding, removing profiles via ConfigManager.""" def __init__(self, logger, config_manager: ConfigManager): """ Initializes the ProfileHandler. Args: logger (logging.Logger): Logger instance. config_manager (ConfigManager): Instance to interact with config file. """ self.logger = logger self.config_manager = config_manager def get_profile_list(self): """Returns the list of available profile names.""" return self.config_manager.get_profile_sections() def load_profile_data(self, profile_name): """ Loads all relevant data for a given profile name. Args: profile_name (str): The name of the profile to load. Returns: dict or None: A dictionary containing all profile settings, or None if the profile doesn't exist. """ self.logger.info(f"Loading data for profile: '{profile_name}'") if profile_name not in self.get_profile_list(): self.logger.error(f"Cannot load: Profile '{profile_name}' not found.") return None # Use ConfigManager's internal knowledge of keys and defaults keys_with_defaults = self.config_manager._get_expected_keys_with_defaults() profile_data = {} # Load each option using ConfigManager for key, default_value in keys_with_defaults.items(): # Pass the actual default value from the dictionary profile_data[key] = self.config_manager.get_profile_option( profile_name, key, fallback=default_value ) # Convert loaded string values back to appropriate types if needed # Example: Booleans profile_data["autocommit"] = \ str(profile_data.get("autocommit", "False")).lower() == "true" profile_data["autobackup"] = \ str(profile_data.get("autobackup", "False")).lower() == "true" self.logger.debug(f"Loaded data for '{profile_name}': {profile_data}") return profile_data def save_profile_data(self, profile_name, profile_data): """ Saves the provided data dictionary to the specified profile name. Args: profile_name (str): The name of the profile to save. profile_data (dict): Dictionary containing the settings to save. Keys should match config options. Returns: bool: True on success, False on failure. """ if not profile_name: self.logger.warning("Cannot save: No profile name provided.") return False if not isinstance(profile_data, dict): self.logger.error("Cannot save: Invalid profile data format (not a dict).") return False self.logger.info(f"Saving data for profile: '{profile_name}'") try: # Iterate through data and save using ConfigManager for key, value in profile_data.items(): # Convert specific types back to string for storage if isinstance(value, bool): value_to_save = str(value) # Add other type conversions if necessary else: # Assume other types can be directly converted to string value_to_save = str(value) if value is not None else "" self.config_manager.set_profile_option( profile_name, key, value_to_save ) # Persist changes to the configuration file self.config_manager.save_config() self.logger.info(f"Profile '{profile_name}' saved successfully.") return True except Exception as e: self.logger.error(f"Error saving profile '{profile_name}': {e}", exc_info=True) # Let the caller (main app) show the error message return False def add_new_profile(self, profile_name): """ Adds a new profile with default settings. Args: profile_name (str): The name for the new profile. Returns: bool: True if added successfully, False otherwise. """ self.logger.info(f"Attempting to add new profile: '{profile_name}'") # Basic validation if not profile_name: self.logger.warning("Add profile failed: Name cannot be empty.") return False if profile_name in self.get_profile_list(): self.logger.warning(f"Add profile failed: '{profile_name}' already exists.") return False try: # Get defaults and customize for a new profile defaults = self.config_manager._get_expected_keys_with_defaults() defaults["bundle_name"] = f"{profile_name}_repo.bundle" defaults["bundle_name_updated"] = f"{profile_name}_update.bundle" defaults["svn_working_copy_path"] = "" # Start empty defaults["usb_drive_path"] = "" # Start empty # Set all options for the new profile section # ConfigManager.set_profile_option creates the section if needed for key, value in defaults.items(): self.config_manager.set_profile_option(profile_name, key, value) # Save the configuration file self.config_manager.save_config() self.logger.info(f"Profile '{profile_name}' added successfully.") return True except Exception as e: # Log unexpected errors during profile addition self.logger.error(f"Error adding profile '{profile_name}': {e}", exc_info=True) return False def remove_existing_profile(self, profile_name): """ Removes an existing profile (cannot remove the default profile). Args: profile_name (str): The name of the profile to remove. Returns: bool: True if removed successfully, False otherwise. """ self.logger.info(f"Attempting to remove profile: '{profile_name}'") # Validation checks if not profile_name: self.logger.warning("Remove profile failed: No name provided.") return False if profile_name == DEFAULT_PROFILE: self.logger.warning("Remove profile failed: Cannot remove default.") return False if profile_name not in self.get_profile_list(): self.logger.warning(f"Remove profile failed: '{profile_name}' not found.") return False try: # Attempt removal using ConfigManager success = self.config_manager.remove_profile_section(profile_name) if success: # Save config only if removal was successful self.config_manager.save_config() self.logger.info(f"Profile '{profile_name}' removed.") return True else: # ConfigManager should log the reason for failure self.logger.error(f"ConfigManager reported failure removing '{profile_name}'.") return False except Exception as e: # Log unexpected errors during removal self.logger.error(f"Error removing profile '{profile_name}': {e}", exc_info=True) return False