diff --git a/.vscode/settings.json b/.vscode/settings.json index a83440e..9f7a7f3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationForFirstPipeline", - "powershell.codeFormatting.newLineAfterCloseBrace": false + "powershell.codeFormatting.newLineAfterCloseBrace": false, + "editor.renderWhitespace": "all" } diff --git a/PSCMake/Common/CMake.ps1 b/PSCMake/Common/CMake.ps1 index e61f9d6..bfc7188 100644 --- a/PSCMake/Common/CMake.ps1 +++ b/PSCMake/Common/CMake.ps1 @@ -133,10 +133,12 @@ function GetConfigurePresetNames { $Presets = $CMakePresetsJson.configurePresets # Filter presets that have '"hidden":true' - $Presets = $Presets | Where-Object { -not (Get-MemberValue -InputObject $_ -Name 'hidden' -Or $false) } + $Presets = $Presets | + Where-Object { -not (Get-MemberValue -InputObject $_ -Name 'hidden' -Or $false) } # Filter presets that have (or their ancestors have) conditions that evaluate to $false - $Presets = $Presets | Where-Object { EvaluatePresetCondition $_ $CMakePresetsJson.configurePresets } + $Presets = $Presets | + Where-Object { EvaluatePresetCondition $_ $CMakePresetsJson.configurePresets } $Presets.name } @@ -185,48 +187,72 @@ function ResolvePresets { $PresetJson, $ConfigurePresetJson } -function ResolvePresetProperty { - param( - $CMakePresetsJson, - $ConfigurePreset, - $PropertyName - ) +<# + .Synopsis + Searches the specified preset and its ancestors, invoking the specified action for each preset. - for ($Preset = $ConfigurePreset; $Preset; ) { - $PropertyValue = Get-MemberValue -InputObject $Preset -Name $PropertyName - if ($PropertyValue) { - return $PropertyValue - } + .Parameter Preset + The preset to start searching from. - $BasePreset = Get-MemberValue $Preset 'inherits' - if (-not $BasePreset) { - break + .Parameter Presets + The collection of presets to search for 'inherit' references. + + .Description + The action should return $null to continue searching, or a non-$null value to stop searching and return that value. + + When searching multiple preset 'inherit' values, the presets will be search in order. +#> +function SearchAncestors { + param( + $Preset, + $Presets, + [scriptblock] $Action + ) + if ($null -eq $Preset) { + return $null + } + [array] $PendingPresets = @($Preset) + for (; ($null -ne $PendingPresets) -and ($PendingPresets.Count -gt 0); ) { + $Preset, $PendingPresets = $PendingPresets + $Result = & $Action $Preset + if ($null -ne $Result) { + return $Result } + [array] $BasePresets = Get-MemberValue $Preset 'inherits' -Or @() | + ForEach-Object { + $BaseParentName = $_ + $Presets | Where-Object { $_.name -eq $BaseParentName } | Select-Object -First 1 + } + $PendingPresets = $BasePresets + $PendingPresets + } +} - $Preset = $CMakePresetsJson.configurePresets | Where-Object { $_.name -eq $BasePreset } | Select-Object -First 1 +function ResolvePresetProperty { + param( + $Preset, + $Presets, + $PropertyName + ) + SearchAncestors $Preset $Presets { + param($CurrentPreset) + Get-MemberValue -InputObject $CurrentPreset -Name $PropertyName } } function EvaluatePresetCondition { param( - $PresetJson, - $PresetsJson + $Preset, + $Presets ) - - $PresetConditionJson = Get-MemberValue $PresetJson 'condition' - if ($PresetConditionJson) { - if (-not (EvaluateCondition $PresetConditionJson $PresetJson)) { + $Result = SearchAncestors $Preset $Presets { + param($CurrentPreset) + $PresetConditionJson = Get-MemberValue $CurrentPreset 'condition' + if (($PresetConditionJson) -and + (-not (EvaluateCondition $PresetConditionJson $CurrentPreset))) { return $false } } - - $BasePresetName = Get-MemberValue $PresetJson 'inherits' - if (-not $BasePresetName) { - return $true - } - - $BasePreset = $PresetsJson | Where-Object { $_.name -eq $BasePresetName } | Select-Object -First 1 - EvaluatePresetCondition $BasePreset $PresetsJson + $Result -ne $false } function EvaluateCondition { @@ -296,7 +322,7 @@ function GetBinaryDirectory { $CMakePresetsJson, $ConfigurePreset ) - $BinaryDirectory = ResolvePresetProperty -CMakePresetsJson $CMakePresetsJson $ConfigurePreset 'binaryDir' + $BinaryDirectory = ResolvePresetProperty $ConfigurePreset $CMakePresetsJson.configurePresets 'binaryDir' # Perform macro-replacement $Result = MacroReplacement $BinaryDirectory $ConfigurePreset diff --git a/Tests/ResolvePresetProperty.Tests.ps1 b/Tests/ResolvePresetProperty.Tests.ps1 index 92be33b..4d82d3c 100644 --- a/Tests/ResolvePresetProperty.Tests.ps1 +++ b/Tests/ResolvePresetProperty.Tests.ps1 @@ -9,7 +9,7 @@ Describe 'ResolvePresetProperty' { $CMakePresetsJson = Get-Content "$PSScriptRoot/ReferencePresets/CMakePresets.Single.json" | ConvertFrom-Json $ConfigurePreset = $CMakePresetsJson.configurePresets[0] - $BinaryDirectory = ResolvePresetProperty $CMakePresetsJson $ConfigurePreset 'binaryDir' + $BinaryDirectory = ResolvePresetProperty $ConfigurePreset $CMakePresetsJson.configurePresets 'binaryDir' $BinaryDirectory | Should -Be '${sourceDir}/__output/${presetName}' } @@ -17,7 +17,7 @@ Describe 'ResolvePresetProperty' { $CMakePresetsJson = Get-Content "$PSScriptRoot/ReferencePresets/CMakePresets.Inherited.json" | ConvertFrom-Json $ConfigurePreset = $CMakePresetsJson.configurePresets | Where-Object { $_.name -eq 'windows-x64' } | Select-Object -First 1 - $BinaryDirectory = ResolvePresetProperty $CMakePresetsJson $ConfigurePreset 'binaryDir' + $BinaryDirectory = ResolvePresetProperty $ConfigurePreset $CMakePresetsJson.configurePresets 'binaryDir' $BinaryDirectory | Should -Be '${sourceDir}/__output/${presetName}' } } diff --git a/Tests/SearchAncestors.Tests.ps1 b/Tests/SearchAncestors.Tests.ps1 new file mode 100644 index 0000000..cf7e2e3 --- /dev/null +++ b/Tests/SearchAncestors.Tests.ps1 @@ -0,0 +1,91 @@ +#Requires -PSEdition Core + +BeforeAll { + $script:Presets = ConvertFrom-Json -InputObject @" +[ + { + "name": "Preset1" + }, + { + "name": "Preset2", + "inherits": "Preset1" + }, + { + "name": "Preset3" + }, + { + "name": "Preset4", + "inherits": ["Preset2", "Preset3"] + } +] +"@ + $script:Preset1 = $script:Presets | Where-Object { $_.name -eq 'Preset1' } | Select-Object -First 1 + $script:Preset2 = $script:Presets | Where-Object { $_.name -eq 'Preset2' } | Select-Object -First 1 + $script:Preset3 = $script:Presets | Where-Object { $_.name -eq 'Preset3' } | Select-Object -First 1 + $script:Preset4 = $script:Presets | Where-Object { $_.name -eq 'Preset4' } | Select-Object -First 1 + + . $PSScriptRoot/../PSCMake/Common/CMake.ps1 +} + +Describe 'SearchAncestors' { + It 'Returns $null when passed a $null preset' { + SearchAncestors $null $Presets { } | + Should -Be $null + } + + It 'Searches a single preset' { + $script:VisitedPresets = @() + SearchAncestors $Preset1 $Presets { + param($CurrentPreset) + $script:VisitedPresets += $CurrentPreset.name + } | + Should -Be $null + + $script:VisitedPresets | + Should -Be @('Preset1') + } + + It 'Searches a preset and its parent' { + $script:VisitedPresets = @() + SearchAncestors $Preset2 $Presets { + param($CurrentPreset) + $script:VisitedPresets += $CurrentPreset.name + } | + Should -Be $null + + $script:VisitedPresets | + Should -Be @('Preset2', 'Preset1') + } + + It 'Returns the result of a found preset' { + $Name = SearchAncestors $Preset2 $Presets { + param($CurrentPreset) + $CurrentPreset.name + } + $Name | Should -Be 'Preset2' + } + + It 'Stops searching when a result is found' { + $script:VisitedPresets = @() + $Name = SearchAncestors $Preset2 $Presets { + param($CurrentPreset) + $script:VisitedPresets += $CurrentPreset.name + $CurrentPreset.name + } + $Name | Should -Be 'Preset2' + $script:VisitedPresets | + Should -Be @('Preset2') + } + + It 'Searches a preset and its multiple parents' { + $script:VisitedPresets = @() + SearchAncestors $Preset4 $Presets { + param($CurrentPreset) + $script:VisitedPresets += $CurrentPreset.name + } | + Should -Be $null + + $script:VisitedPresets | + Should -Be @('Preset4', 'Preset2', 'Preset1', 'Preset3') + } +}