Private/WinGet/Get-HydrationWinGetAppTemplates.ps1
|
function Get-HydrationWinGetAppTemplates { <# .SYNOPSIS Gets WinGet app templates from the repo-owned starter pack. .DESCRIPTION Loads WinGet app templates from Templates/MobileApps/Windows/WinGet/Apps and validates them against the repo-owned JSON schema. Optionally filters by template ID or a preset definition from Templates/MobileApps/Windows/WinGet/Presets. .PARAMETER TemplatePath The root WinGet template path. Defaults to Templates/MobileApps/Windows/WinGet. .PARAMETER TemplateId One or more template IDs to load. .PARAMETER PresetId Optional preset ID to resolve from Templates/MobileApps/Windows/WinGet/Presets. .OUTPUTS PSCustomObject #> [CmdletBinding()] [OutputType([pscustomobject[]])] param( [Parameter()] [string]$TemplatePath, [Parameter()] [string[]]$TemplateId, [Parameter()] [string]$PresetId ) function Get-TemplateErrorRecord { param( [Parameter(Mandatory)] [System.Exception]$Exception, [Parameter(Mandatory)] [string]$ErrorId, [Parameter(Mandatory)] [System.Management.Automation.ErrorCategory]$Category, [Parameter()] [object]$TargetObject ) return [System.Management.Automation.ErrorRecord]::new( $Exception, $ErrorId, $Category, $TargetObject ) } function Confirm-TemplatePath { param( [Parameter(Mandatory)] [string]$Path, [Parameter(Mandatory)] [string]$ErrorId, [Parameter(Mandatory)] [string]$Message ) if (-not (Test-Path -Path $Path)) { $errorRecord = Get-TemplateErrorRecord -Exception ([System.IO.FileNotFoundException]::new($Message)) ` -ErrorId $ErrorId ` -Category ([System.Management.Automation.ErrorCategory]::ObjectNotFound) ` -TargetObject $Path $PSCmdlet.ThrowTerminatingError($errorRecord) } } function Add-ResolvedTemplateId { param( [Parameter()] [AllowNull()] [string]$Id ) if (-not [string]::IsNullOrWhiteSpace($Id) -and -not $resolvedTemplateIds.Contains($Id)) { $resolvedTemplateIds.Add($Id) } } function Get-TemplateFileById { param( [Parameter(Mandatory)] [string]$Id, [Parameter(Mandatory)] [System.Collections.Generic.Dictionary[string, System.IO.FileInfo]]$TemplateFileIndex ) if ($TemplateFileIndex.ContainsKey($Id)) { return $TemplateFileIndex[$Id] } $currentTemplatePath = Join-Path -Path $appPath -ChildPath "$Id.json" $errorRecord = Get-TemplateErrorRecord -Exception ([System.IO.FileNotFoundException]::new("WinGet template file not found: $currentTemplatePath")) ` -ErrorId 'WinGetTemplateFileNotFound' ` -Category ([System.Management.Automation.ErrorCategory]::ObjectNotFound) ` -TargetObject $currentTemplatePath $PSCmdlet.ThrowTerminatingError($errorRecord) } function Test-WinGetTemplateJson { param( [Parameter(Mandatory)] [string]$Path, [Parameter(Mandatory)] [string]$SchemaPath, [Parameter(Mandatory)] [string]$ValidationErrorId, [Parameter(Mandatory)] [string]$InvalidErrorId, [Parameter(Mandatory)] [string]$InvalidMessage ) try { $templateIsValid = Test-Json -Path $Path -SchemaFile $SchemaPath -ErrorAction Stop } catch { $errorRecord = Get-TemplateErrorRecord -Exception $_.Exception ` -ErrorId $ValidationErrorId ` -Category ([System.Management.Automation.ErrorCategory]::InvalidData) ` -TargetObject $Path $PSCmdlet.ThrowTerminatingError($errorRecord) } if (-not $templateIsValid) { $errorRecord = Get-TemplateErrorRecord -Exception ([System.InvalidOperationException]::new($InvalidMessage)) ` -ErrorId $InvalidErrorId ` -Category ([System.Management.Automation.ErrorCategory]::InvalidData) ` -TargetObject $Path $PSCmdlet.ThrowTerminatingError($errorRecord) } } $templatePathWasProvided = $PSBoundParameters.ContainsKey('TemplatePath') if (-not $TemplatePath) { $TemplatePath = Join-Path -Path $script:TemplatesPath -ChildPath 'MobileApps/Windows/WinGet' } $appPath = Join-Path -Path $TemplatePath -ChildPath 'Apps' $presetPath = Join-Path -Path $TemplatePath -ChildPath 'Presets' $schemaPath = Join-Path -Path $TemplatePath -ChildPath 'Schemas/winGetAppTemplate.schema.json' $presetSchemaPath = Join-Path -Path $TemplatePath -ChildPath 'Schemas/winGetAppPreset.schema.json' $requestedTemplateIds = @($TemplateId | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }) if (-not (Test-Path -Path $TemplatePath) -and -not $templatePathWasProvided -and -not $PresetId -and $requestedTemplateIds.Count -eq 0) { Write-Verbose "WinGet template root not found: $TemplatePath" return @() } Confirm-TemplatePath -Path $TemplatePath -ErrorId 'WinGetTemplateRootNotFound' -Message "WinGet template root not found: $TemplatePath" Confirm-TemplatePath -Path $appPath -ErrorId 'WinGetTemplateAppPathNotFound' -Message "WinGet template app path not found: $appPath" Confirm-TemplatePath -Path $schemaPath -ErrorId 'WinGetTemplateSchemaNotFound' -Message "WinGet app template schema not found: $schemaPath" Confirm-TemplatePath -Path $presetSchemaPath -ErrorId 'WinGetPresetSchemaNotFound' -Message "WinGet preset schema not found: $presetSchemaPath" $resolvedTemplateIds = [System.Collections.Generic.List[string]]::new() if ($PresetId) { Confirm-TemplatePath -Path $presetPath -ErrorId 'WinGetTemplatePresetPathNotFound' -Message "WinGet template preset path not found: $presetPath" $presetFile = Join-Path -Path $presetPath -ChildPath "$PresetId.json" Confirm-TemplatePath -Path $presetFile -ErrorId 'WinGetTemplatePresetNotFound' -Message "WinGet template preset not found: $presetFile" Test-WinGetTemplateJson -Path $presetFile ` -SchemaPath $presetSchemaPath ` -ValidationErrorId 'WinGetTemplatePresetValidationFailed' ` -InvalidErrorId 'WinGetTemplatePresetInvalid' ` -InvalidMessage "WinGet preset failed schema validation: $presetFile" $presetDefinition = Get-Content -Path $presetFile -Raw -Encoding utf8 | ConvertFrom-Json -Depth 100 foreach ($presetTemplateId in $presetDefinition.appIds) { Add-ResolvedTemplateId -Id $presetTemplateId } } foreach ($requestedTemplateId in $requestedTemplateIds) { Add-ResolvedTemplateId -Id $requestedTemplateId } if ($resolvedTemplateIds.Count -gt 0) { $templateFileIndex = [System.Collections.Generic.Dictionary[string, System.IO.FileInfo]]::new([System.StringComparer]::OrdinalIgnoreCase) foreach ($templateFile in Get-ChildItem -Path $appPath -Filter '*.json' -File) { $templateIdFromFile = [System.IO.Path]::GetFileNameWithoutExtension($templateFile.Name) if (-not $templateFileIndex.ContainsKey($templateIdFromFile)) { $templateFileIndex[$templateIdFromFile] = $templateFile } } $templateFiles = foreach ($currentTemplateId in $resolvedTemplateIds) { Get-TemplateFileById -Id $currentTemplateId -TemplateFileIndex $templateFileIndex } } else { $templateFiles = Get-ChildItem -Path $appPath -Filter '*.json' -File | Sort-Object -Property Name } $templates = foreach ($templateFile in $templateFiles) { Test-WinGetTemplateJson -Path $templateFile.FullName ` -SchemaPath $schemaPath ` -ValidationErrorId 'WinGetTemplateValidationFailed' ` -InvalidErrorId 'WinGetTemplateInvalid' ` -InvalidMessage "WinGet template failed schema validation: $($templateFile.FullName)" $template = Get-Content -Path $templateFile.FullName -Raw -Encoding utf8 | ConvertFrom-Json -Depth 100 $template | Add-Member -NotePropertyName 'TemplatePath' -NotePropertyValue $templateFile.FullName -Force if ($PresetId) { $template | Add-Member -NotePropertyName 'PresetId' -NotePropertyValue $PresetId -Force } $template } Write-Verbose "Loaded $($templates.Count) WinGet app template(s) from $TemplatePath" return $templates } |