[CmdletBinding()]
|
param(
|
[Parameter(Mandatory = $true)][string]$ProjectRoot,
|
[Parameter(Mandatory = $true)][string]$RunRoot,
|
[Parameter(Mandatory = $true)][string]$CscPath,
|
[Parameter(Mandatory = $true)][string]$ExpectedVectorsPath
|
)
|
|
Set-StrictMode -Version Latest
|
$ErrorActionPreference = 'Stop'
|
|
$runId = 'RUN-DEV-ANA-SEMI-ROOT-PREFLIGHT-V007-IMPLEMENTATION-20260724-001'
|
$expectedProjectRoot = 'E:\mb-ms-doc\project-info'
|
$expectedRunRoot = 'E:\mb-ms-doc\project-info\dev\ana-dev\tmp\RUN-DEV-ANA-SEMI-ROOT-PREFLIGHT-V007-IMPLEMENTATION-20260724-001'
|
$expectedCsc = 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe'
|
$expectedVectors = 'E:\mb-ms-doc\project-info\dev\ana-dev\test\V007ExpectedVectors.json'
|
$emptySha = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
|
|
function Get-Sha256Bytes([byte[]]$Bytes) {
|
$sha = [Security.Cryptography.SHA256]::Create()
|
try { return ([BitConverter]::ToString($sha.ComputeHash($Bytes)).Replace('-', '').ToLowerInvariant()) }
|
finally { $sha.Dispose() }
|
}
|
function Get-Sha256File([string]$Path) {
|
$stream = [IO.File]::Open($Path, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::None)
|
try {
|
$sha = [Security.Cryptography.SHA256]::Create()
|
try { return ([BitConverter]::ToString($sha.ComputeHash($stream)).Replace('-', '').ToLowerInvariant()) }
|
finally { $sha.Dispose() }
|
}
|
finally { $stream.Dispose() }
|
}
|
function Get-ArgvHash([string[]]$Argv) {
|
$stream = New-Object IO.MemoryStream
|
try {
|
$domain = [Text.Encoding]::UTF8.GetBytes('ANA-SEMI-ARGV-V001')
|
$stream.Write($domain, 0, $domain.Length)
|
foreach ($token in $Argv) {
|
$stream.WriteByte(0)
|
$bytes = [Text.Encoding]::UTF8.GetBytes($token)
|
$stream.Write($bytes, 0, $bytes.Length)
|
}
|
return Get-Sha256Bytes $stream.ToArray()
|
}
|
finally { $stream.Dispose() }
|
}
|
function Quote-WindowsToken([string]$Token) {
|
if ($Token.Length -gt 0 -and $Token.IndexOfAny([char[]]@(' ', "`t", '"')) -lt 0) { return $Token }
|
$builder = New-Object Text.StringBuilder
|
[void]$builder.Append('"')
|
$slashes = 0
|
foreach ($ch in $Token.ToCharArray()) {
|
if ($ch -eq '\') { $slashes++; continue }
|
if ($ch -eq '"') {
|
[void]$builder.Append(('\' * (($slashes * 2) + 1)))
|
[void]$builder.Append('"')
|
$slashes = 0
|
continue
|
}
|
if ($slashes -gt 0) { [void]$builder.Append(('\' * $slashes)); $slashes = 0 }
|
[void]$builder.Append($ch)
|
}
|
if ($slashes -gt 0) { [void]$builder.Append(('\' * ($slashes * 2))) }
|
[void]$builder.Append('"')
|
return $builder.ToString()
|
}
|
function Join-WindowsArguments([string[]]$Arguments) {
|
return [string]::Join(' ', @($Arguments | ForEach-Object { Quote-WindowsToken $_ }))
|
}
|
function Escape-JsonString([string]$Value) {
|
$builder = New-Object Text.StringBuilder
|
[void]$builder.Append('"')
|
foreach ($ch in $Value.ToCharArray()) {
|
$code = [int][char]$ch
|
switch ($code) {
|
8 { [void]$builder.Append('\b'); continue }
|
9 { [void]$builder.Append('\t'); continue }
|
10 { [void]$builder.Append('\n'); continue }
|
12 { [void]$builder.Append('\f'); continue }
|
13 { [void]$builder.Append('\r'); continue }
|
34 { [void]$builder.Append('\"'); continue }
|
92 { [void]$builder.Append('\\'); continue }
|
}
|
if ($code -lt 32) { [void]$builder.Append(('\u{0:x4}' -f $code)) }
|
else { [void]$builder.Append($ch) }
|
}
|
[void]$builder.Append('"')
|
return $builder.ToString()
|
}
|
function ConvertTo-JcsValue($Value) {
|
if ($null -eq $Value) { return 'null' }
|
if ($Value -is [string]) { return Escape-JsonString $Value }
|
if ($Value -is [bool]) { if ($Value) { return 'true' }; return 'false' }
|
if ($Value -is [byte] -or $Value -is [sbyte] -or $Value -is [int16] -or $Value -is [uint16] -or
|
$Value -is [int32] -or $Value -is [uint32] -or $Value -is [int64] -or $Value -is [uint64]) {
|
return ([Convert]::ToString($Value, [Globalization.CultureInfo]::InvariantCulture))
|
}
|
if ($Value -is [Collections.IDictionary]) {
|
$keys = @($Value.Keys | ForEach-Object { [string]$_ })
|
[Array]::Sort($keys, [StringComparer]::Ordinal)
|
$parts = New-Object Collections.Generic.List[string]
|
foreach ($key in $keys) { $parts.Add((Escape-JsonString $key) + ':' + (ConvertTo-JcsValue $Value[$key])) }
|
return '{' + [string]::Join(',', $parts.ToArray()) + '}'
|
}
|
if ($Value -is [Collections.IEnumerable]) {
|
$parts = New-Object Collections.Generic.List[string]
|
foreach ($item in $Value) { $parts.Add((ConvertTo-JcsValue $item)) }
|
return '[' + [string]::Join(',', $parts.ToArray()) + ']'
|
}
|
$dictionary = [ordered]@{}
|
foreach ($property in $Value.PSObject.Properties) { $dictionary[$property.Name] = $property.Value }
|
return ConvertTo-JcsValue $dictionary
|
}
|
function Write-JcsCreateNew([string]$Path, $Value) {
|
$bytes = (New-Object Text.UTF8Encoding($false)).GetBytes((ConvertTo-JcsValue $Value))
|
$stream = New-Object IO.FileStream($Path, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
try { $stream.Write($bytes, 0, $bytes.Length); $stream.Flush($true) }
|
finally { $stream.Dispose() }
|
}
|
function Write-Utf8LfCreateNew([string]$Path, [string]$Text) {
|
$normalized = $Text.Replace("`r`n", "`n").Replace("`r", "`n").TrimEnd("`n") + "`n"
|
$bytes = (New-Object Text.UTF8Encoding($false)).GetBytes($normalized)
|
$stream = New-Object IO.FileStream($Path, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
try { $stream.Write($bytes, 0, $bytes.Length); $stream.Flush($true) }
|
finally { $stream.Dispose() }
|
}
|
function Escape-Csv([string]$Value) {
|
if ($null -eq $Value) { return '' }
|
if ($Value.IndexOfAny([char[]]@(',', '"', "`r", "`n")) -ge 0) { return '"' + $Value.Replace('"', '""') + '"' }
|
return $Value
|
}
|
function Assert-CanonicalSource([string]$Path, [bool]$Json) {
|
$bytes = [IO.File]::ReadAllBytes($Path)
|
if ($bytes.Length -eq 0) { throw 'STOP_VALIDATION_PRECHECK' }
|
if ($bytes.Length -ge 3 -and $bytes[0] -eq 239 -and $bytes[1] -eq 187 -and $bytes[2] -eq 191) { throw 'STOP_VALIDATION_PRECHECK' }
|
if (@($bytes | Where-Object { $_ -eq 13 }).Count -ne 0) { throw 'STOP_VALIDATION_PRECHECK' }
|
[void](New-Object Text.UTF8Encoding($false, $true)).GetString($bytes)
|
if ($Json) {
|
if ($bytes[-1] -eq 10) { throw 'STOP_VALIDATION_PRECHECK' }
|
}
|
elseif ($bytes[-1] -ne 10 -or ($bytes.Length -gt 1 -and $bytes[-2] -eq 10)) { throw 'STOP_VALIDATION_PRECHECK' }
|
}
|
|
try {
|
if ([IO.Path]::GetFullPath($ProjectRoot) -cne $expectedProjectRoot -or
|
[IO.Path]::GetFullPath($RunRoot) -cne $expectedRunRoot -or
|
[IO.Path]::GetFullPath($CscPath) -cne $expectedCsc -or
|
[IO.Path]::GetFullPath($ExpectedVectorsPath) -cne $expectedVectors -or
|
(Test-Path -LiteralPath $RunRoot)) { exit 11 }
|
if ((Get-Item -LiteralPath $CscPath).Length -ne 2569696 -or
|
(Get-Sha256File $CscPath) -cne 'aae1db57f898ca8bda18590c56f86ced6d0ead80c22033b76fdfe9119706f116') { exit 11 }
|
|
$relativeSources = @(
|
'dev/ana-dev/AnaSemi.NativeProcessRunnerV006.cs',
|
'dev/ana-dev/Invoke-AnaSemiWrapperSelftestV006.ps1',
|
'dev/ana-dev/synthetic-child.ps1',
|
'dev/ana-dev/test/Test-AnaSemiNativeProcessRunnerV006.Static.ps1',
|
'dev/ana-dev/test/Test-InvokeAnaSemiWrapperSelftestV006.Static.ps1',
|
'dev/ana-dev/test/V007ExpectedVectors.json',
|
'dev/ana-dev/test/Invoke-AnaSemiImplementationValidationV001.ps1'
|
)
|
for ($index = 0; $index -lt $relativeSources.Count; $index++) {
|
$path = Join-Path $ProjectRoot $relativeSources[$index]
|
if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { exit 11 }
|
Assert-CanonicalSource $path ($index -eq 5)
|
}
|
$vectors = [IO.File]::ReadAllText($ExpectedVectorsPath, [Text.Encoding]::UTF8) | ConvertFrom-Json
|
if ($vectors.schema_id -cne 'ANA-SEMI-V007-EXPECTED-VECTORS-JCS-V001') { exit 11 }
|
|
foreach ($directory in @('staging','build','process','test','receipt','manifest')) {
|
[void][IO.Directory]::CreateDirectory((Join-Path $RunRoot $directory))
|
}
|
$stagingPath = Join-Path $RunRoot 'staging/AnaSemi.NativeProcessRunnerV006.dll'
|
$publishedPath = Join-Path $RunRoot 'build/AnaSemi.NativeProcessRunnerV006.dll'
|
$stdoutPath = Join-Path $RunRoot 'process/csc.stdout.bin'
|
$stderrPath = Join-Path $RunRoot 'process/csc.stderr.bin'
|
$processResultPath = Join-Path $RunRoot 'process/csc.result.json'
|
$l0Path = Join-Path $RunRoot 'test/l0-static.json'
|
$l1Path = Join-Path $RunRoot 'test/l1-contract.json'
|
$receiptPath = Join-Path $RunRoot 'receipt/implementation-receipt.md'
|
$manifestPath = Join-Path $RunRoot 'manifest/implementation-source-manifest.csv'
|
foreach ($path in @($stagingPath,$publishedPath,$stdoutPath,$stderrPath,$processResultPath,$l0Path,$l1Path,$receiptPath,$manifestPath)) {
|
if (Test-Path -LiteralPath $path) { exit 11 }
|
}
|
|
$cscArgv = [string[]]@(
|
$CscPath,'/nologo','/target:library','/optimize+','/debug-','/checked+','/platform:anycpu','/warnaserror+','/utf8output',
|
('/out:' + $stagingPath),(Join-Path $ProjectRoot 'dev/ana-dev/AnaSemi.NativeProcessRunnerV006.cs')
|
)
|
$cscArgvHash = Get-ArgvHash $cscArgv
|
if ($cscArgv.Count -ne 11 -or $cscArgvHash -cne '2d898216b8f1bb95fbc716737915a43e47c57f4d48685da74b392a167dc024df') { exit 11 }
|
|
$stdoutStream = New-Object IO.FileStream($stdoutPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::Read)
|
$stderrStream = New-Object IO.FileStream($stderrPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::Read)
|
$process = New-Object Diagnostics.Process
|
$startedAt = [DateTimeOffset]::UtcNow
|
$started = $false
|
try {
|
$startInfo = New-Object Diagnostics.ProcessStartInfo
|
$startInfo.FileName = $CscPath
|
$startInfo.Arguments = Join-WindowsArguments $cscArgv[1..10]
|
$startInfo.UseShellExecute = $false
|
$startInfo.CreateNoWindow = $true
|
$startInfo.RedirectStandardOutput = $true
|
$startInfo.RedirectStandardError = $true
|
$process.StartInfo = $startInfo
|
try { $started = $process.Start() } catch { $started = $false }
|
if (-not $started) {
|
$stdoutStream.Flush($true); $stderrStream.Flush($true)
|
$stdoutStream.Dispose(); $stderrStream.Dispose(); $process.Dispose()
|
exit 12
|
}
|
$stdoutTask = $process.StandardOutput.BaseStream.CopyToAsync($stdoutStream)
|
$stderrTask = $process.StandardError.BaseStream.CopyToAsync($stderrStream)
|
if (-not $process.WaitForExit(60000)) {
|
try { $process.Kill() } catch {}
|
if (-not $process.WaitForExit(10000)) { exit 27 }
|
[void]$stdoutTask.GetAwaiter().GetResult(); [void]$stderrTask.GetAwaiter().GetResult()
|
$stdoutStream.Flush($true); $stderrStream.Flush($true)
|
$stdoutStream.Dispose(); $stderrStream.Dispose()
|
exit 13
|
}
|
[void]$stdoutTask.GetAwaiter().GetResult(); [void]$stderrTask.GetAwaiter().GetResult()
|
$stdoutStream.Flush($true); $stderrStream.Flush($true)
|
$stdoutStream.Dispose(); $stderrStream.Dispose()
|
$finishedAt = [DateTimeOffset]::UtcNow
|
$processId = [uint32]$process.Id
|
$cscExit = [int32]$process.ExitCode
|
}
|
finally {
|
if ($null -ne $stdoutStream) { try { $stdoutStream.Dispose() } catch {} }
|
if ($null -ne $stderrStream) { try { $stderrStream.Dispose() } catch {} }
|
if ($null -ne $process) { $process.Dispose() }
|
}
|
if ($cscExit -ne 0) { exit 14 }
|
if ((Get-Item -LiteralPath $stdoutPath).Length -ne 0 -or (Get-Item -LiteralPath $stderrPath).Length -ne 0) { exit 15 }
|
if (-not (Test-Path -LiteralPath $stagingPath -PathType Leaf)) { exit 15 }
|
$stagingName = [Reflection.AssemblyName]::GetAssemblyName($stagingPath)
|
if ($stagingName.Name -cne 'AnaSemi.NativeProcessRunnerV006' -or $stagingName.Version.ToString() -cne '1.0.0.0') { exit 15 }
|
$stagingInfo = Get-Item -LiteralPath $stagingPath
|
$stagingHash = Get-Sha256File $stagingPath
|
|
try {
|
$source = [IO.File]::Open($stagingPath, [IO.FileMode]::Open, [IO.FileAccess]::Read, [IO.FileShare]::None)
|
$target = New-Object IO.FileStream($publishedPath, [IO.FileMode]::CreateNew, [IO.FileAccess]::Write, [IO.FileShare]::None)
|
try { $source.CopyTo($target); $target.Flush($true) }
|
finally { $target.Dispose(); $source.Dispose() }
|
$publishedInfo = Get-Item -LiteralPath $publishedPath
|
$publishedHash = Get-Sha256File $publishedPath
|
if ($publishedInfo.Length -ne $stagingInfo.Length -or $publishedHash -cne $stagingHash) { exit 16 }
|
}
|
catch { exit 16 }
|
|
$processResult = [ordered]@{
|
argv_count = [uint16]11
|
argv_sha256 = $cscArgvHash
|
child_liveness = 'EXITED'
|
exit_code = [int32]0
|
finished_at = $finishedAt.ToString('o')
|
process_id = $processId
|
process_started = $true
|
publish_bytes = [uint64]$publishedInfo.Length
|
publish_path = $publishedPath
|
publish_sha256 = $publishedHash
|
schema_id = 'ANA-SEMI-IMPLEMENTATION-PROCESS-RESULT-JCS-V002'
|
staging_bytes = [uint64]$stagingInfo.Length
|
staging_path = $stagingPath
|
staging_sha256 = $stagingHash
|
started_at = $startedAt.ToString('o')
|
status = 'PASS'
|
stderr_bytes = [uint64]0
|
stderr_path = $stderrPath
|
stderr_sha256 = $emptySha
|
stdout_bytes = [uint64]0
|
stdout_path = $stdoutPath
|
stdout_sha256 = $emptySha
|
stop_code = $null
|
timed_out = $false
|
tool_bytes = [uint64]2569696
|
tool_path = $CscPath
|
tool_sha256 = 'aae1db57f898ca8bda18590c56f86ced6d0ead80c22033b76fdfe9119706f116'
|
}
|
Write-JcsCreateNew $processResultPath $processResult
|
|
$resolvedPublished = [IO.Path]::GetFullPath($publishedPath)
|
$before = @([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -ceq 'AnaSemi.NativeProcessRunnerV006' })
|
if ($before.Count -ne 0) { exit 18 }
|
try { $assembly = [Reflection.Assembly]::LoadFile($resolvedPublished) } catch { exit 19 }
|
if ($null -eq $assembly -or $assembly.FullName -cne 'AnaSemi.NativeProcessRunnerV006, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' -or
|
[IO.Path]::GetFullPath($assembly.Location) -cne $resolvedPublished) { exit 21 }
|
$after = @([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.GetName().Name -ceq 'AnaSemi.NativeProcessRunnerV006' })
|
if ($after.Count -ne 1 -or -not [object]::ReferenceEquals($after[0], $assembly)) { exit 20 }
|
$expectedTypes = @('AnaSemi.NativeProcessContractExceptionV006','AnaSemi.NativeProcessResultV006','AnaSemi.NativeProcessRunnerV006','AnaSemi.ProcessResultEnvelopeValidatorV006','AnaSemi.ProcessResultSidecarCsvV006','AnaSemi.WindowsCommandLineV006')
|
$actualTypes = @($assembly.GetExportedTypes() | ForEach-Object { $_.FullName })
|
[Array]::Sort($expectedTypes, [StringComparer]::Ordinal); [Array]::Sort($actualTypes, [StringComparer]::Ordinal)
|
if ([string]::Join([char]0, $expectedTypes) -cne [string]::Join([char]0, $actualTypes)) { exit 21 }
|
|
$l0Module = Join-Path $ProjectRoot 'dev/ana-dev/test/Test-AnaSemiNativeProcessRunnerV006.Static.ps1'
|
$l1Module = Join-Path $ProjectRoot 'dev/ana-dev/test/Test-InvokeAnaSemiWrapperSelftestV006.Static.ps1'
|
$dot0 = @(. $l0Module)
|
if ($dot0.Count -ne 0) { exit 22 }
|
try {
|
$out0 = @(Invoke-AnaSemiL0StaticValidationV001 -ProjectRoot $ProjectRoot -RunnerAssemblyPath $publishedPath -ExpectedVectorsPath $ExpectedVectorsPath -OutputPath $l0Path)
|
if ($out0.Count -ne 0) { exit 22 }
|
}
|
catch { exit 23 }
|
$dot1 = @(. $l1Module)
|
if ($dot1.Count -ne 0) { exit 22 }
|
try {
|
$out1 = @(Invoke-AnaSemiL1ContractValidationV001 -ProjectRoot $ProjectRoot -RunnerAssemblyPath $publishedPath -ExpectedVectorsPath $ExpectedVectorsPath -OutputPath $l1Path)
|
if ($out1.Count -ne 0) { exit 22 }
|
}
|
catch { exit 24 }
|
|
$targetPaths = @(
|
(Join-Path $ProjectRoot $relativeSources[0]),(Join-Path $ProjectRoot $relativeSources[1]),(Join-Path $ProjectRoot $relativeSources[2]),
|
(Join-Path $ProjectRoot $relativeSources[3]),(Join-Path $ProjectRoot $relativeSources[4]),(Join-Path $ProjectRoot $relativeSources[5]),
|
(Join-Path $ProjectRoot $relativeSources[6]),$stagingPath,$publishedPath,$stdoutPath,$stderrPath,$processResultPath,$l0Path,$l1Path
|
)
|
$receiptLines = New-Object Collections.Generic.List[string]
|
foreach ($heading in @('Metadata','Toolchain','Source And Test Hashes','Compiler Process','L0 Result','L1 Result','Counts And Boundaries','Stop Or Pass')) {
|
$receiptLines.Add('## ' + $heading)
|
switch ($heading) {
|
'Metadata' { $receiptLines.Add('- run_id=' + $runId); $receiptLines.Add('- schema_id=ANA-SEMI-IMPLEMENTATION-RECEIPT-MD-V002') }
|
'Toolchain' { $receiptLines.Add('- powershell=455680/9785001b0dcf755eddb8af294a373c0b87b2498660f724e76c4d53f9c217c7a3'); $receiptLines.Add('- csc=2569696/aae1db57f898ca8bda18590c56f86ced6d0ead80c22033b76fdfe9119706f116') }
|
'Source And Test Hashes' { for ($i=0;$i -lt $targetPaths.Count;$i++) { $info=Get-Item -LiteralPath $targetPaths[$i]; $receiptLines.Add(('- I{0:d2}={1}/{2}' -f ($i+1),$info.Length,(Get-Sha256File $targetPaths[$i]))) } }
|
'Compiler Process' { $receiptLines.Add('- outer_argv=15/ac99c11e3446bfa4d35867f99818d7836db9c17571960b3b1bfc9474f05a5b64'); $receiptLines.Add('- csc_argv=11/' + $cscArgvHash); $receiptLines.Add('- csc_exit=0') }
|
'L0 Result' { $receiptLines.Add('- status=PASS') }
|
'L1 Result' { $receiptLines.Add('- status=PASS') }
|
'Counts And Boundaries' { $receiptLines.Add('- external_process_count=2'); $receiptLines.Add('- network_count=0'); $receiptLines.Add('- database_count=0'); $receiptLines.Add('- credential_count=0'); $receiptLines.Add('- formal_target_count=0'); $receiptLines.Add('- BATCH-001=HELD') }
|
'Stop Or Pass' { $receiptLines.Add('- status=PASS'); $receiptLines.Add('- stop_code=null') }
|
}
|
$receiptLines.Add('')
|
}
|
try { Write-Utf8LfCreateNew $receiptPath ([string]::Join("`n", $receiptLines.ToArray())) } catch { exit 25 }
|
|
$allPaths = $targetPaths + @($receiptPath,$manifestPath)
|
$ids = 1..16 | ForEach-Object { 'I{0:d2}' -f $_ }
|
$roles = @('WRAPPER_SOURCE','HARNESS_SOURCE','CHILD_SOURCE','L0_TEST_SOURCE','L1_TEST_SOURCE','EXPECTED_VECTORS','VALIDATION_ENTRY','COMPILER_STAGING','PUBLISHED_ASSEMBLY','CSC_STDOUT','CSC_STDERR','CSC_PROCESS_RESULT','L0_RESULT','L1_RESULT','IMPLEMENTATION_RECEIPT','IMPLEMENTATION_MANIFEST')
|
$media = @('text/x-csharp; charset=utf-8','text/x-powershell; charset=utf-8','text/x-powershell; charset=utf-8','text/x-powershell; charset=utf-8','text/x-powershell; charset=utf-8','application/json','text/x-powershell; charset=utf-8','application/vnd.microsoft.portable-executable','application/vnd.microsoft.portable-executable','application/octet-stream','application/octet-stream','application/json','application/json','application/json','text/markdown; charset=utf-8','text/csv; charset=utf-8')
|
$schemas = @('ANA-SEMI-NATIVE-WRAPPER-CS-V001','ANA-SEMI-WRAPPER-HARNESS-PS1-V001','ANA-SEMI-SYNTHETIC-CHILD-PS1-V001','ANA-SEMI-L0-VALIDATOR-PS1-V001','ANA-SEMI-L1-VALIDATOR-PS1-V001','ANA-SEMI-V007-EXPECTED-VECTORS-JCS-V001','ANA-SEMI-IMPLEMENTATION-VALIDATION-PS1-V001','PE-DOTNET48-STAGING-V001','PE-DOTNET48-V001','RAW-BYTES-V001','RAW-BYTES-V001','ANA-SEMI-IMPLEMENTATION-PROCESS-RESULT-JCS-V002','ANA-SEMI-IMPLEMENTATION-L0-JCS-V002','ANA-SEMI-IMPLEMENTATION-L1-JCS-V002','ANA-SEMI-IMPLEMENTATION-RECEIPT-MD-V002','ANA-SEMI-IMPLEMENTATION-MANIFEST-CSV-V002')
|
$statuses = @('SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','SOURCE_FROZEN','COMPILER_STAGING_READY','BUILD_PUBLISHED','RAW_CAPTURED','RAW_CAPTURED','PROCESS_RESULT_PASS','TEST_PASS','TEST_PASS','RECEIPT_FINALIZED','MANIFEST_SELF_EXTERNAL_HASH')
|
$relative = $relativeSources + @(
|
('dev/ana-dev/tmp/' + $runId + '/staging/AnaSemi.NativeProcessRunnerV006.dll'),
|
('dev/ana-dev/tmp/' + $runId + '/build/AnaSemi.NativeProcessRunnerV006.dll'),
|
('dev/ana-dev/tmp/' + $runId + '/process/csc.stdout.bin'),('dev/ana-dev/tmp/' + $runId + '/process/csc.stderr.bin'),
|
('dev/ana-dev/tmp/' + $runId + '/process/csc.result.json'),('dev/ana-dev/tmp/' + $runId + '/test/l0-static.json'),
|
('dev/ana-dev/tmp/' + $runId + '/test/l1-contract.json'),('dev/ana-dev/tmp/' + $runId + '/receipt/implementation-receipt.md'),
|
('dev/ana-dev/tmp/' + $runId + '/manifest/implementation-source-manifest.csv'))
|
$header = 'run_id,target_id,artifact_role,project_relative_path,media_type,schema_id,expected_presence,materialized,exists,bytes,sha256,status,created_at,upstream_stop_code'
|
$rows = New-Object Collections.Generic.List[string]
|
$rows.Add($header)
|
for ($i=0;$i -lt 16;$i++) {
|
if ($i -eq 15) { $bytes=''; $hash='' }
|
else { $item=Get-Item -LiteralPath $allPaths[$i]; $bytes=[string]$item.Length; $hash=Get-Sha256File $allPaths[$i] }
|
$created = [DateTimeOffset]::UtcNow.ToString('o')
|
$values = @($runId,$ids[$i],$roles[$i],$relative[$i],$media[$i],$schemas[$i],'ALWAYS','true','true',$bytes,$hash,$statuses[$i],$created,'')
|
$rows.Add([string]::Join(',', @($values | ForEach-Object { Escape-Csv ([string]$_) })))
|
}
|
try { Write-Utf8LfCreateNew $manifestPath ([string]::Join("`n", $rows.ToArray())) } catch { exit 26 }
|
exit 0
|
}
|
catch {
|
exit 28
|
}
|