src/public/Configuration/Get-AitherPath.ps1
|
#Requires -Version 7.0 <# .SYNOPSIS Resolve installation or data paths from AitherZero configuration. .DESCRIPTION Get-AitherPath resolves paths from the Paths section of AitherZero configuration with proper precedence: 1. Environment variable (AITHERZERO_<PATH_KEY>) 2. config.local.psd1 override 3. config.psd1 default 4. Fallback default parameter Supports cross-platform path placeholders: - {InstallRoot} - Resolves to platform-specific installation root - {DataRoot} - Resolves to platform-specific data storage root This function ensures all automation scripts use consistent, configurable paths instead of hardcoding installation directories. .PARAMETER PathKey The path key to resolve, using dot notation relative to the Paths section. Examples: - 'InstallRoot' -> Paths.InstallRoot - 'Applications.Docker.InstallPath' -> Paths.Applications.Docker.InstallPath - 'Data.Models' -> Paths.Data.Models .PARAMETER Default Fallback value if path is not configured. Required. .PARAMETER CreateIfMissing If specified, create the directory if it doesn't exist. .PARAMETER Configuration Optional pre-loaded configuration hashtable. If not provided, calls Get-AitherConfigs. .EXAMPLE # Get Docker install path $dockerPath = Get-AitherPath -PathKey 'Applications.Docker.InstallPath' -Default '{InstallRoot}Docker' .EXAMPLE # Get models directory and ensure it exists $modelsPath = Get-AitherPath -PathKey 'Data.Models' -Default '{DataRoot}/models' -CreateIfMissing .EXAMPLE # Override via environment variable $env:AITHERZERO_APPLICATIONS_DOCKER_INSTALLPATH = 'D:\MyDocker' $path = Get-AitherPath -PathKey 'Applications.Docker.InstallPath' -Default '{InstallRoot}Docker' # Returns: D:\MyDocker .NOTES All automation scripts should use this function instead of hardcoding paths. Users can customize paths in config.local.psd1 or via environment variables. Path placeholders work cross-platform: - Windows: {InstallRoot} defaults to D:\ (or secondary drive) - Linux/macOS: {InstallRoot} defaults to $HOME/aitherzero - CI: {InstallRoot} defaults to $GITHUB_WORKSPACE/aitherzero #> function Get-AitherPath { [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory, Position = 0)] [ValidateNotNullOrEmpty()] [string]$PathKey, [Parameter(Mandatory, Position = 1)] [string]$Default, [Parameter()] [switch]$CreateIfMissing, [Parameter()] [hashtable]$Configuration ) # Load configuration if not provided if (-not $Configuration) { $Configuration = Get-AitherConfigs -ErrorAction SilentlyContinue } $resolvedPath = $null # 1. Check environment variable (highest priority) # Convert path key to env var name: Applications.Docker.InstallPath -> AITHERZERO_APPLICATIONS_DOCKER_INSTALLPATH $envVarName = "AITHERZERO_$($PathKey -replace '\.', '_')".ToUpper() $envValue = [Environment]::GetEnvironmentVariable($envVarName) if (-not [string]::IsNullOrEmpty($envValue)) { $resolvedPath = $envValue Write-Verbose "Path '$PathKey' resolved from environment variable $envVarName" } # 2. Check configuration (config.local.psd1 overrides config.psd1) if (-not $resolvedPath -and $Configuration -and $Configuration.Paths) { $pathParts = $PathKey -split '\.' $value = $Configuration.Paths foreach ($part in $pathParts) { if ($value -is [hashtable] -and $value.ContainsKey($part)) { $value = $value[$part] } else { $value = $null break } } if (-not [string]::IsNullOrEmpty($value) -and $value -is [string]) { $resolvedPath = $value Write-Verbose "Path '$PathKey' resolved from configuration" } } # 3. Use default if (-not $resolvedPath) { $resolvedPath = $Default Write-Verbose "Path '$PathKey' using default: $Default" } # Resolve {InstallRoot} and {DataRoot} placeholders $resolvedPath = Resolve-AitherPathPlaceholders -Path $resolvedPath -Configuration $Configuration # Expand environment variables in path $resolvedPath = [Environment]::ExpandEnvironmentVariables($resolvedPath) # Normalize path separators for current platform if ($IsWindows) { $resolvedPath = $resolvedPath -replace '/', '\' } else { $resolvedPath = $resolvedPath -replace '\\', '/' } # Create directory if requested if ($CreateIfMissing -and -not (Test-Path $resolvedPath)) { try { New-Item -ItemType Directory -Path $resolvedPath -Force | Out-Null Write-Verbose "Created directory: $resolvedPath" } catch { Write-AitherLog -Level Warning -Message "Failed to create directory '$resolvedPath': $_" -Source 'Get-AitherPath' -Exception $_ } } return $resolvedPath } <# .SYNOPSIS Resolve {InstallRoot} and {DataRoot} placeholders in paths. .DESCRIPTION Internal helper function to resolve path placeholders to platform-specific values from configuration or defaults. #> function Resolve-AitherPathPlaceholders { [CmdletBinding()] [OutputType([string])] param( [Parameter(Mandatory)] [string]$Path, [Parameter()] [hashtable]$Configuration ) # Determine current platform $platform = if ($env:CI -or $env:GITHUB_ACTIONS) { 'CI' } elseif ($IsWindows -or (-not $PSVersionTable.Platform) -or $PSVersionTable.Platform -eq 'Win32NT') { 'Windows' } elseif ($IsMacOS) { 'macOS' } else { 'Linux' } # Resolve {InstallRoot} if ($Path -match '\{InstallRoot\}') { $installRoot = $null # Check environment variable first if ($env:AITHERZERO_INSTALL_ROOT) { $installRoot = $env:AITHERZERO_INSTALL_ROOT } # Check config.local.psd1 override (non-env-var value) elseif ($Configuration -and $Configuration.Paths -and $Configuration.Paths.InstallRoot -and $Configuration.Paths.InstallRoot -notmatch '^\$env:') { $installRoot = $Configuration.Paths.InstallRoot } # Use platform-specific default from config elseif ($Configuration -and $Configuration.Paths -and $Configuration.Paths.InstallRootDefault -and $Configuration.Paths.InstallRootDefault[$platform]) { $installRoot = $Configuration.Paths.InstallRootDefault[$platform] } # Fallback defaults else { $installRoot = switch ($platform) { 'Windows' { 'D:\' } 'CI' { Join-Path $env:GITHUB_WORKSPACE 'aitherzero' } default { Join-Path $HOME 'aitherzero' } } } # Expand $HOME if present (for Linux/macOS defaults) if ($installRoot -match '^\$HOME') { $installRoot = $installRoot -replace '^\$HOME', $HOME } # Ensure trailing separator for consistency $sep = [IO.Path]::DirectorySeparatorChar if (-not $installRoot.EndsWith($sep) -and -not $installRoot.EndsWith('/') -and -not $installRoot.EndsWith('\')) { $installRoot += $sep } $Path = $Path -replace '\{InstallRoot\}', $installRoot Write-Verbose "Resolved {InstallRoot} to: $installRoot" } # Resolve {DataRoot} if ($Path -match '\{DataRoot\}') { $dataRoot = $null # Check environment variable first if ($env:AITHERZERO_DATA_ROOT) { $dataRoot = $env:AITHERZERO_DATA_ROOT } # Check config.local.psd1 override (non-env-var value) elseif ($Configuration -and $Configuration.Paths -and $Configuration.Paths.DataRoot -and $Configuration.Paths.DataRoot -notmatch '^\$env:') { $dataRoot = $Configuration.Paths.DataRoot } # Use platform-specific default from config elseif ($Configuration -and $Configuration.Paths -and $Configuration.Paths.DataRootDefault -and $Configuration.Paths.DataRootDefault[$platform]) { $dataRoot = $Configuration.Paths.DataRootDefault[$platform] # DataRootDefault might contain {InstallRoot}, resolve recursively if ($dataRoot -match '\{InstallRoot\}') { $dataRoot = Resolve-AitherPathPlaceholders -Path $dataRoot -Configuration $Configuration } } # Fallback defaults else { $dataRoot = switch ($platform) { 'Windows' { 'D:\AitherData' } 'CI' { Join-Path $env:GITHUB_WORKSPACE 'aitherzero-data' } default { Join-Path $HOME 'aitherzero-data' } } } # Expand $HOME if present if ($dataRoot -match '^\$HOME') { $dataRoot = $dataRoot -replace '^\$HOME', $HOME } $Path = $Path -replace '\{DataRoot\}', $dataRoot Write-Verbose "Resolved {DataRoot} to: $dataRoot" } return $Path } # Export handled by build.ps1 |