???# gov_pipeline_freeze_v1.0.ps1 # Freeze snapshot: manifest (json/csv/txt), snapshot copies, doctor+acceptance logs, simple index.html. param( [string]$Root="\\DS-918\chatgpt\ChatGPT-Gouvernance-Projets\_registry", [string]$Label="", [switch]$Utf8Console, [switch]$RunAcceptance ) if($Utf8Console){ try{ [Console]::OutputEncoding = [Text.Encoding]::UTF8 }catch{} } function Exists([string]$p){ (-not [string]::IsNullOrWhiteSpace($p)) -and (Test-Path -LiteralPath $p) } function Read-Text([string]$p){ if(-not (Exists $p)){ return "" } try{ Get-Content -LiteralPath $p -Raw -Encoding UTF8 }catch{ Get-Content -LiteralPath $p -Raw } } function ToIso([datetime]$d){ if($null -eq $d){ return "" } return $d.ToString("yyyy-MM-ddTHH:mm:ss") } function Slug([string]$s){ if([string]::IsNullOrWhiteSpace($s)){ return "" } $sb=New-Object System.Text.StringBuilder; foreach($c in $s.ToCharArray()){ if( ("a" -le $c -and $c -le "z") -or ("A" -le $c -and $c -le "Z") -or ("0" -le $c -and $c -le "9") -or $c -eq "_" -or $c -eq "-" ){ [void]$sb.Append($c) } else { [void]$sb.Append("_") } } $sb.ToString() } function Ensure-Dir([string]$p){ if(-not (Test-Path -LiteralPath $p)){ New-Item -ItemType Directory -Path $p -Force | Out-Null } } function File-InfoRec([string]$root,[string]$path){ $h=@{} $h.rel = if($path.StartsWith($root,[StringComparison]::OrdinalIgnoreCase)){ $path.Substring($root.Length).TrimStart("\/") } else { $path } try{ $item = Get-Item -LiteralPath $path }catch{ $item=$null } if($item){ $h.size = [int64]$item.Length $h.mtime = ToIso $item.LastWriteTime try{ $h.sha256 = (Get-FileHash -Algorithm SHA256 -LiteralPath $path).Hash.ToUpperInvariant() }catch{ $h.sha256="" } } else { $h.size=-1; $h.mtime=""; $h.sha256="" } return $h } function Write-TextUtf8([string]$path,[string[]]$lines){ $enc = New-Object System.Text.UTF8Encoding($false) $txt = ($lines -join "`r`n") [IO.File]::WriteAllText($path,$txt,$enc) } function Copy-Into([string]$root,[string]$destRoot,[string]$path){ $rel = if($path.StartsWith($root,[StringComparison]::OrdinalIgnoreCase)){ $path.Substring($root.Length).TrimStart("\/") } else { [IO.Path]::GetFileName($path) } $dst = Join-Path $destRoot $rel $dir = [IO.Path]::GetDirectoryName($dst) Ensure-Dir $dir if(Test-Path -LiteralPath $path){ Copy-Item -LiteralPath $path -Destination $dst -Force } } function Parse-Pointer([string]$bootText){ $res=@{Path="";SHA256="";Entries=-1;SizeBytes=-1} if([string]::IsNullOrWhiteSpace($bootText)){ return $res } $norm = $bootText -replace "`r`n","`n" $lines = $norm -split "`n" $inBlk=$false foreach($ln in $lines){ $t = $ln.Trim() if($t -ceq "[BUG_KB_JSON_POINTER]"){ $inBlk=$true; continue } if($inBlk){ if($t.StartsWith("[")){ break } if($t.Length -gt 0){ $k = $t.IndexOf(":"); if($k -ge 0){ $name=$t.Substring(0,$k).Trim(); $val=$t.Substring($k+1).Trim() if($name -ieq "Path"){ $res.Path=$val } elseif($name -ieq "SHA256"){ $hex=""; foreach($c in $val.ToCharArray()){ if( ("0" -le $c -and $c -le "9") -or ("A" -le $c -and $c -le "F") -or ("a" -le $c -and $c -le "f") ){ $hex += $c } } $res.SHA256 = $hex.ToUpperInvariant() } elseif($name -ieq "Entries"){ try{ $res.Entries = [int]$val }catch{ $res.Entries=-1 } } elseif($name -ieq "SizeBytes"){ try{ $res.SizeBytes = [int]$val }catch{ $res.SizeBytes=-1 } } } } } } return $res } Write-Host "== GOV PIPELINE :: FREEZE v1.0 ==" if($Root -like "\\\\\\\\*"){ $Root = $Root -replace "^[\\]+","\\\\" } $scriptsDir = Join-Path $Root "scripts" $bootFile = Join-Path $Root "bootpack\bootpack.txt" $pasteFile = Join-Path $Root "bootpack\bootpack_paste.txt" $kbFile = Join-Path $Root "bug_kb\BUG_KB.json.txt" if(-not (Exists $bootFile)){ Write-Host ("[FATAL] missing: {0}" -f $bootFile); exit 3 } if(-not (Exists $pasteFile)){ Write-Host ("[FATAL] missing: {0}" -f $pasteFile); exit 3 } if(-not (Exists $kbFile)){ Write-Host ("[FATAL] missing: {0}" -f $kbFile); exit 3 } $doctor1 = Join-Path $scriptsDir "gov_pipeline_doctor_ultra_min_v1.2.ps1" $doctor2 = Join-Path $scriptsDir "gov_pipeline_doctor_ultra_min_v1.1.ps1" $inter = Join-Path $scriptsDir "gov_pipeline_interactive_write_v1.0.ps1" $accept = Join-Path $scriptsDir "kb_acceptance_tests_v1.0.1.ps1" $posthk = Join-Path $scriptsDir "post_bootpack_pointer_refresh_v1.0.2.ps1" $emit = Join-Path $scriptsDir "kb_emit_bootpack_dual_v1.1.ps1" $comp = Join-Path $scriptsDir "kb_compare_lite_v1.1.ps1" $bulk = Join-Path $scriptsDir "kb_bulk_ingest_v1.3.ps1" $scrub = Join-Path $scriptsDir "kb_ascii_scrub_v1.0.ps1" $ql121 = Join-Path $scriptsDir "kb_quicklog_and_sync_v1.2.1.ps1" $ql13 = Join-Path $scriptsDir "kb_quicklog_and_sync_v1.3.ps1" $ptrref = Join-Path $scriptsDir "kb_pointer_refresh_v1.0.ps1" $doctor = if(Exists $doctor1){ $doctor1 } elseif(Exists $doctor2){ $doctor2 } else { "" } if([string]::IsNullOrWhiteSpace($doctor)){ Write-Host "[FATAL] doctor missing"; exit 3 } # doctor run $docOut = & powershell -NoProfile -ExecutionPolicy Bypass -File $doctor -Root $Root # acceptance run (optional) $accOut = @() if(Exists $accept -and $RunAcceptance){ $accOut = & powershell -NoProfile -ExecutionPolicy Bypass -File $accept $Root } # build archive folder $stamp = (Get-Date).ToString("yyyyMMdd_HHmmss") $lbl = Slug $Label $archRoot = Join-Path $Root "archives\freeze" Ensure-Dir $archRoot $folderName = if([string]::IsNullOrWhiteSpace($lbl)){ "FREEZE_" + $stamp } else { "FREEZE_" + $stamp + "_" + $lbl } $dest = Join-Path $archRoot $folderName Ensure-Dir $dest Ensure-Dir (Join-Path $dest "snapshot") # fileset $files = @( $bootFile,$pasteFile,$kbFile, $doctor1,$doctor2,$inter,$accept,$posthk,$emit,$comp,$bulk,$scrub,$ql121,$ql13,$ptrref ) | Where-Object { $_ -and (Test-Path -LiteralPath $_) } # manifest data $items = @() foreach($f in $files){ $items += (File-InfoRec $Root $f) } # copy snapshot foreach($f in $files){ Copy-Into $Root (Join-Path $dest "snapshot") $f } # pointer echo $bootRaw = Read-Text $bootFile $ptr = Parse-Pointer $bootRaw # write manifest files $jsonPath = Join-Path $dest "manifest.json.txt" $csvPath = Join-Path $dest "manifest.csv" $txtPath = Join-Path $dest "manifest.txt" $docPath = Join-Path $dest "doctor.log.txt" $accPath = Join-Path $dest "acceptance.log.txt" $idxPath = Join-Path $dest "index.html" # JSON $obj = @{ root=$Root; created=(Get-Date).ToString("yyyy-MM-ddTHH:mm:ss"); label=$lbl; pointer=@{ path=$ptr.Path; sha256=$ptr.SHA256; entries=$ptr.Entries; sizeBytes=$ptr.SizeBytes }; items=$items } $json = ($obj | ConvertTo-Json -Depth 6) $json = $json -replace "`r?`n","`r`n" [IO.File]::WriteAllText($jsonPath,$json,(New-Object System.Text.UTF8Encoding($false))) # CSV $csv = New-Object System.Collections.Generic.List[string] $csv.Add("relpath;size;sha256;lastwrite") | Out-Null foreach($it in $items){ $csv.Add(("{0};{1};{2};{3}" -f $it.rel,$it.size,$it.sha256,$it.mtime)) | Out-Null } Write-TextUtf8 $csvPath $csv # TXT $txt = New-Object System.Collections.Generic.List[string] $txt.Add("FREEZE manifest") | Out-Null $txt.Add(("root: {0}" -f $Root)) | Out-Null $txt.Add(("created: {0}" -f (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss"))) | Out-Null $txt.Add(("label: {0}" -f $lbl)) | Out-Null $txt.Add("") | Out-Null $txt.Add("[POINTER]") | Out-Null $txt.Add(("Path: {0}" -f $ptr.Path)) | Out-Null $txt.Add(("SHA256: {0}" -f $ptr.SHA256)) | Out-Null $txt.Add(("Entries: {0}" -f $ptr.Entries)) | Out-Null $txt.Add(("SizeBytes: {0}" -f $ptr.SizeBytes)) | Out-Null $txt.Add("") | Out-Null $txt.Add("[FILES]") | Out-Null foreach($it in $items){ $txt.Add(("{0} size={1} sha256={2} mtime={3}" -f $it.rel,$it.size,$it.sha256,$it.mtime)) | Out-Null } Write-TextUtf8 $txtPath $txt # logs Write-TextUtf8 $docPath @($docOut) Write-TextUtf8 $accPath @($accOut) # HTML (simple, ascii-only content) $H = @( "","","
root: {0}
created: {1}
label: {2}
Path: {0}`nSHA256: {1}`nEntries: {2}`nSizeBytes: {3}" -f $ptr.Path,$ptr.SHA256,$ptr.Entries,$ptr.SizeBytes),
"| relpath | size | sha256 | lastwrite |
|---|---|---|---|
| {0} | {1} | {2} | {3} |