<# .SYNOPSIS Regenerate bundle-lock.json from the staged bundle, after showing what would change. .DESCRIPTION Run this on the machine that assembled the wheelhouse, once the bundle holds the payload you intend to ship: bundle\wheels\ the wheels, built with the matching Python bundle\python\ the Python installer bundle\httpplatformhandler\ the IIS module MSI bundle\urlrewrite\ URL Rewrite MSI (optional) bundle\mysql\ MySQL MSI (optional) Then COMMIT the resulting bundle-lock.json. That commit is the review: it is the only place a change to what runs as SYSTEM on a customer's server becomes visible to a human. A lock regenerated and committed without reading the diff provides nothing, so this refuses to overwrite an existing lock until you have seen the change and passed -Yes. .EXAMPLE .\refresh-bundle-lock.ps1 # show the diff, write nothing .\refresh-bundle-lock.ps1 -Yes # write it .NOTES Building the wheelhouse itself no longer requires Windows. From any machine: pip download -r requirements.txt -d wheels --only-binary=:all: ` --platform win_amd64 --python-version 314 --implementation cp --abi cp314 Do it wherever you like; this script records what came out. #> [CmdletBinding()] param( [string] $BundleRoot = (Join-Path $PSScriptRoot 'bundle'), [string] $LockPath = (Join-Path $PSScriptRoot 'bundle-lock.json'), [string] $PythonTag = 'cp314', [string] $Platform = 'win_amd64', [switch] $Yes ) $ErrorActionPreference = 'Stop' . (Join-Path $PSScriptRoot 'bundle-lock.ps1') function Say { param($m, $c = 'Gray') Write-Host $m -ForegroundColor $c } if (-not (Test-Path $BundleRoot)) { Say "bundle not found: $BundleRoot" 'Red' Say 'Stage it first with build-installer.ps1 (or build-installer.sh), then add' 'Yellow' Say 'the wheels and installers by hand.' 'Yellow' exit 1 } Say '' Say " Hashing $BundleRoot" 'Cyan' $new = New-BundleLock -BundleRoot $BundleRoot -PythonTag $PythonTag -Platform $Platform foreach ($name in $new.payloads.Keys) { Say (" {0,-22} {1,4} files" -f $name, $new.payloads[$name].files.Count) } $old = Read-BundleLock $LockPath if (-not $old) { Say '' Say ' No existing lock - this will be the first one.' 'Yellow' } else { # Diff by file, per payload, so the operator sees exactly which artifacts # changed rather than "the lock is different". Say '' Say ' Changes against the committed lock:' 'Cyan' $changes = 0 foreach ($name in $new.payloads.Keys) { $oldFiles = @{} if ($old.payloads.PSObject.Properties.Name -contains $name) { foreach ($p in $old.payloads.$name.files.PSObject.Properties) { $oldFiles[$p.Name] = $p.Value.sha256 } } $newFiles = $new.payloads[$name].files foreach ($rel in ($newFiles.Keys | Sort-Object)) { if (-not $oldFiles.ContainsKey($rel)) { Say " + $name/$rel" 'Green'; $changes++ } elseif ($oldFiles[$rel] -ne $newFiles[$rel].sha256) { Say " ~ $name/$rel (content changed)" 'Yellow'; $changes++ } } foreach ($rel in ($oldFiles.Keys | Sort-Object)) { if (-not $newFiles.ContainsKey($rel)) { Say " - $name/$rel" 'Red'; $changes++ } } } foreach ($p in $old.payloads.PSObject.Properties.Name) { if (-not $new.payloads.Contains($p)) { Say " - $p/ (whole payload gone)" 'Red'; $changes++ } } if ($changes -eq 0) { Say ' none - the bundle already matches the lock' 'Green' exit 0 } Say '' Say (" {0} change(s)." -f $changes) 'White' } if (-not $Yes) { Say '' Say ' Nothing written. Read the list above, then re-run with -Yes.' 'Yellow' Say ' Commit the resulting bundle-lock.json - that commit IS the review.' 'Yellow' exit 2 } # ConvertTo-Json defaults to a depth of 2, which silently flattens the per-file # entries into "System.Collections.Hashtable" strings and produces a lock that # verifies against nothing. $new | ConvertTo-Json -Depth 8 | Set-Content -Path $LockPath -Encoding UTF8 Say '' Say " Written: $LockPath" 'Green' Say ' Commit it.' 'Green'