# ═══════════════════════════════════════════════════════════════════════════ # AUTARCH — Full Windows Installer Builder # # Auto-installs required tools, then builds: # dist\bin\AUTARCH\AUTARCH.exe — standalone executable bundle # dist\bin\AUTARCH-1.3-win64.msi — Windows installer # # Usage (run as Administrator or allow UAC prompt): # powershell -ExecutionPolicy Bypass -File scripts\build-all.ps1 # # What this script installs (if not already present): # - pyinstaller (via pip) # - WiX Toolset 4 (via dotnet tool install --global wix) # - .NET SDK (via winget, if dotnet is missing) # ═══════════════════════════════════════════════════════════════════════════ param( [string]$Python = "python", [string]$Version = "1.3", [switch]$SkipExe = $false, # Skip .exe build (use existing dist\bin\AUTARCH\) [switch]$SkipMsi = $false # Skip .msi build ) $ErrorActionPreference = "Stop" $AppDir = Split-Path -Parent $PSScriptRoot $BinDir = Join-Path $AppDir "dist\bin" $DistDir = Join-Path $AppDir "dist" Write-Host "" Write-Host "████████████████████████████████████████████████████" -ForegroundColor Cyan Write-Host " AUTARCH $Version — Windows Build System" -ForegroundColor Cyan Write-Host "████████████████████████████████████████████████████" -ForegroundColor Cyan Write-Host "" # ── Helper functions ────────────────────────────────────────────────────────── function Write-Step([string]$msg) { Write-Host "" Write-Host " ► $msg" -ForegroundColor Yellow } function Write-OK([string]$msg) { Write-Host " ✔ $msg" -ForegroundColor Green } function Write-Warn([string]$msg) { Write-Host " ⚠ $msg" -ForegroundColor Magenta } function Test-Command([string]$cmd) { return $null -ne (Get-Command $cmd -ErrorAction SilentlyContinue) } # ── 1. Verify Python ────────────────────────────────────────────────────────── Write-Step "Checking Python..." try { $pyVer = & $Python --version 2>&1 Write-OK "$pyVer" } catch { Write-Host "ERROR: Python not found. Install Python 3.10+ from python.org" -ForegroundColor Red exit 1 } # ── 2. Install / verify PyInstaller ────────────────────────────────────────── Write-Step "Checking PyInstaller..." $piVer = & $Python -c "import PyInstaller; print(PyInstaller.__version__)" 2>&1 if ($piVer -match "^\d") { Write-OK "PyInstaller $piVer" } else { Write-Warn "PyInstaller not found — installing..." & $Python -m pip install pyinstaller --quiet $piVer = & $Python -c "import PyInstaller; print(PyInstaller.__version__)" 2>&1 Write-OK "PyInstaller $piVer installed" } # ── 3. Install / verify .NET SDK (required for WiX 4) ──────────────────────── if (-not $SkipMsi) { Write-Step "Checking .NET SDK (required for WiX)..." if (Test-Command "dotnet") { $dotnetVer = (dotnet --version 2>&1) Write-OK ".NET SDK $dotnetVer" } else { Write-Warn ".NET SDK not found — installing via winget..." if (Test-Command "winget") { winget install Microsoft.DotNet.SDK.8 --silent --accept-package-agreements --accept-source-agreements $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") if (Test-Command "dotnet") { Write-OK ".NET SDK installed" } else { Write-Host "ERROR: Failed to install .NET SDK. Install manually from https://dot.net" -ForegroundColor Red Write-Host " Then re-run this script." -ForegroundColor Yellow exit 1 } } else { Write-Host "ERROR: winget not found. Install .NET SDK 8+ manually from https://dot.net" -ForegroundColor Red Write-Host " Then re-run this script." -ForegroundColor Yellow exit 1 } } } # ── 4. Install / verify WiX Toolset 4 ──────────────────────────────────────── if (-not $SkipMsi) { Write-Step "Checking WiX Toolset 4..." $wixOk = $false if (Test-Command "wix") { $wixVer = (wix --version 2>&1) Write-OK "wix $wixVer" $wixOk = $true } else { # Try via dotnet tool $dtWix = (dotnet tool list --global 2>&1) | Select-String "wix" if ($dtWix) { Write-OK "WiX found (dotnet tool)" $wixOk = $true } else { Write-Warn "WiX not found — installing via dotnet tool..." dotnet tool install --global wix --prerelease 2>&1 | Out-Null # Refresh PATH $env:Path += ";$env:USERPROFILE\.dotnet\tools" if (Test-Command "wix") { $wixVer = (wix --version 2>&1) Write-OK "WiX $wixVer installed" $wixOk = $true } else { Write-Warn "WiX could not be installed automatically." Write-Warn "Install manually: dotnet tool install --global wix" Write-Warn "Skipping MSI build." $SkipMsi = $true } } } } # ── 5. Create output directory ──────────────────────────────────────────────── Write-Step "Preparing output directory..." if (-not (Test-Path $BinDir)) { New-Item -ItemType Directory -Path $BinDir -Force | Out-Null } Write-OK "dist\bin\" # ── 6. Build .exe with PyInstaller ─────────────────────────────────────────── if (-not $SkipExe) { Write-Step "Building AUTARCH.exe (PyInstaller one-directory bundle)..." Write-Host " This may take 3–10 minutes..." -ForegroundColor DarkGray $SpecFile = Join-Path $AppDir "autarch.spec" $WorkDir = Join-Path $DistDir ".pyinstaller-work" Set-Location $AppDir & $Python -m PyInstaller $SpecFile ` --distpath $BinDir ` --workpath $WorkDir ` --noconfirm ` --clean if ($LASTEXITCODE -ne 0) { Write-Host "ERROR: PyInstaller build failed." -ForegroundColor Red exit $LASTEXITCODE } $exePath = Join-Path $BinDir "AUTARCH\AUTARCH.exe" if (Test-Path $exePath) { $sizeMB = [math]::Round((Get-ChildItem (Join-Path $BinDir "AUTARCH") -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB, 1) Write-OK "dist\bin\AUTARCH\AUTARCH.exe ($sizeMB MB bundle)" } else { Write-Host "ERROR: AUTARCH.exe not found after build." -ForegroundColor Red exit 1 } } else { Write-Warn "Skipping .exe build (-SkipExe)" $exePath = Join-Path $BinDir "AUTARCH\AUTARCH.exe" if (-not (Test-Path $exePath)) { Write-Host "ERROR: dist\bin\AUTARCH\AUTARCH.exe not found. Remove -SkipExe to build it." -ForegroundColor Red exit 1 } } # ── 7. Generate WiX source (.wxs) from PyInstaller output ──────────────────── if (-not $SkipMsi) { Write-Step "Generating WiX source from AUTARCH bundle..." $WxsFile = Join-Path $DistDir ".wix\AUTARCH.wxs" $WxsDir = Split-Path $WxsFile $BundleDir = Join-Path $BinDir "AUTARCH" $MsiOut = Join-Path $BinDir "AUTARCH-${Version}-win64.msi" if (-not (Test-Path $WxsDir)) { New-Item -ItemType Directory -Path $WxsDir -Force | Out-Null } # Use WiX 4 harvest tool to generate component list from the bundle directory $HeatOut = Join-Path $WxsDir "components.wxs" # Build WiX 4 MSI directly using wix build command Write-Host " Running wix build (WiX 4)..." -ForegroundColor DarkGray # Create a minimal WiX 4 package definition $WixSrcDir = Join-Path $DistDir ".wix" $PackageWxs = Join-Path $WixSrcDir "Package.wxs" # Generate file list for WiX $files = Get-ChildItem $BundleDir -Recurse -File $compLines = @() $fileLines = @() $i = 0 foreach ($f in $files) { $rel = $f.FullName.Substring($BundleDir.Length + 1) $relDir = [System.IO.Path]::GetDirectoryName($rel) $id = "f$i" $compId = "c$i" $fileLines += " " $compLines += " " $i++ } # Write Package.wxs (WiX 4 syntax) @" "@ | Out-File -FilePath $PackageWxs -Encoding utf8 # Add all files as components $i = 0 foreach ($f in $files) { $rel = $f.FullName.Substring($BundleDir.Length + 1) $relDir = [System.IO.Path]::GetDirectoryName($rel) $fid = "File_$i" $cid = "Comp_$i" $did = if ($relDir) { "Dir_$($relDir.Replace('\','_').Replace(' ','_'))" } else { "INSTALLFOLDER" } $srcPath = $f.FullName " " | Out-File -FilePath $PackageWxs -Encoding utf8 -Append $i++ } @" "@ | Out-File -FilePath $PackageWxs -Encoding utf8 -Append Write-Host " Compiling MSI with WiX 4..." -ForegroundColor DarkGray $env:Path += ";$env:USERPROFILE\.dotnet\tools" wix build $PackageWxs -out $MsiOut if ($LASTEXITCODE -ne 0) { Write-Host "ERROR: WiX MSI build failed." -ForegroundColor Red Write-Warn "The .exe bundle is still available at dist\bin\AUTARCH\AUTARCH.exe" exit $LASTEXITCODE } if (Test-Path $MsiOut) { $sizeMB = [math]::Round((Get-Item $MsiOut).Length / 1MB, 1) Write-OK "dist\bin\AUTARCH-${Version}-win64.msi ($sizeMB MB)" } } # ── 8. Summary ──────────────────────────────────────────────────────────────── Write-Host "" Write-Host "████████████████████████████████████████████████████" -ForegroundColor Green Write-Host " BUILD COMPLETE" -ForegroundColor Green Write-Host "████████████████████████████████████████████████████" -ForegroundColor Green Write-Host "" Write-Host " Standalone bundle: dist\bin\AUTARCH\AUTARCH.exe" -ForegroundColor White if (-not $SkipMsi) { Write-Host " MSI installer: dist\bin\AUTARCH-${Version}-win64.msi" -ForegroundColor White } Write-Host "" Write-Host " Run standalone: .\dist\bin\AUTARCH\AUTARCH.exe --web" -ForegroundColor Cyan Write-Host " Install MSI: msiexec /i dist\bin\AUTARCH-${Version}-win64.msi" -ForegroundColor Cyan Write-Host ""