ps/Modules/Alkami.PowerShell.Choco/Public/Format-ParseChocoPackages.ps1

106 lines
4.5 KiB
PowerShell
Raw Normal View History

2023-05-30 22:51:22 -07:00
function Format-ParseChocoPackages {
<#
.SYNOPSIS
Returns a list of package objects parsed from choco-style "name|version" strings.
.DESCRIPTION
Takes a list of package names and optional versions and returns array of PSObjects with properties containing
the Name and Version (if entered) parsed.
.PARAMETER Text
Can be either an array of package names with versions to parse or a NewLine-delimited string of
package names and versions.
.PARAMETER Delimiter
Delimiter to use when splitting the package name from the version in the $Text parameter. Defaults to "|"
.PARAMETER Validate
Switch to use SemVer regular expression validation on the Version. Also performs duplicate check on 'PackageName but different Version' passed into -Text parameter.
.Example
Format-ParseChocoPackages -Text @("alkami.api.afx|1.7.1-pre100","alkami.api.afx|1.7.1-pre100") -Validate
Format-ParseChocoPackages -Text alkami.api.afx|1.7.1 -Validate
Format-ParseChocoPackages -Text alkami.api.afx
Format-ParseChocoPackages -Text chocolatey|v1.7.1.0
#>
[CmdletBinding()]
[OutputType([System.Object])]
[OutputType([System.Collections.ArrayList])]
Param(
[Parameter(Mandatory = $true)]
[AllowNull()]
[object]$Text,
[Parameter(Mandatory = $false)]
[string]$Delimiter = "|",
[Parameter(Mandatory = $false)]
[switch]$Validate
)
if (!$Text) {
$packages = @()
return $packages
}
$logLead = (Get-LogLeadName)
# Detect if it's a single string passed in and split it into a string-array per line.
if(!($Text -is [array])) {
$Text = $Text.Split([Environment]::NewLine)
}
# Detect any exact duplicate lines and remove them.
# If this is coming from Classify-Packages, we've already trimmed this. But if it isn't, we still want this unique to work as expected.
if($Validate){
$Text = $Text.Trim() | Sort-Object | Get-Unique
}
Write-Verbose "$logLead : Parsing $($Text.Count) choco packages..."
$chocoPackages = [System.Collections.ArrayList]::new()
$packageMap = @{};
$Text | ForEach-Object {
if(!([string]::IsNullOrEmpty($_))) {
Write-Verbose "$logLead : Parsing $_"
$option = [System.StringSplitOptions]::RemoveEmptyEntries
$splitItem = $_.Trim().Split($Delimiter, $option)
Write-Verbose "$logLead : Package Name parsed to [$($splitItem[0])]"
Write-Verbose "$logLead : Package Version parsed to [$($splitItem[1])]"
if($Validate -and $splitItem.Count -gt 2) {
Write-Error "Package [$($_.Trim())] passed in is not in the correct SemVer3 format. Is there more than one package on a line?"
}
# Make sure that the version isn't malformed. Should be in the proper Semver format. Regular Epxression taken from https://semver.org
if($Validate -and $null -ne $splitItem[1] -and $splitItem[1] -cnotmatch "^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$") {
Write-Error "Version [$($splitItem[1])] of module [$($splitItem[0])] passed in is not in the correct SemVer3 format."
}
$properties = @{ Name = $splitItem[0]; Version = $splitItem[1]; Feed = $null; Tags = $null; IsService = $null; StartMode = $null; IsValid = $false;}
$pkg = New-Object -TypeName PSObject -Prop $properties
# Test if the package object is already in the array. Return error if same package name but different versions are in the input array.
if($Validate) {
$lowerName = $pkg.Name.ToLower()
if($packageMap.ContainsKey($lowerName)) {
if($packageMap[$lowerName] -ne $pkg.Version) {
Write-Error "Package [$($pkg.Name)] is in the list more than once with differing versions. Please review your package parameters and include only the correct version"
Write-Host "##teamcity[buildProblem description='Multiple versions of $($pkg.Name) are in the install list' identity='$($pkg.Name)']"
}
}
$packageMap[$lowerName] = $pkg.Version
}
$chocoPackages.Add($pkg) | Out-Null
}
}
Write-Verbose "$logLead : Successfully parsed $($chocoPackages.Count) packages."
return $chocoPackages
}