diff options
Diffstat (limited to 'packaging/win/build-node-runtime.ps1')
| -rw-r--r-- | packaging/win/build-node-runtime.ps1 | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/packaging/win/build-node-runtime.ps1 b/packaging/win/build-node-runtime.ps1 new file mode 100644 index 0000000..c432e01 --- /dev/null +++ b/packaging/win/build-node-runtime.ps1 @@ -0,0 +1,138 @@ +<# +.SYNOPSIS + Freeze the MeshBay node daemon into a relocatable Windows binary. + +.DESCRIPTION + Produces packages/meshbay-client/node-runtime/meshbay-node.exe (+ its + onedir payload) with PyInstaller. electron-builder then carries that tree + into the NSIS installer as an extraResource (see package.json build.win). + + The frozen binary is what the desktop client spawns and what the W3 + autostart launcher points at, so it must be a genuine single .exe -- which + is why this uses PyInstaller and not the python-embed zip (whose pip + console-script wrapper bakes in an absolute interpreter path and does not + survive being installed somewhere else). + + ffmpeg/ffprobe are NOT bundled by default. Pass -FfmpegDir (or set + MESHBAY_FFMPEG_DIR) to copy them in beside the daemon; otherwise the node + resolves them from PATH at startup (meshbay_node.platform.check_media_tools) + and streaming needs ffmpeg installed separately. + +.PARAMETER Python + Interpreter used to build. Must be 3.12+ and able to install the packages. + Default: a throwaway venv this script creates under build/_node-build-venv. + +.PARAMETER FfmpegDir + Directory containing ffmpeg.exe and ffprobe.exe to bundle. Optional. + +.PARAMETER KeepBuildVenv + Do not delete the throwaway build venv on success (faster re-runs). +#> +[CmdletBinding()] +param( + [string]$Python = "", + [string]$FfmpegDir = $env:MESHBAY_FFMPEG_DIR, + [switch]$KeepBuildVenv +) + +$ErrorActionPreference = "Stop" +Set-StrictMode -Version Latest + +$WinDir = $PSScriptRoot +$Repo = (Resolve-Path (Join-Path $WinDir "..\..")).Path +$Client = Join-Path $Repo "packages\meshbay-client" +$OutDir = Join-Path $Client "node-runtime" +$BuildVenv = Join-Path $Client "build\_node-build-venv" +$SpecFile = Join-Path $WinDir "meshbay-node.spec" + +function Step($msg) { Write-Host "==> $msg" -ForegroundColor Cyan } + +# --- 1. interpreter -------------------------------------------------------- +$createdVenv = $false +if (-not $Python) { + Step "creating build venv ($BuildVenv)" + if (Get-Command py -ErrorAction SilentlyContinue) { + & py -3.12 -m venv --clear $BuildVenv + } else { + & python -m venv --clear $BuildVenv + } + if ($LASTEXITCODE -ne 0) { throw "venv creation failed" } + $Python = Join-Path $BuildVenv "Scripts\python.exe" + $createdVenv = $true +} +if (-not (Test-Path $Python)) { throw "Python not found: $Python" } + +$verOut = (& $Python -c "import sys; print(sys.version_info[0]); print(sys.version_info[1])") +$verMajor = [int]$verOut[0] +$verMinor = [int]$verOut[1] +if ($verMajor -lt 3 -or ($verMajor -eq 3 -and $verMinor -lt 12)) { + throw "need Python 3.12 or newer, got $verMajor.$verMinor" +} +Step "python $verMajor.$verMinor ($Python)" + +# --- 2. dependencies ----------------------------------------------------- +Step "installing meshbay-common, meshbay-node and PyInstaller" +& $Python -m pip install --upgrade pip --quiet +& $Python -m pip install --quiet ` + (Join-Path $Repo "packages\meshbay-common") ` + (Join-Path $Repo "packages\meshbay-node") ` + "pyinstaller>=6.10" ` + "tzdata" +# tzdata: Windows ships no IANA zone database, so zoneinfo (pulled in +# transitively) has nothing to read without it. PyInstaller warns +# 'Hidden import "tzdata" not found' when it is absent. +if ($LASTEXITCODE -ne 0) { throw "pip install failed" } + +# --- 3. freeze -------------------------------------------------------- +if (Test-Path $OutDir) { Remove-Item -Recurse -Force $OutDir } +$pyiWork = Join-Path $Client "build\_pyinstaller" +$pyiDist = Join-Path $Client "build\_pyinstaller-dist" +Step "running PyInstaller (this takes a few minutes)" +Push-Location $WinDir +try { + & $Python -m PyInstaller --noconfirm --clean ` + --workpath $pyiWork --distpath $pyiDist ` + $SpecFile + if ($LASTEXITCODE -ne 0) { throw "PyInstaller failed" } +} +finally { + Pop-Location +} + +$frozen = Join-Path $pyiDist "meshbay-node" +if (-not (Test-Path (Join-Path $frozen "meshbay-node.exe"))) { + throw "PyInstaller did not produce meshbay-node.exe at $frozen" +} + +# --- 4. optional ffmpeg ---------------------------------------------- +if ($FfmpegDir) { + foreach ($tool in @("ffmpeg.exe", "ffprobe.exe")) { + $src = Join-Path $FfmpegDir $tool + if (-not (Test-Path $src)) { throw "$tool not found in $FfmpegDir" } + Copy-Item $src (Join-Path $frozen $tool) + Step "bundled $tool" + } +} +else { + Write-Host " ffmpeg not bundled -- the node will look for it on PATH" -ForegroundColor Yellow +} + +# --- 5. publish ---------------------------------------------------- +Move-Item $frozen $OutDir +Remove-Item -Recurse -Force $pyiWork, $pyiDist -ErrorAction SilentlyContinue +if ($createdVenv -and -not $KeepBuildVenv) { + Remove-Item -Recurse -Force $BuildVenv -ErrorAction SilentlyContinue +} + +# --- 6. smoke test ----------------------------------------------- +# Capture, do NOT pipe to Select-Object -First: that stops the native process +# mid-write and reports a spurious non-zero exit. +Step "smoke test: meshbay-node --help" +$exe = Join-Path $OutDir "meshbay-node.exe" +$help = & $exe --help 2>&1 +if ($LASTEXITCODE -ne 0) { throw "frozen meshbay-node --help exited $LASTEXITCODE" } +if ($help -notmatch "meshbay-node") { throw "frozen --help output looks wrong" } + +$mb = (Get-ChildItem $OutDir -Recurse | Measure-Object Length -Sum).Sum / 1MB +Write-Host "" +Write-Host ("OK node-runtime ready at {0} ({1:N0} MB)" -f $OutDir, $mb) -ForegroundColor Green |