Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 69 additions & 11 deletions PSCMake/Common/CMake.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,28 @@ $CMakeCandidates = @(

<#
.Synopsis
Finds the root of the CMake build - the current or ancestral folder containing a 'CMakePresets.json' file.
Finds the path of the CMakePresets file in the current or ancestral folder. This may be a 'CMakePresets.json' file
or a 'CMakeUserPresets.json' file.
#>
function FindCMakeRoot {
function FindCMakePresets {
$CurrentLocation = (Get-Location).Path
GetPathOfFileAbove $CurrentLocation 'CMakePresets.json'
GetPathOfFileAbove $CurrentLocation 'CMakeUserPresets.json', 'CMakePresets.json'
}

<#
.Synopsis
Finds the root of the CMake build - the current or ancestral folder containing CMake presets.
#>
function FindCMakeRoot {
$CMakePresetsPath = FindCMakePresets
[System.IO.Path]::GetDirectoryName($CMakePresetsPath)
}

$script:CMakePresetsPath = $null

<#
.Synopsis
Gets the path that the most recently loaded CMakePresets.json was loaded from.
Gets the path that the most recently loaded 'CMakePresets.json' or 'CMakeUserPresets.json' was loaded from.
#>
function GetCMakePresetsPath {
$script:CMakePresetsPath
Expand All @@ -64,16 +74,62 @@ function GetCMakePresets {
param(
[switch] $Silent
)
$CMakeRoot = FindCMakeRoot
if (-not $CMakeRoot) {
$script:CMakePresetsPath = FindCMakePresets
if (-not $script:CMakePresetsPath) {
if ($Silent) {
return $null
}
Write-Error "Can't find CMakePresets.json"
Write-Error "Can't find 'CMakePresets.json' or 'CMakeUserPresets.json' in the current or any parent folder."
}
$script:CMakePresetsPath = Join-Path -Path $CMakeRoot -ChildPath 'CMakePresets.json'
Write-Verbose "Presets = $CMakePresetsPath"
Get-Content $CMakePresetsPath | ConvertFrom-Json

$CMakeRoot = [System.IO.Path]::GetDirectoryName($CMakePresetsPath)
$CMakePresetsJson = $null

Write-Verbose "Presets = $CMakeRoot"

# If files were included, load them now and merge them in. Keep track of files that were included to avoid cycles.
$IncludedFiles = [System.Collections.Generic.HashSet[string]]::new()
[array] $IncludePaths = @(
$CMakePresetsPath
if ([System.IO.Path]::GetFileName($CMakePresetsPath) -ieq 'CMakeUserPresets.json') {
Join-Path -Path $CMakeRoot -ChildPath 'CMakePresets.json'
}
)

for (; ; ) {
$IncludePath, $IncludePaths = $IncludePaths
if (-not $IncludePath) {
break
}

Write-Verbose "Processing CMakePresets: $IncludePath"

# Macro substiution for include paths
$IncludePath = MacroReplacement $IncludePath $null

if (-not (Test-Path -Path $IncludePath -PathType Leaf)) {
Write-Error "Included CMake presets file '$IncludePath' not found."
}

if ($IncludedFiles.Contains($IncludePath)) {
Write-Error "Cyclic include detected for included CMake presets file '$IncludePath'."
}

$IncludeJson = Get-Content $IncludePath | ConvertFrom-Json
if (-not $CMakePresetsJson) {
$CMakePresetsJson = $IncludeJson
} else {
$CMakePresetsJson.buildPresets += Get-MemberValue -InputObject $IncludeJson -Name 'buildPresets' -Or @()
$CMakePresetsJson.configurePresets += Get-MemberValue -InputObject $IncludeJson -Name 'configurePresets' -Or @()
}

$IncludePaths += Get-MemberValue -InputObject $IncludeJson -Name 'include' -Or @()

# Add to included files set
$IncludedFiles.Add($IncludePath) | Out-Null
}

$CMakePresetsJson
}

<#
Expand Down Expand Up @@ -363,7 +419,9 @@ function MacroReplacement {
break
}
'\$\{presetName\}' {
$PresetJson.name
if ($PresetJson) {
$PresetJson.name
}
break
}
'\$\{generator\}' {
Expand Down
16 changes: 11 additions & 5 deletions PSCMake/Common/Common.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,19 @@ function DownloadFile([string] $Url, [string] $DownloadPath) {

<#
.Synopsis
Searches the given location and parent folders looking for the given file.
Searches the given location and parent folders looking for the given file(s).

.Outputs
The path to the first matching file found, or $null if none found.
#>
function GetPathOfFileAbove([string]$Location, [string]$File) {
function GetPathOfFileAbove([string]$Location, [string[]]$Files) {
for (; $Location.Length -ne 0; $Location = Split-Path $Location) {
if (Test-Path -PathType Leaf -Path (Join-Path -Path $Location -ChildPath $File)) {
$Location
break
foreach ($File in $Files) {
$Candidate = Join-Path -Path $Location -ChildPath $File
if (Test-Path -PathType Leaf -Path $Candidate) {
$Candidate
break
}
}
}
}
Expand Down
8 changes: 4 additions & 4 deletions Tests/GetCMakePresets.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ BeforeAll {

Describe 'GetCMakePresets' {
It 'Loads the CMakePresets.json when running from a folder with a CMakePresets.json' {
Mock FindCMakeRoot {
Join-Path -Path $PSScriptRoot -ChildPath 'ReferenceBuild'
Mock FindCMakePresets {
Join-Path -Path $PSScriptRoot -ChildPath 'ReferenceBuild/CMakePresets.json'
}

$ActualCMakePresetsJson = GetCMakePresets
Expand All @@ -20,15 +20,15 @@ Describe 'GetCMakePresets' {
}

It 'Reports an error when a CMakePresets.json is not found' {
Mock FindCMakeRoot {
Mock FindCMakePresets {
$null
}
{ GetCMakePresets } |
Should -Throw
}

It 'Reports an error when a CMakePresets.json is not found, unless -Silent is passed' {
Mock FindCMakeRoot {
Mock FindCMakePresets {
$null
}
GetCMakePresets -Silent |
Expand Down