Files
MBN_STOCK_WEBVIEW/scripts/LegacyCutCoverage.psm1

246 lines
7.3 KiB
PowerShell

#Requires -Version 5.1
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
function Get-RootPrefix {
param(
[Parameter(Mandatory = $true)]
[string] $Root
)
if ($Root.EndsWith([IO.Path]::DirectorySeparatorChar) -or
$Root.EndsWith([IO.Path]::AltDirectorySeparatorChar)) {
return $Root
}
return $Root + [IO.Path]::DirectorySeparatorChar
}
function Test-IsUnderRoot {
param(
[Parameter(Mandatory = $true)]
[string] $Root,
[Parameter(Mandatory = $true)]
[string] $Candidate
)
$prefix = Get-RootPrefix -Root $Root
return $Candidate.StartsWith($prefix, [StringComparison]::OrdinalIgnoreCase)
}
function Find-ReparseAncestor {
param(
[Parameter(Mandatory = $true)]
[string] $Root,
[Parameter(Mandatory = $true)]
[string] $Candidate
)
$rootItem = Get-Item -LiteralPath $Root -Force
if (($rootItem.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
return '.'
}
$prefix = Get-RootPrefix -Root $Root
$relative = $Candidate.Substring($prefix.Length)
$current = $Root
foreach ($part in ($relative -split '[\\/]' | Where-Object { $_.Length -ne 0 })) {
$current = Join-Path $current $part
if (-not (Test-Path -LiteralPath $current)) {
break
}
$item = Get-Item -LiteralPath $current -Force
if (($item.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
return $part
}
}
return $null
}
function Resolve-CoveragePath {
param(
[Parameter(Mandatory = $true)]
[string] $Root,
[Parameter(Mandatory = $true)]
[string] $RelativePath
)
if ([string]::IsNullOrWhiteSpace($RelativePath) -or
[IO.Path]::IsPathRooted($RelativePath)) {
return [pscustomobject][ordered]@{
Status = 'RootEscape'
FullPath = $null
}
}
try {
$candidate = [IO.Path]::GetFullPath((Join-Path $Root $RelativePath))
}
catch {
return [pscustomobject][ordered]@{
Status = 'ManifestInvalid'
FullPath = $null
}
}
if (-not (Test-IsUnderRoot -Root $Root -Candidate $candidate)) {
return [pscustomobject][ordered]@{
Status = 'RootEscape'
FullPath = $null
}
}
$reparse = Find-ReparseAncestor -Root $Root -Candidate $candidate
if (-not [string]::IsNullOrEmpty($reparse)) {
return [pscustomobject][ordered]@{
Status = 'Reparse'
FullPath = $null
}
}
return [pscustomobject][ordered]@{
Status = 'Resolved'
FullPath = $candidate
}
}
function Test-AssetDefinition {
param(
[Parameter(Mandatory = $true)]
[string] $Kind,
[Parameter(Mandatory = $true)]
[string] $RelativePath
)
$allowedExtensions = switch ($Kind) {
'Image' { @('.bmp', '.jpeg', '.jpg', '.png', '.tga') }
'Texture' { @('.bmp', '.jpeg', '.jpg', '.png', '.tga', '.vrv') }
'Video' { @('.vrv') }
default { return $false }
}
$extension = [IO.Path]::GetExtension($RelativePath)
return $allowedExtensions -contains $extension.ToLowerInvariant()
}
function Test-LegacyCutCoverageState {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string] $CutRoot,
[Parameter(Mandatory = $true)]
[string[]] $Aliases,
[Parameter(Mandatory = $true)]
[object[]] $AssetRequirements,
[Parameter(Mandatory = $true)]
[int] $ReachableBuilders
)
if (-not [IO.Path]::IsPathRooted($CutRoot)) {
throw 'CutRoot must be an absolute path.'
}
$root = [IO.Path]::GetFullPath($CutRoot)
if (-not (Test-Path -LiteralPath $root -PathType Container)) {
throw 'CutRoot does not identify an existing directory.'
}
$aliasFindings = [Collections.Generic.List[object]]::new()
foreach ($alias in $Aliases) {
$relativePath = $alias + '.t2s'
$resolved = Resolve-CoveragePath -Root $root -RelativePath $relativePath
$status = $resolved.Status
if ($status -eq 'Resolved') {
if (-not (Test-Path -LiteralPath $resolved.FullPath -PathType Leaf)) {
$status = 'Missing'
}
else {
$item = Get-Item -LiteralPath $resolved.FullPath -Force
$status = if ($item.Length -le 0) { 'Empty' } else { 'Present' }
}
}
$aliasFindings.Add([pscustomobject][ordered]@{
Alias = $alias
RelativePath = $relativePath
Status = $status
})
}
$assetFindings = [Collections.Generic.List[object]]::new()
foreach ($requirement in $AssetRequirements) {
$builder = [string] $requirement.Builder
$kind = [string] $requirement.Kind
$relativePath = [string] $requirement.Path
$status = 'ManifestInvalid'
if (-not [string]::IsNullOrWhiteSpace($builder) -and
-not [string]::IsNullOrWhiteSpace($relativePath) -and
(Test-AssetDefinition -Kind $kind -RelativePath $relativePath)) {
$resolved = Resolve-CoveragePath -Root $root -RelativePath $relativePath
$status = $resolved.Status
if ($status -eq 'Resolved') {
if (-not (Test-Path -LiteralPath $resolved.FullPath -PathType Leaf)) {
$status = 'Missing'
}
else {
$item = Get-Item -LiteralPath $resolved.FullPath -Force
$status = if ($item.Length -le 0) { 'Empty' } else { 'Present' }
}
}
}
$assetFindings.Add([pscustomobject][ordered]@{
Builder = $builder
Kind = $kind
RelativePath = $relativePath
Status = $status
})
}
$missingAliases = @($aliasFindings | Where-Object Status -eq 'Missing')
$unsafeAliases = @($aliasFindings | Where-Object {
$_.Status -ne 'Present' -and $_.Status -ne 'Missing'
})
$missingAssets = @($assetFindings | Where-Object Status -eq 'Missing')
$unsafeAssets = @($assetFindings | Where-Object {
$_.Status -ne 'Present' -and $_.Status -ne 'Missing'
})
$rootEscapes = @($assetFindings | Where-Object Status -eq 'RootEscape')
$reparseAssets = @($assetFindings | Where-Object Status -eq 'Reparse')
$invalidAssets = @($assetFindings | Where-Object Status -eq 'ManifestInvalid')
$failed = $missingAliases.Count -ne 0 -or
$unsafeAliases.Count -ne 0 -or
$missingAssets.Count -ne 0 -or
$unsafeAssets.Count -ne 0
return [pscustomobject][ordered]@{
Status = if ($failed) { 'Failed' } else { 'Passed' }
ReachableBuilders = $ReachableBuilders
ActiveAliases = $Aliases.Count
Missing = $missingAliases.Count
Unsafe = $unsafeAliases.Count
RequiredAssets = $AssetRequirements.Count
MissingAssets = $missingAssets.Count
UnsafeAssets = $unsafeAssets.Count
RootEscapes = $rootEscapes.Count
ReparseAssets = $reparseAssets.Count
InvalidAssetDefinitions = $invalidAssets.Count
AliasFindings = $aliasFindings.ToArray()
AssetFindings = $assetFindings.ToArray()
}
}
Export-ModuleMember -Function Test-LegacyCutCoverageState