Initial Attempts at Packaging Server into EXE

This commit is contained in:
2025-04-30 06:16:57 -06:00
parent 954a5d5554
commit 801c58d11a
3 changed files with 75 additions and 60 deletions

2
.gitignore vendored
View File

@ -9,7 +9,7 @@ Borealis-Server.exe
# Pyinstaller Files # Pyinstaller Files
/Data/Agent/Packaging_Data/ /Data/Agent/Packaging_Data/
/Data/Server/Packaging_Data/ /Data/Server/Packaging_Server/
# Development Folders # Development Folders
/Server/ /Server/

View File

@ -1,75 +1,88 @@
#////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Data/Server/Package-Borealis-Server.ps1 #////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/Data/Server/Package-Borealis-Server.ps1
# ------------------- CONFIGURATION ------------------- # ------------- Configuration -------------
$venvDir = "Pyinstaller_Virtual_Environment" # (all paths are made absolute via Join-Path and $scriptDir)
$serverScript = "Server\Borealis\server.py" $scriptDir = Split-Path $MyInvocation.MyCommand.Definition -Parent
$projectRoot = Resolve-Path (Join-Path $scriptDir "..\..") # go up two levels to <ProjectRoot>\Borealis
$packagingDir = Join-Path $scriptDir "Packaging_Server"
$venvDir = Join-Path $packagingDir "Pyinstaller_Virtual_Environment"
$distDir = Join-Path $packagingDir "dist"
$buildDir = Join-Path $packagingDir "build"
$specPath = $packagingDir
$serverScript = Join-Path $scriptDir "server.py"
$outputName = "Borealis-Server" $outputName = "Borealis-Server"
$distExePath = "dist\$outputName.exe" $finalExeName = "$outputName.exe"
$buildDir = "Pyinstaller_Server_Build" $requirementsPath = Join-Path $scriptDir "server-requirements.txt"
$specFile = "$outputName.spec" $iconPath = Join-Path $scriptDir "Borealis.ico"
$reactBuild = "Server\web-interface\build" # Static assets to bundle:
$tesseractDir = "Server\Borealis\Python_API_Endpoints\Tesseract-OCR" # - the compiled React build under Server/web-interface/build
$staticBuildSrc = Join-Path $projectRoot "Server\web-interface\build"
$staticBuildDst = "web-interface/build"
# - Tesseract-OCR folder must be nested under 'Borealis/Python_API_Endpoints/Tesseract-OCR'
$ocrSrc = Join-Path $scriptDir "Python_API_Endpoints\Tesseract-OCR"
$ocrDst = "Borealis/Python_API_Endpoints/Tesseract-OCR"
$soundsSrc = Join-Path $scriptDir "Sounds"
$soundsDst = "Sounds"
# ------------------- ENV SETUP ------------------- # Embedded Python shipped under Dependencies\Python\python.exe
Write-Host "`n[INFO] Preparing virtual environment and dependencies..." -ForegroundColor Cyan $embeddedPython = Join-Path $projectRoot "Dependencies\Python\python.exe"
$activateScript = "$venvDir\Scripts\Activate.ps1" # ------------- Prepare packaging folder -------------
if (-Not (Test-Path $packagingDir)) {
New-Item -ItemType Directory -Path $packagingDir | Out-Null
}
if (-Not (Test-Path $activateScript)) { # 1) Create or upgrade virtual environment
if (-Not (Test-Path (Join-Path $venvDir "Scripts\python.exe"))) {
Write-Host "[SETUP] Creating virtual environment at $venvDir" Write-Host "[SETUP] Creating virtual environment at $venvDir"
python -m venv $venvDir & $embeddedPython -m venv --upgrade-deps $venvDir
} }
# ------------------- ACTIVATE ------------------- # helper to invoke venv's python
Write-Host "[INFO] Activating virtual environment..." $venvPy = Join-Path $venvDir "Scripts\python.exe"
. $activateScript
# ------------------- INSTALL DEPENDENCIES ------------------- # 2) Bootstrap & upgrade pip
Write-Host "[INFO] Installing project dependencies into virtual environment..." Write-Host "[INFO] Bootstrapping pip"
pip install --upgrade pip > $null & $venvPy -m ensurepip --upgrade
pip install -r requirements.txt & $venvPy -m pip install --upgrade pip
# ------------------- INSTALL PYINSTALLER ------------------- # 3) Install server dependencies
Write-Host "[INFO] Installing PyInstaller..." Write-Host "[INFO] Installing server dependencies"
pip install pyinstaller > $null & $venvPy -m pip install -r $requirementsPath
# Ensure dnspython is available for Eventlet's greendns support
& $venvPy -m pip install dnspython
# Resolve PyInstaller path # 4) Install PyInstaller
$pyInstallerPath = "$venvDir\Scripts\pyinstaller.exe" Write-Host "[INFO] Installing PyInstaller"
& $venvPy -m pip install pyinstaller
if (-Not (Test-Path $pyInstallerPath)) { # 5) Clean previous artifacts
Write-Host "[ERROR] PyInstaller not found even after install. Aborting." -ForegroundColor Red Write-Host "[INFO] Cleaning previous artifacts"
exit 1 Remove-Item -Recurse -Force $distDir, $buildDir, "$specPath\$outputName.spec" -ErrorAction SilentlyContinue
}
# ------------------- CLEANUP OLD BUILD ------------------- # 6) Run PyInstaller, bundling server code and assets
Write-Host "[INFO] Cleaning previous build artifacts..." -ForegroundColor Gray # Collect all Eventlet and DNS submodules to avoid missing dynamic imports
Remove-Item -Recurse -Force "dist", "build", $specFile -ErrorAction SilentlyContinue Write-Host "[INFO] Running PyInstaller"
& $venvPy -m PyInstaller `
--onefile `
--name $outputName `
--icon $iconPath `
--collect-submodules eventlet `
--collect-submodules dns `
--distpath $distDir `
--workpath $buildDir `
--specpath $specPath `
--add-data "$staticBuildSrc;$staticBuildDst" `
--add-data "$ocrSrc;$ocrDst" `
--add-data "$soundsSrc;$soundsDst" `
$serverScript
# ------------------- BUILD PYINSTALLER CMD ------------------- # 7) Copy the final EXE back to Data/Server
$reactStaticAssets = "$reactBuild;web-interface/build" if (Test-Path (Join-Path $distDir $finalExeName)) {
$tesseractAssets = "$tesseractDir;Borealis/Python_API_Endpoints/Tesseract-OCR" Copy-Item (Join-Path $distDir $finalExeName) (Join-Path $scriptDir $finalExeName) -Force
Write-Host "[SUCCESS] Server packaged at $finalExeName"
$cmdArgs = @(
"--onefile",
"--noconfirm",
"--name", "$outputName",
"--add-data", "`"$reactStaticAssets`"",
"--add-data", "`"$tesseractAssets`"",
"--hidden-import=eventlet",
"--clean",
"`"$serverScript`""
)
$arguments = $cmdArgs -join " "
Write-Host "`n[INFO] Running PyInstaller with Start-Process..." -ForegroundColor Yellow
Start-Process -FilePath $pyInstallerPath -ArgumentList $arguments -Wait -NoNewWindow
# ------------------- DONE -------------------
if (Test-Path $distExePath) {
Write-Host "`n[SUCCESS] Packaging complete!"
Write-Host " Output: $distExePath" -ForegroundColor Green
} else { } else {
Write-Host "`n[FAILURE] Packaging failed." -ForegroundColor Red Write-Host "[FAILURE] Packaging failed." -ForegroundColor Red
} }

View File

@ -1,4 +1,6 @@
Folder Structure: #////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: <ProjectRoot>/project_directory_tree.txt
Folder Structure:
├── Dependencies ├── Dependencies
├── Launch-Borealis.ps1 ├── Launch-Borealis.ps1
├── Launch-Borealis.sh ├── Launch-Borealis.sh