193 lines
8.1 KiB
PowerShell
193 lines
8.1 KiB
PowerShell
|
function Get-PackageManifest {
|
|||
|
<#
|
|||
|
.SYNOPSIS
|
|||
|
Given a path, find the AlkamiManifest in that location.
|
|||
|
However, this should return either an xml, json, etc formatted value as a dotted object
|
|||
|
This also validates the manifest to be valid
|
|||
|
|
|||
|
.PARAMETER Path
|
|||
|
This can be the path to the known manifest file, or to a folder.
|
|||
|
This will find the first manifest preferring xml over json etc, in a given folder.
|
|||
|
This folder does not expect to find manifests lower than the current file, but may look in the parent folder for a manifest
|
|||
|
|
|||
|
.PARAMETER RawContent
|
|||
|
Can be used to pass in raw content to let it be parsed for us
|
|||
|
|
|||
|
.PARAMETER SkipTests
|
|||
|
Use this to skip tests when reading the package. Use sparingly.
|
|||
|
|
|||
|
.PARAMETER PackageName
|
|||
|
Optional package name.
|
|||
|
|
|||
|
.PARAMETER ManifestSource
|
|||
|
Optional information including the feed source, name, and version
|
|||
|
#>
|
|||
|
[CmdletBinding(DefaultParameterSetName = 'Path')]
|
|||
|
[OutputType([object])]
|
|||
|
param (
|
|||
|
[Parameter(Mandatory = $true, ParameterSetName = 'Path')]
|
|||
|
[ValidateNotNullOrEmpty()]
|
|||
|
$Path,
|
|||
|
[Parameter(Mandatory = $true, ParameterSetName = 'RawContent')]
|
|||
|
[ValidateNotNullOrEmpty()]
|
|||
|
$RawContent,
|
|||
|
[switch]$SkipTests,
|
|||
|
[Parameter(Mandatory = $false)]
|
|||
|
[string]$PackageName,
|
|||
|
[Parameter(Mandatory = $false)]
|
|||
|
[string]$ManifestSource
|
|||
|
)
|
|||
|
|
|||
|
$logLead = Get-LogLeadName
|
|||
|
$fileContent = $RawContent
|
|||
|
$extension = $null
|
|||
|
|
|||
|
if ($PSCmdlet.ParameterSetName -eq 'Path') {
|
|||
|
$isPackage = $false
|
|||
|
$packagePath = (Get-ChocolateyInstallPath)
|
|||
|
|
|||
|
$validManifestFilenames = (Get-ValidPackageManifestFilenames)
|
|||
|
|
|||
|
if (!(Test-Path $Path)) {
|
|||
|
throw "$logLead : Provided path was not valid, or is not found. Please ensure your value is a valid path on disk. Path: [$Path]"
|
|||
|
}
|
|||
|
|
|||
|
# Normally this would write an error to indicate a problem
|
|||
|
# We don't need that, we're just curious if it matches a package location so we can treat it like a package
|
|||
|
if (Test-PathIsInApprovedPackageLocation -Path $Path -ErrorAction SilentlyContinue) {
|
|||
|
$isPackage = $true
|
|||
|
}
|
|||
|
|
|||
|
$item = (Get-Item $Path)
|
|||
|
$leafName = $null
|
|||
|
if (!$item.PSIsContainer) {
|
|||
|
# path was a folder
|
|||
|
$leafName = (Split-Path -Path $Path -Leaf)
|
|||
|
# make $Path be a folder only
|
|||
|
$Path = (Split-Path -Path $Path -Parent)
|
|||
|
} else {
|
|||
|
# Otherwise $Path is already a folder
|
|||
|
}
|
|||
|
|
|||
|
if (![string]::IsNullOrWhiteSpace($leafName)) {
|
|||
|
if (!$validManifestFilenames.Contains($leafName)) {
|
|||
|
Write-Warning "$logLead : Supplied file is not a valid manifest name. Defaulting to a manifest filename lookup"
|
|||
|
$leafName = $null
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ([string]::IsNullOrWhiteSpace($leafName)) {
|
|||
|
# this means "label the loop that you want to exit early in the break statement later"
|
|||
|
:fileLookup do {
|
|||
|
foreach ($candidateName in $validManifestFilenames) {
|
|||
|
$candidatePath = (Join-Path -Path $Path -ChildPath $candidateName)
|
|||
|
Write-Verbose "$logLead : Looking for a manifest candidate at [$candidatePath]"
|
|||
|
$item = (Get-Item -Path $candidatePath -ErrorAction Ignore)
|
|||
|
if ($null -ne $item) {
|
|||
|
# we found an item, this is good
|
|||
|
$leafName = $candidateName
|
|||
|
break fileLookup
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$Path = (Split-Path $Path -Parent)
|
|||
|
if ([string]::IsNullOrWhiteSpace($Path)) {
|
|||
|
Write-Error "Could not find an AlkamiManifest in the specified folder or parent folders"
|
|||
|
return $null
|
|||
|
}
|
|||
|
|
|||
|
if ($isPackage -and (Test-PathsAreEqual -Source $Path -Target $packagePath)) {
|
|||
|
Write-Error "$logLead : Parent package folder found, no manifest found. Please verify expected folder contains a manifest."
|
|||
|
return $null
|
|||
|
}
|
|||
|
} while ($true)
|
|||
|
}
|
|||
|
|
|||
|
$manifestPath = (Join-Path -Path $Path -ChildPath $leafName)
|
|||
|
|
|||
|
if (!(Test-Path $manifestPath)) {
|
|||
|
Write-Error "$logLead : Could not find manifest file in path [$Path]"
|
|||
|
}
|
|||
|
|
|||
|
$fileContent = (Get-Content -Path $manifestPath -Raw)
|
|||
|
|
|||
|
if ([string]::IsNullOrWhiteSpace($fileContent)) {
|
|||
|
throw "$logLead : Content of [$manifestPath] is empty or whitespace. This file can not be empty for validation to continue"
|
|||
|
}
|
|||
|
|
|||
|
$extension = [System.IO.Path]::GetExtension($manifestPath)
|
|||
|
} else {
|
|||
|
# fileContent was set to rawContent
|
|||
|
if ($null -ne $fileContent) {
|
|||
|
if ($fileContent -is [string]) {
|
|||
|
$firstCharacter = $fileContent[0]
|
|||
|
if ($firstCharacter -eq '<') {
|
|||
|
$extension = '.xml'
|
|||
|
}
|
|||
|
if ($firstCharacter -eq '{') {
|
|||
|
$extension = '.json'
|
|||
|
}
|
|||
|
} elseif ($fileContent -is [xml]) {
|
|||
|
$extension = '.xml'
|
|||
|
} else {
|
|||
|
# heck, idk, let's pretend it's json and try it and see what happens
|
|||
|
$extension = '.json'
|
|||
|
}
|
|||
|
if (!(Test-StringIsNullOrWhitespace -Value $ManifestSource)) {
|
|||
|
$manifestPath = $ManifestSource
|
|||
|
} elseif (!(Test-StringIsNullOrWhitespace -Value $PackageName)) {
|
|||
|
$manifestPath = $PackageName
|
|||
|
} else {
|
|||
|
$manifestPath = "File content was provided with no name"
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
$targetObject = $null
|
|||
|
|
|||
|
switch ($extension) {
|
|||
|
'.json' { $targetObject = (ConvertFrom-Json $fileContent) }
|
|||
|
'.xml' {
|
|||
|
try {
|
|||
|
$targetObject = (ConvertFrom-Xml ([xml]($fileContent))).packageManifest
|
|||
|
} catch [System.Management.Automation.RuntimeException] {
|
|||
|
if ($null -ne $_.FullyQualifiedErrorId -and $_.FullyQualifiedErrorId -eq "InvalidCastToXmlDocument") {
|
|||
|
if($null -eq $PackageName)
|
|||
|
{
|
|||
|
# Append a random 4 digit number so we don't get identity collisions
|
|||
|
$date = Get-Date
|
|||
|
$random = Get-Random -Maximum 10000 -SetSeed $date.Millisecond
|
|||
|
$PackageName = "UnknownPackageName_$random"
|
|||
|
}
|
|||
|
|
|||
|
$problemMessage = "Couldn't parse manifest XML for [$PackageName]. Please contact the appropriate dev team."
|
|||
|
Write-Warning "$loglead : $problemMessage. Exception was:"
|
|||
|
Write-Warning $_.Exception
|
|||
|
|
|||
|
$sanitizedProblemMessage = ConvertTo-SafeTeamCityMessage -InputText $problemMessage
|
|||
|
|
|||
|
Write-Host "##teamcity[buildProblem description='$sanitizedProblemMessage' identity='$PackageName']"
|
|||
|
}
|
|||
|
}
|
|||
|
# even if there was a content there, it may not have had a root called <packageManifest>
|
|||
|
# anchoring to remove the .packageManifest reduces a lot of other complexities elsewhere
|
|||
|
if ($null -eq $targetObject) {
|
|||
|
throw "$logLead : No valid packageManifest found in [$manifestPath]"
|
|||
|
}
|
|||
|
}
|
|||
|
default {throw "$logLead : The content passed in appears to not be xml or json. Please verify the source data is an AlkamiManifest content."}
|
|||
|
}
|
|||
|
|
|||
|
# Can't combine the two jumps because it doesn't early-abort on comparisons
|
|||
|
# Use skipping tests sparingly, prefer to only when they are already installed.
|
|||
|
# That does not mean "comparing the path is in the package repository location"
|
|||
|
# because for chocolatey it always will be, it's small sub-paths differentiation there.
|
|||
|
if (!$SkipTests) {
|
|||
|
if (!(Test-AlkamiManifest -TargetObject $targetObject)) {
|
|||
|
Write-Warning "$logLead : Manifest at [$manifestPath] failed processing. Please resolve errors and reprocess."
|
|||
|
throw "$logLead : Can not parse manifest properly."
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return $targetObject
|
|||
|
}
|