Skip to main content
Glama
registry_parser.py8.1 kB
"""Parser for Windows Registry Delphi configuration.""" import re import winreg from pathlib import Path from typing import Optional from src.models import BuildLogInfo, Platform class RegistryParser: """Parses Windows Registry to extract Delphi library configuration.""" # Registry base path for Delphi BDS_REGISTRY_PATH = r"Software\Embarcadero\BDS" def __init__(self, delphi_version: str = "23.0", platform: str = "Win32"): """Initialize registry parser. Args: delphi_version: Delphi version (e.g., "23.0" for Delphi 12) platform: Target platform ("Win32" or "Win64") """ self.delphi_version = delphi_version self.platform = platform self.registry_path = f"{self.BDS_REGISTRY_PATH}\\{delphi_version}\\Library\\{platform}" def parse(self) -> BuildLogInfo: """Parse registry to extract library paths and settings. Returns: BuildLogInfo with extracted configuration Raises: FileNotFoundError: If registry key not found PermissionError: If cannot access registry """ try: # Open registry key key = winreg.OpenKey( winreg.HKEY_CURRENT_USER, self.registry_path, 0, winreg.KEY_READ ) # Read values search_path = self._read_registry_value(key, "Search Path", "") debug_dcu_path = self._read_registry_value(key, "Debug DCU Path", "") # Close key winreg.CloseKey(key) # Parse paths search_paths = self._parse_path_string(search_path) # Add debug paths if present if debug_dcu_path: debug_paths = self._parse_path_string(debug_dcu_path) search_paths.extend(debug_paths) # Determine compiler path compiler_path = self._get_compiler_path() # Create BuildLogInfo return BuildLogInfo( compiler_path=compiler_path, delphi_version=self.delphi_version, platform=Platform.WIN32 if self.platform == "Win32" else Platform.WIN64, build_config="Release", # Registry doesn't specify this search_paths=self._deduplicate_paths(search_paths), namespace_prefixes=[], # Would need to read from another key unit_aliases={}, # Would need to read from another key compiler_flags=[], ) except FileNotFoundError: raise FileNotFoundError( f"Registry key not found: {self.registry_path}\n" f"Make sure Delphi {self.delphi_version} is installed." ) except PermissionError: raise PermissionError(f"Cannot access registry key: {self.registry_path}") def _read_registry_value(self, key: winreg.HKEYType, value_name: str, default: str = "") -> str: """Read a string value from registry key. Args: key: Open registry key value_name: Name of the value to read default: Default value if not found Returns: String value from registry """ try: value, _ = winreg.QueryValueEx(key, value_name) return value if value else default except FileNotFoundError: return default def _parse_path_string(self, path_string: str) -> list[Path]: """Parse a semicolon-separated path string from registry. Handles environment variables like $(BDS), $(BDSLIB), etc. Args: path_string: Semicolon-separated paths with possible env vars Returns: List of Path objects """ if not path_string: return [] paths = [] # Split by semicolons path_parts = [p.strip() for p in path_string.split(";") if p.strip()] for part in path_parts: # Expand environment variables expanded = self._expand_variables(part) if expanded: try: paths.append(Path(expanded)) except Exception: # Skip invalid paths continue return paths def _expand_variables(self, path_str: str) -> Optional[str]: """Expand Delphi environment variables in path. Common variables: - $(BDS) - Delphi installation directory - $(BDSLIB) - Library directory - $(BDSCOMMONDIR) - Common directory - $(Platform) - Platform name - $(LANGDIR) - Language directory Args: path_str: Path string with possible variables Returns: Expanded path string, or None if cannot expand """ # Get BDS (Delphi installation) path from registry try: root_key = winreg.OpenKey( winreg.HKEY_CURRENT_USER, f"{self.BDS_REGISTRY_PATH}\\{self.delphi_version}", 0, winreg.KEY_READ, ) bds_path, _ = winreg.QueryValueEx(root_key, "RootDir") winreg.CloseKey(root_key) except Exception: bds_path = f"C:\\Program Files (x86)\\Embarcadero\\Studio\\{self.delphi_version}" # Define variable mappings variables = { "$(BDS)": bds_path.rstrip("\\"), "$(BDSLIB)": f"{bds_path.rstrip('\\\\')}\\lib", "$(BDSCOMMONDIR)": f"C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\{self.delphi_version}", "$(BDSUSERDIR)": f"C:\\Users\\{self._get_username()}\\Documents\\Embarcadero\\Studio\\{self.delphi_version}", "$(BDSCatalogRepository)": f"C:\\Users\\{self._get_username()}\\Documents\\Embarcadero\\Studio\\{self.delphi_version}\\CatalogRepository", "$(BDSCatalogRepositoryAllUsers)": f"C:\\Users\\Public\\Documents\\Embarcadero\\Studio\\{self.delphi_version}\\CatalogRepository", "$(Platform)": self.platform, "$(LANGDIR)": "", # Usually empty } # Replace variables expanded = path_str for var, value in variables.items(): expanded = expanded.replace(var, value) # If still has unresolved variables, return None if "$(" in expanded: return None return expanded def _get_username(self) -> str: """Get current Windows username. Returns: Username string """ import os return os.environ.get("USERNAME", "User") def _get_compiler_path(self) -> Path: """Get compiler executable path based on platform. Returns: Path to compiler executable """ # Try to get from registry try: root_key = winreg.OpenKey( winreg.HKEY_CURRENT_USER, f"{self.BDS_REGISTRY_PATH}\\{self.delphi_version}", 0, winreg.KEY_READ, ) bds_path, _ = winreg.QueryValueEx(root_key, "RootDir") winreg.CloseKey(root_key) compiler_name = "dcc32.exe" if self.platform == "Win32" else "dcc64.exe" return Path(bds_path) / "bin" / compiler_name except Exception: # Fallback to default path compiler_name = "dcc32.exe" if self.platform == "Win32" else "dcc64.exe" return Path( f"C:\\Program Files (x86)\\Embarcadero\\Studio\\{self.delphi_version}\\bin\\{compiler_name}" ) def _deduplicate_paths(self, paths: list[Path]) -> list[Path]: """Remove duplicate paths while preserving order. Args: paths: List of paths Returns: List of unique paths """ seen = set() unique_paths = [] for path in paths: normalized = str(path).lower() if normalized not in seen: seen.add(normalized) unique_paths.append(path) return unique_paths

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Basti-Fantasti/delphi-build-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server