"""Profile management for env-pro.""" import os from pathlib import Path from typing import Optional, Dict, List from dotenv import dotenv_values class ProfileError(Exception): """Base exception for profile errors.""" pass class ProfileNotFoundError(ProfileError): """Raised when a profile is not found.""" pass def get_profiles_dir(project_root: Optional[Path] = None) -> Path: """Get the profiles directory path.""" if project_root is None: project_root = Path.cwd() return project_root / ".env-profiles" def get_active_profile(project_root: Optional[Path] = None) -> Optional[str]: """Get the currently active profile name.""" profiles_dir = get_profiles_dir(project_root) active_file = profiles_dir / ".active" if active_file.exists(): return active_file.read_text().strip() return None def set_active_profile(profile_name: str, project_root: Optional[Path] = None): """Set the active profile.""" profiles_dir = get_profiles_dir(project_root) profiles_dir.mkdir(parents=True, exist_ok=True) active_file = profiles_dir / ".active" active_file.write_text(profile_name) def list_profiles(project_root: Optional[Path] = None) -> List[str]: """List all available profiles.""" profiles_dir = get_profiles_dir(project_root) if not profiles_dir.exists(): return [] profiles = [] for item in profiles_dir.iterdir(): if item.is_dir() and not item.name.startswith('.'): profiles.append(item.name) return sorted(profiles) def create_profile(profile_name: str, project_root: Optional[Path] = None): """Create a new profile.""" profiles_dir = get_profiles_dir(project_root) profile_dir = profiles_dir / profile_name if profile_dir.exists(): raise ProfileError(f"Profile '{profile_name}' already exists") profile_dir.mkdir(parents=True, exist_ok=True) env_file = profile_dir / ".env" env_file.write_text("") return profile_dir def delete_profile(profile_name: str, project_root: Optional[Path] = None): """Delete a profile.""" profiles_dir = get_profiles_dir(project_root) profile_dir = profiles_dir / profile_name if not profile_dir.exists(): raise ProfileNotFoundError(f"Profile '{profile_name}' not found") import shutil shutil.rmtree(profile_dir) def get_profile_vars(profile_name: str, project_root: Optional[Path] = None) -> Dict[str, str]: """Get all variables for a profile.""" profiles_dir = get_profiles_dir(project_root) env_file = profiles_dir / profile_name / ".env" if not env_file.exists(): raise ProfileNotFoundError(f"Profile '{profile_name}' not found") vars = dotenv_values(env_file) return {k: v for k, v in vars.items() if v is not None} def set_profile_var(profile_name: str, key: str, value: str, project_root: Optional[Path] = None): """Set a variable in a profile.""" profiles_dir = get_profiles_dir(project_root) env_file = profiles_dir / profile_name / ".env" if not env_file.exists(): raise ProfileNotFoundError(f"Profile '{profile_name}' not found") vars = dotenv_values(env_file) vars[key] = value with open(env_file, 'w') as f: for k, v in vars.items(): if v is not None: f.write(f"{k}={v}\n") def delete_profile_var(profile_name: str, key: str, project_root: Optional[Path] = None): """Delete a variable from a profile.""" profiles_dir = get_profiles_dir(project_root) env_file = profiles_dir / profile_name / ".env" if not env_file.exists(): raise ProfileNotFoundError(f"Profile '{profile_name}' not found") vars = dotenv_values(env_file) if key in vars: del vars[key] with open(env_file, 'w') as f: for k, v in vars.items(): if v is not None: f.write(f"{k}={v}\n") def init_project(project_root: Optional[Path] = None): """Initialize env-pro in a project directory.""" profiles_dir = get_profiles_dir(project_root) if profiles_dir.exists(): return profiles_dir profiles_dir.mkdir(parents=True, exist_ok=True) default_profile = profiles_dir / "default" default_profile.mkdir() default_env = default_profile / ".env" default_env.write_text("") active_file = profiles_dir / ".active" active_file.write_text("default") return profiles_dir