diff --git a/scaffoldforge/config.py b/scaffoldforge/config.py new file mode 100644 index 0000000..f406eee --- /dev/null +++ b/scaffoldforge/config.py @@ -0,0 +1,129 @@ +"""Configuration management for ScaffoldForge.""" + +import os +from pathlib import Path +from typing import Any, Dict, Optional + +import yaml + + +class Config: + """Configuration management class.""" + + _instance: Optional["Config"] = None + _config: Dict[str, Any] = {} + + def __new__(cls) -> "Config": + if cls._instance is None: + cls._instance = super().__new__(cls) + return cls._instance + + def __init__(self): + if not self._config: + self._load_default_config() + + def _load_default_config(self) -> None: + """Load default configuration.""" + self._config = { + "languages": { + "python": { + "name": "Python", + "extension": ".py", + "package_manager": "pip", + "config_files": ["pyproject.toml", "requirements.txt"], + "templates": ["main.py", "utils.py", "models.py"], + }, + "javascript": { + "name": "JavaScript", + "extension": ".js", + "package_manager": "npm", + "config_files": ["package.json"], + "templates": ["index.js", "utils.js"], + }, + "go": { + "name": "Go", + "extension": ".go", + "package_manager": "go", + "config_files": ["go.mod"], + "templates": ["main.go", "utils.go"], + }, + "rust": { + "name": "Rust", + "extension": ".rs", + "package_manager": "cargo", + "config_files": ["Cargo.toml"], + "templates": ["main.rs", "lib.rs"], + }, + }, + "templates": { + "builtin_path": str(Path(__file__).parent / "templates"), + "custom_path": os.environ.get("SCAFFOLD_TEMPLATE_DIR"), + "cache_enabled": True, + "cache_ttl": 3600, + }, + "github": { + "api_rate_limit_warning": 100, + "max_retries": 3, + "retry_delay": 5, + }, + "output": { + "default_directory": "./generated", + "create_gitignore": True, + "create_readme": True, + "preserve_permissions": False, + }, + } + + def load(self, config_path: str) -> None: + """Load configuration from YAML file.""" + path = Path(config_path) + if path.exists(): + with open(path, "r") as f: + user_config = yaml.safe_load(f) or {} + self._config.update(user_config) + + def get(self, key: str, default: Any = None) -> Any: + """Get configuration value using dot notation.""" + keys = key.split(".") + value = self._config + for k in keys: + if isinstance(value, dict): + value = value.get(k) + else: + return default + return value if value is not None else default + + def get_github_token(self) -> Optional[str]: + """Get GitHub token from environment or config.""" + return os.environ.get("GITHUB_TOKEN") + + def get_template_dir(self) -> str: + """Get template directory path.""" + custom = self.get("templates.custom_path") + if custom and Path(custom).exists(): + return custom + return self.get("templates.builtin_path", "") + + def get_output_dir(self) -> str: + """Get default output directory.""" + env_dir = os.environ.get("SCAFFOLD_OUTPUT_DIR") + if env_dir: + return env_dir + return self.get("output.default_directory", "./generated") + + def get_supported_languages(self) -> list[str]: + """Get list of supported programming languages.""" + return list(self.get("languages", {}).keys()) + + +_config = Config() + + +def load_config(config_path: str) -> None: + """Load configuration from file.""" + _config.load(config_path) + + +def get_config() -> Config: + """Get the global configuration instance.""" + return _config