diff --git a/app/env_pro/core/profile.py b/app/env_pro/core/profile.py new file mode 100644 index 0000000..2a38af3 --- /dev/null +++ b/app/env_pro/core/profile.py @@ -0,0 +1,151 @@ +"""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