Private/DFSessionConfig.ps1
|
#Requires -Version 7.0 # The session's configuration: the hashtable passed to Start-DFSession -Config, # stored here once and read only through Get-DFConfig. Nothing reads a global # $DFConfig. Before Start-DFSession runs (e.g. a script importing DotForge only # for its helpers), every read returns its default. $script:DFSessionConfig = @{} # Every key DotForge or a companion reads. tests/DFSessionConfig.Tests.ps1 fails # when code reads a key that is missing here. Value: a one-line description. $script:DFConfigKeys = [ordered]@{ Tools = 'Tools and +groups to configure (Start-DFSession)' ExcludeTools = 'Tools and +groups removed from Tools' Defaults = 'Role -> preferred tool' Theme = 'Shared theme name' SkipSetup = 'Tools whose one-time setup never runs' SkipConflictCheck = 'Skip the coreutils shadowing check' IgnoreConflicts = 'Command names left out of the shadowing check' ShimsPath = 'Folder New-DFShim writes to' InstallVia = 'Tool -> source to install it from (beats everything, including ExcludeSources)' InstallOrder = 'Preferred source order for Install-DFTool (ordering only)' ExcludeSources = 'Sources Install-DFTool never uses (unless InstallVia names one)' BatTheme = 'bat theme' DeltaTheme = 'delta theme' FzfTheme = 'fzf theme' GlowTheme = 'glow theme' MdcatTheme = 'mdcat theme' MdvTheme = 'mdv theme' MoorTheme = 'moor theme' VividTheme = 'vivid (LS_COLORS) theme' PSReadLineTheme = 'PSReadLine theme' PSReadLineEditMode = 'PSReadLine edit mode' DotenvSafeMode = 'ps-dotenv safe mode' DotenvApprovedDirs = 'Folders ps-dotenv may load .env files from' } # Keys that existed before and what replaced them. $script:DFRemovedConfigKeys = @{ PackageManagerOrder = 'use InstallOrder (sources, ordering only) and ExcludeSources' SkipTools = 'list the tools you want in Tools, and unwanted members of a +group in ExcludeTools' CompletionMode = "set Defaults['tab-completion'] = 'inshellisense' to use inshellisense" } function Set-DFSessionConfig { <# .SYNOPSIS Validates a configuration hashtable and stores a copy as the session's configuration. .DESCRIPTION Called by Start-DFSession. An unknown key warns, suggesting the known key it most likely misspells; a key that was removed warns with what replaced it. Warnings never stop the session. The stored copy is shallow: later changes to the caller's hashtable don't affect it. .PARAMETER Config The configuration passed to Start-DFSession -Config. .OUTPUTS None. #> [CmdletBinding()] param([Parameter(Mandatory)][System.Collections.IDictionary]$Config) $known = [string[]]$script:DFConfigKeys.Keys foreach ($key in $Config.Keys) { if ($script:DFConfigKeys.Contains($key)) { continue } if ($script:DFRemovedConfigKeys.ContainsKey($key)) { Write-Warning "DotForge: config key '$key' was removed — $($script:DFRemovedConfigKeys[$key])." continue } $suggestion = Get-DFFieldSuggestion -Name $key -Known $known $hint = if ($suggestion) { " — did you mean '$suggestion'?" } else { ' (ignored)' } Write-Warning "DotForge: unknown config key '$key'$hint" } $script:DFSessionConfig = Copy-DFConfigValue $Config $script:DFSessionConfigured = $true } function Copy-DFConfigValue { <# .SYNOPSIS Deep-copies a config value: dictionaries and lists are copied recursively, scalars returned as is. .DESCRIPTION The session snapshot must not share nested objects (the Defaults hashtable, list settings) with the caller's hashtable, or changing them after Start-DFSession would silently change the session. .PARAMETER Value The value to copy. .OUTPUTS System.Object. Dictionaries come back as hashtables, lists as object arrays. #> param($Value) if ($Value -is [System.Collections.IDictionary]) { $copy = @{} foreach ($k in $Value.Keys) { $copy[$k] = Copy-DFConfigValue $Value[$k] } return $copy } if ($Value -is [System.Collections.IEnumerable] -and $Value -isnot [string]) { return , [object[]]@(foreach ($item in $Value) { Copy-DFConfigValue $item }) } $Value } $script:DFSessionConfigured = $false $script:DFLegacyConfigWarned = $false function Assert-DFSessionConfigured { <# .SYNOPSIS Warns, once per session, when an old-style global $DFConfig exists but was never passed to Start-DFSession. .DESCRIPTION DotForge no longer reads a global $DFConfig. A profile that still sets one would otherwise lose its settings silently, including protective ones (SkipSetup keeps a tool's one-time setup from changing files such as your global git config; DotenvSafeMode and DotenvApprovedDirs limit which .env files load). Failing open silently is the wrong default, so this says so loudly. It only tests that the variable exists; it never reads its values. .OUTPUTS None. #> [CmdletBinding()] param() if ($script:DFSessionConfigured -or $script:DFLegacyConfigWarned) { return } if (-not (Test-Path variable:global:DFConfig)) { return } $script:DFLegacyConfigWarned = $true Write-Warning ("DotForge: a global `$DFConfig was found but is no longer read, so none of its settings apply " + "(including SkipSetup, DotenvSafeMode and DotenvApprovedDirs). Pass it explicitly: Start-DFSession -Config `$DFConfig") } |