# RepoSync/config/profile_manager.py """ Manages loading and saving of server connection profiles and application settings from a JSON file. """ import json import logging import os from pathlib import Path from typing import Dict, List, Optional, Any logger = logging.getLogger(__name__) def get_config_path() -> Path: """ Gets the path to the configuration file inside a 'config' subdirectory relative to the application's current working directory. """ base_path = Path.cwd() config_dir = base_path / "config" config_dir.mkdir(exist_ok=True) return config_dir / "profiles.json" class ProfileManager: """Handles CRUD for server profiles and app settings.""" def __init__(self): self.profiles_path = get_config_path() self.profiles: Dict[str, Dict] = {} self.settings: Dict[str, Any] = {} self.load_data() def load_data(self): """Loads both profiles and settings from the JSON file.""" logger.info(f"Loading data from: {self.profiles_path}") if not self.profiles_path.exists(): self.profiles = {} self.settings = { "bundle_path": str(Path.home() / "RepoSyncBundles"), "git_timeout": 600 # Default: 10 minutes } logger.warning("Profiles file not found. Using default settings.") return try: with open(self.profiles_path, "r", encoding="utf-8") as f: data = json.load(f) self.profiles = data.get("profiles", {}) self.settings = data.get("settings", {}) # Ensure defaults are set if they are missing from the file if "bundle_path" not in self.settings: self.settings["bundle_path"] = str(Path.home() / "RepoSyncBundles") if "git_timeout" not in self.settings: self.settings["git_timeout"] = 600 logger.info(f"Loaded {len(self.profiles)} profiles and app settings.") except (json.JSONDecodeError, IOError) as e: logger.error(f"Failed to load or parse profiles file: {e}. Starting fresh.") self.profiles = {} self.settings = { "bundle_path": str(Path.home() / "RepoSyncBundles"), "git_timeout": 600 } def save_data(self): """Saves both profiles and settings to the JSON file.""" logger.info(f"Saving data to: {self.profiles_path}") data_to_save = { "profiles": self.profiles, "settings": self.settings } try: with open(self.profiles_path, "w", encoding="utf-8") as f: json.dump(data_to_save, f, indent=4) except IOError as e: logger.error(f"Failed to save profiles file: {e}") def get_profile(self, name: str) -> Optional[Dict]: """Retrieves a single profile by name.""" return self.profiles.get(name) def get_all_profiles(self) -> Dict[str, Dict]: """Returns all loaded profiles.""" return self.profiles def get_profile_names(self) -> List[str]: """Returns a list of all profile names.""" return list(self.profiles.keys()) def add_or_update_profile(self, name: str, data: Dict): """Adds a new profile or updates an existing one.""" if not name.strip(): raise ValueError("Profile name cannot be empty.") self.profiles[name] = data self.save_data() def delete_profile(self, name: str): """Deletes a profile by name.""" if name in self.profiles: del self.profiles[name] self.save_data() def get_setting(self, key: str, default: Any = None) -> Any: """Gets a specific application setting.""" return self.settings.get(key, default) def set_setting(self, key: str, value: Any): """Sets an application setting and saves it.""" logger.info(f"Updating setting '{key}' to '{value}'") self.settings[key] = value self.save_data()