config.py 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. from __future__ import annotations
  2. import logging
  3. import os
  4. from pathlib import Path
  5. from typing import Any, Dict, Optional, Union
  6. import yaml
  7. from rich.console import Console
  8. from .variables import Variable, VariableSection, VariableCollection
  9. logger = logging.getLogger(__name__)
  10. console = Console()
  11. class ConfigManager:
  12. """Manages configuration for the CLI application."""
  13. def __init__(self, config_path: Optional[Union[str, Path]] = None) -> None:
  14. """Initialize the configuration manager.
  15. Args:
  16. config_path: Path to the configuration file. If None, uses default location.
  17. """
  18. if config_path is None:
  19. # Default to ~/.config/boilerplates/config.yaml
  20. config_dir = Path.home() / ".config" / "boilerplates"
  21. config_dir.mkdir(parents=True, exist_ok=True)
  22. self.config_path = config_dir / "config.yaml"
  23. else:
  24. self.config_path = Path(config_path)
  25. # Create default config if it doesn't exist
  26. if not self.config_path.exists():
  27. self._create_default_config()
  28. def _create_default_config(self) -> None:
  29. """Create a default configuration file."""
  30. default_config = {
  31. "defaults": {},
  32. "preferences": {
  33. "editor": "vim",
  34. "output_dir": None,
  35. "library_paths": []
  36. }
  37. }
  38. self._write_config(default_config)
  39. logger.info(f"Created default configuration at {self.config_path}")
  40. def _read_config(self) -> Dict[str, Any]:
  41. """Read configuration from file.
  42. Returns:
  43. Dictionary containing the configuration.
  44. Raises:
  45. yaml.YAMLError: If YAML parsing fails.
  46. """
  47. try:
  48. with open(self.config_path, 'r') as f:
  49. config = yaml.safe_load(f) or {}
  50. return config
  51. except yaml.YAMLError as e:
  52. logger.error(f"Failed to parse YAML configuration: {e}")
  53. raise
  54. except Exception as e:
  55. logger.error(f"Failed to read configuration file: {e}")
  56. raise
  57. def _write_config(self, config: Dict[str, Any]) -> None:
  58. """Write configuration to file.
  59. Args:
  60. config: Dictionary containing the configuration to write.
  61. """
  62. try:
  63. with open(self.config_path, 'w') as f:
  64. yaml.dump(config, f, default_flow_style=False)
  65. logger.debug(f"Configuration written to {self.config_path}")
  66. except Exception as e:
  67. logger.error(f"Failed to write configuration file: {e}")
  68. raise
  69. def get_config_path(self) -> Path:
  70. """Get the path to the configuration file.
  71. Returns:
  72. Path to the configuration file.
  73. """
  74. return self.config_path
  75. # -------------------------
  76. # SECTION: Defaults Management
  77. # -------------------------
  78. def get_defaults(self, module_name: str) -> Dict[str, Any]:
  79. """Get default variable values for a module.
  80. Returns defaults in a flat format:
  81. {
  82. "var_name": "value",
  83. "var2_name": "value2"
  84. }
  85. Args:
  86. module_name: Name of the module
  87. Returns:
  88. Dictionary of default values (flat key-value pairs)
  89. """
  90. config = self._read_config()
  91. defaults = config.get("defaults", {})
  92. return defaults.get(module_name, {})
  93. def set_defaults(self, module_name: str, defaults: Dict[str, Any]) -> None:
  94. """Set default variable values for a module.
  95. Args:
  96. module_name: Name of the module
  97. defaults: Dictionary of defaults (flat key-value pairs):
  98. {"var_name": "value", "var2_name": "value2"}
  99. """
  100. config = self._read_config()
  101. if "defaults" not in config:
  102. config["defaults"] = {}
  103. config["defaults"][module_name] = defaults
  104. self._write_config(config)
  105. logger.info(f"Updated defaults for module '{module_name}'")
  106. def set_default_value(self, module_name: str, var_name: str, value: Any) -> None:
  107. """Set a single default variable value.
  108. Args:
  109. module_name: Name of the module
  110. var_name: Name of the variable
  111. value: Default value to set
  112. """
  113. defaults = self.get_defaults(module_name)
  114. defaults[var_name] = value
  115. self.set_defaults(module_name, defaults)
  116. logger.info(f"Set default for '{module_name}.{var_name}' = '{value}'")
  117. def get_default_value(self, module_name: str, var_name: str) -> Optional[Any]:
  118. """Get a single default variable value.
  119. Args:
  120. module_name: Name of the module
  121. var_name: Name of the variable
  122. Returns:
  123. Default value or None if not set
  124. """
  125. defaults = self.get_defaults(module_name)
  126. return defaults.get(var_name)
  127. def clear_defaults(self, module_name: str) -> None:
  128. """Clear all defaults for a module.
  129. Args:
  130. module_name: Name of the module
  131. """
  132. config = self._read_config()
  133. if "defaults" in config and module_name in config["defaults"]:
  134. del config["defaults"][module_name]
  135. self._write_config(config)
  136. logger.info(f"Cleared defaults for module '{module_name}'")
  137. # !SECTION
  138. # -------------------------
  139. # SECTION: Preferences Management
  140. # -------------------------
  141. def get_preference(self, key: str) -> Optional[Any]:
  142. """Get a user preference value.
  143. Args:
  144. key: Preference key (e.g., 'editor', 'output_dir', 'library_paths')
  145. Returns:
  146. Preference value or None if not set
  147. """
  148. config = self._read_config()
  149. preferences = config.get("preferences", {})
  150. return preferences.get(key)
  151. def set_preference(self, key: str, value: Any) -> None:
  152. """Set a user preference value.
  153. Args:
  154. key: Preference key
  155. value: Preference value
  156. """
  157. config = self._read_config()
  158. if "preferences" not in config:
  159. config["preferences"] = {}
  160. config["preferences"][key] = value
  161. self._write_config(config)
  162. logger.info(f"Set preference '{key}' = '{value}'")
  163. def get_all_preferences(self) -> Dict[str, Any]:
  164. """Get all user preferences.
  165. Returns:
  166. Dictionary of all preferences
  167. """
  168. config = self._read_config()
  169. return config.get("preferences", {})
  170. # !SECTION