Configuration Loader
The ConfigManager is responsible for loading, validating, and merging configuration from multiple sources into a single ResolvedConfig.
Override Chain
Section titled “Override Chain”Configuration is resolved through a layered merge:
- Hardcoded defaults — defined in
ServiceRegistry::SERVICE_TYPES(default versions, ports) - Global config —
~/.dde/config.yml, loaded byConfigManager::loadGlobalConfig() - Project config —
.dde/config.yml, loaded byConfigManager::loadProjectConfig() - CLI options —
--output,--service, etc., applied at runtime
Step 1: Load Global Config
Section titled “Step 1: Load Global Config”public function loadGlobalConfig(): GlobalConfigReads ~/.dde/config.yml (path from the configDir parameter). The YAML is parsed and validated against GlobalConfigDefinition (a Symfony TreeBuilder schema). If the file is missing, empty defaults are used. If the file has invalid configuration, a warning is recorded and defaults are used.
Returns a GlobalConfig DTO containing:
output— default output format (text/json)dnsForward— DNS forward servers for dnsmasqsshKeys— SSH key paths for the agentserviceVersions— global version overrides (e.g.mariadb: "10")warnings— any validation warnings
Step 2: Load Project Config
Section titled “Step 2: Load Project Config”public function loadProjectConfig(string $projectDir): ProjectConfigReads {projectDir}/.dde/config.yml. Validated against ProjectConfigDefinition.
Returns a ProjectConfig DTO containing:
name— project name (used for hostnames, database names)services— declared services (array ofServiceDefinition)containers— container-specific settings (e.g.default_database_name)
Step 3: Merge into ResolvedConfig
Section titled “Step 3: Merge into ResolvedConfig”public function resolveConfig(string $projectDir): ResolvedConfigCalls both loaders and merges via ResolvedConfig::merge():
public static function merge(GlobalConfig $global, ProjectConfig $project, array $defaultServiceVersions = []): selfThe merge logic for service versions:
defaults (ServiceRegistry) < global config < project explicit versionSpecifically:
$serviceVersions = array_merge($defaultServiceVersions, $global->serviceVersions)- When resolving a specific service version,
getServiceVersion()checks project services first, then falls back to$serviceVersions
Project Directory Detection
Section titled “Project Directory Detection”public function findProjectDirectory(): ?stringSearches upward from the current working directory for a .dde/config.yml file. Returns the directory containing it, or null if not found.
public function findDockerProjectDirectory(): ?stringSimilar, but searches for Docker Compose files (docker-compose.yml, docker-compose.yaml, compose.yml, compose.yaml).
Worktree Detection
Section titled “Worktree Detection”public function detectWorktree(string $projectDir): ?WorktreeInfoRuns git worktree list --porcelain and parses the output to determine if the current directory is a git worktree. Returns WorktreeInfo (with main directory, worktree directory, branch name, and directory suffix) or null if not a worktree.
Hostname Resolution
Section titled “Hostname Resolution”public function resolveProjectHostname(string $projectName, ?WorktreeInfo $worktreeInfo): stringReturns the hostname for the project:
- Standard project:
{projectName}.test - Worktree:
{projectName}-{sanitized-suffix}.test
The suffix is sanitized via sanitizeWorktreeSuffix(): transliterated to ASCII, lowercased, and truncated to 63 characters (DNS label limit).