mirror of
https://github.com/harvard-edge/cs249r_book.git
synced 2026-04-29 00:59:07 -05:00
fix: convert preflight here-string from expandable to literal for file-based execution
The preflight script used @"..."@ (expandable here-string) with backtick-escaped variables, which produced invalid PowerShell when written to a .ps1 file. Switch to @'...'@ (literal here-string) with normal PowerShell syntax. Format-specific checks (PDF/EPUB) are appended conditionally using GitHub Actions expressions.
This commit is contained in:
137
.github/workflows/book-build-container.yml
vendored
137
.github/workflows/book-build-container.yml
vendored
@@ -459,80 +459,87 @@ jobs:
|
||||
shell: pwsh
|
||||
run: |
|
||||
Write-Host "🧪 Running Windows toolchain preflight checks..."
|
||||
$preflightScript = @"
|
||||
$scriptContent = @'
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$PSNativeCommandUseErrorActionPreference = $true
|
||||
|
||||
`$ErrorActionPreference = 'Stop'
|
||||
`$PSNativeCommandUseErrorActionPreference = `$true
|
||||
|
||||
function Invoke-Check {
|
||||
param(
|
||||
[string]`$Name,
|
||||
[scriptblock]`$Action
|
||||
)
|
||||
Write-Host \"▶ preflight: `$Name\"
|
||||
try {
|
||||
& `$Action
|
||||
if (-not `$?) { throw 'Command returned non-zero status' }
|
||||
Write-Host \"✅ preflight: `$Name\"
|
||||
} catch {
|
||||
`$errorMessage = `$_.Exception.Message
|
||||
Write-Error (\"❌ preflight failed: `$Name -- {0}\" -f `$errorMessage)
|
||||
throw
|
||||
}
|
||||
function Invoke-Check {
|
||||
param(
|
||||
[string]$Name,
|
||||
[scriptblock]$Action
|
||||
)
|
||||
Write-Host ">> preflight: $Name"
|
||||
try {
|
||||
& $Action
|
||||
if (-not $?) { throw 'Command returned non-zero status' }
|
||||
Write-Host "OK preflight: $Name"
|
||||
} catch {
|
||||
$errorMessage = $_.Exception.Message
|
||||
Write-Error ("FAIL preflight: $Name -- {0}" -f $errorMessage)
|
||||
throw
|
||||
}
|
||||
}
|
||||
|
||||
Invoke-Check 'quarto on PATH' { `$resolved = Get-Command quarto -ErrorAction Stop; Write-Host (\" quarto -> {0}\" -f `$resolved.Source) }
|
||||
Invoke-Check 'quarto version' { quarto --version | Select-Object -First 1 }
|
||||
Invoke-Check 'pandoc available' {
|
||||
`$pandocCmd = Get-Command pandoc -ErrorAction SilentlyContinue
|
||||
if (`$pandocCmd) {
|
||||
Write-Host (\" pandoc -> {0}\" -f `$pandocCmd.Source)
|
||||
} else {
|
||||
quarto pandoc --version | Select-Object -First 1 | Out-Null
|
||||
Write-Host \" pandoc -> bundled via quarto\"
|
||||
}
|
||||
Invoke-Check 'quarto on PATH' { $resolved = Get-Command quarto -ErrorAction Stop; Write-Host (" quarto -> {0}" -f $resolved.Source) }
|
||||
Invoke-Check 'quarto version' { quarto --version | Select-Object -First 1 }
|
||||
Invoke-Check 'pandoc available' {
|
||||
$pandocCmd = Get-Command pandoc -ErrorAction SilentlyContinue
|
||||
if ($pandocCmd) {
|
||||
Write-Host (" pandoc -> {0}" -f $pandocCmd.Source)
|
||||
} else {
|
||||
quarto pandoc --version | Select-Object -First 1 | Out-Null
|
||||
Write-Host " pandoc -> bundled via quarto"
|
||||
}
|
||||
Invoke-Check 'pandoc version' {
|
||||
`$pandocCmd = Get-Command pandoc -ErrorAction SilentlyContinue
|
||||
if (`$pandocCmd) {
|
||||
pandoc --version | Select-Object -First 1
|
||||
} else {
|
||||
quarto pandoc --version | Select-Object -First 1
|
||||
}
|
||||
}
|
||||
Invoke-Check 'pandoc version' {
|
||||
$pandocCmd = Get-Command pandoc -ErrorAction SilentlyContinue
|
||||
if ($pandocCmd) {
|
||||
pandoc --version | Select-Object -First 1
|
||||
} else {
|
||||
quarto pandoc --version | Select-Object -First 1
|
||||
}
|
||||
Invoke-Check 'python on PATH' { `$resolved = Get-Command python -ErrorAction Stop; Write-Host (\" python -> {0}\" -f `$resolved.Source) }
|
||||
Invoke-Check 'python version' { python --version }
|
||||
Invoke-Check 'python3 on PATH' { `$resolved = Get-Command python3 -ErrorAction Stop; Write-Host (\" python3 -> {0}\" -f `$resolved.Source) }
|
||||
Invoke-Check 'python3 version' { python3 --version }
|
||||
Invoke-Check 'mlsysim import' { python -c 'import mlsysim,sys; print(\"mlsysim:\", mlsysim.__file__); print(\"python:\", sys.executable)' }
|
||||
Invoke-Check 'Rscript on PATH' { `$resolved = Get-Command Rscript -ErrorAction Stop; Write-Host (\" Rscript -> {0}\" -f `$resolved.Source) }
|
||||
Invoke-Check 'Rscript version' { Rscript --version | Select-Object -First 1 }
|
||||
Invoke-Check 'inkscape on PATH' { `$resolved = Get-Command inkscape -ErrorAction Stop; Write-Host (\" inkscape -> {0}\" -f `$resolved.Source) }
|
||||
Invoke-Check 'inkscape version' { inkscape --version | Select-Object -First 1 }
|
||||
}
|
||||
Invoke-Check 'python on PATH' { $resolved = Get-Command python -ErrorAction Stop; Write-Host (" python -> {0}" -f $resolved.Source) }
|
||||
Invoke-Check 'python version' { python --version }
|
||||
Invoke-Check 'python3 on PATH' { $resolved = Get-Command python3 -ErrorAction Stop; Write-Host (" python3 -> {0}" -f $resolved.Source) }
|
||||
Invoke-Check 'python3 version' { python3 --version }
|
||||
Invoke-Check 'mlsysim import' { python -c "import mlsysim,sys; print('mlsysim:', mlsysim.__file__); print('python:', sys.executable)" }
|
||||
Invoke-Check 'Rscript on PATH' { $resolved = Get-Command Rscript -ErrorAction Stop; Write-Host (" Rscript -> {0}" -f $resolved.Source) }
|
||||
Invoke-Check 'Rscript version' { Rscript --version | Select-Object -First 1 }
|
||||
Invoke-Check 'inkscape on PATH' { $resolved = Get-Command inkscape -ErrorAction Stop; Write-Host (" inkscape -> {0}" -f $resolved.Source) }
|
||||
Invoke-Check 'inkscape version' { inkscape --version | Select-Object -First 1 }
|
||||
'@
|
||||
|
||||
if ('${{ matrix.format_name }}' -eq 'PDF') {
|
||||
Invoke-Check 'lualatex on PATH' { `$resolved = Get-Command lualatex -ErrorAction Stop; Write-Host (\" lualatex -> {0}\" -f `$resolved.Source) }
|
||||
Invoke-Check 'lualatex version' { lualatex --version | Select-Object -First 1 }
|
||||
Invoke-Check 'ghostscript on PATH' {
|
||||
`$gsCmd = Get-Command gs -ErrorAction SilentlyContinue
|
||||
if (-not `$gsCmd) { `$gsCmd = Get-Command gswin64c -ErrorAction SilentlyContinue }
|
||||
if (-not `$gsCmd) { throw 'Ghostscript not found (expected gs or gswin64c)' }
|
||||
Write-Host (\" ghostscript -> {0}\" -f `$gsCmd.Source)
|
||||
}
|
||||
Invoke-Check 'ghostscript version' {
|
||||
`$gsCmd = Get-Command gs -ErrorAction SilentlyContinue
|
||||
if (-not `$gsCmd) { `$gsCmd = Get-Command gswin64c -ErrorAction SilentlyContinue }
|
||||
& `$gsCmd.Source --version
|
||||
}
|
||||
}
|
||||
# Add format-specific checks (GitHub Actions expands matrix vars before PowerShell sees this)
|
||||
$formatChecks = ""
|
||||
if ('${{ matrix.format_name }}' -eq 'PDF') {
|
||||
$formatChecks = @'
|
||||
|
||||
if ('${{ matrix.format_name }}' -eq 'EPUB') {
|
||||
Invoke-Check 'Pillow import' { python -c 'import PIL; print(\"Pillow:\", PIL.__version__)' }
|
||||
}
|
||||
"@
|
||||
Invoke-Check 'lualatex on PATH' { $resolved = Get-Command lualatex -ErrorAction Stop; Write-Host (" lualatex -> {0}" -f $resolved.Source) }
|
||||
Invoke-Check 'lualatex version' { lualatex --version | Select-Object -First 1 }
|
||||
Invoke-Check 'ghostscript on PATH' {
|
||||
$gsCmd = Get-Command gs -ErrorAction SilentlyContinue
|
||||
if (-not $gsCmd) { $gsCmd = Get-Command gswin64c -ErrorAction SilentlyContinue }
|
||||
if (-not $gsCmd) { throw 'Ghostscript not found (expected gs or gswin64c)' }
|
||||
Write-Host (" ghostscript -> {0}" -f $gsCmd.Source)
|
||||
}
|
||||
Invoke-Check 'ghostscript version' {
|
||||
$gsCmd = Get-Command gs -ErrorAction SilentlyContinue
|
||||
if (-not $gsCmd) { $gsCmd = Get-Command gswin64c -ErrorAction SilentlyContinue }
|
||||
& $gsCmd.Source --version
|
||||
}
|
||||
'@
|
||||
}
|
||||
if ('${{ matrix.format_name }}' -eq 'EPUB') {
|
||||
$formatChecks = @'
|
||||
|
||||
Invoke-Check 'Pillow import' { python -c "import PIL; print('Pillow:', PIL.__version__)" }
|
||||
'@
|
||||
}
|
||||
|
||||
$fullScript = $scriptContent + $formatChecks
|
||||
$scriptPath = Join-Path $PWD.Path 'preflight-script.ps1'
|
||||
Set-Content -Path $scriptPath -Value $preflightScript -Encoding UTF8
|
||||
Set-Content -Path $scriptPath -Value $fullScript -Encoding UTF8
|
||||
|
||||
docker run --rm `
|
||||
-e PYTHONPATH=C:\workspace `
|
||||
|
||||
Reference in New Issue
Block a user