231 lines
8.9 KiB
PowerShell
231 lines
8.9 KiB
PowerShell
# MiroFish Windows build script
|
|
# Requirements: Python 3.11+, Node.js 18+, Inno Setup 6
|
|
#
|
|
# Usage:
|
|
# .\build.ps1
|
|
# .\build.ps1 -PyInstaller
|
|
# .\build.ps1 -SkipFrontend
|
|
# .\build.ps1 -SkipBackend
|
|
# .\build.ps1 -SkipInstaller
|
|
# .\build.ps1 -Clean
|
|
|
|
param(
|
|
[switch]$SkipFrontend,
|
|
[switch]$SkipBackend,
|
|
[switch]$SkipInstaller,
|
|
[switch]$Clean,
|
|
[switch]$PyInstaller
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
$ProjectRoot = Split-Path -Parent $PSScriptRoot
|
|
$DistDir = Join-Path $ProjectRoot "dist"
|
|
$InstallerDir = Join-Path $ProjectRoot "installer"
|
|
$PythonVersion = "3.11.9"
|
|
$PythonEmbedUrl = "https://www.python.org/ftp/python/$PythonVersion/python-$PythonVersion-embed-amd64.zip"
|
|
|
|
Write-Host "============================================" -ForegroundColor Cyan
|
|
Write-Host " MiroFish Windows Builder" -ForegroundColor Cyan
|
|
Write-Host "============================================" -ForegroundColor Cyan
|
|
Write-Host ""
|
|
|
|
if ($PyInstaller) {
|
|
Write-Host "Mode: PyInstaller (large, standalone)" -ForegroundColor Magenta
|
|
} else {
|
|
Write-Host "Mode: Embedded Python (recommended)" -ForegroundColor Magenta
|
|
}
|
|
Write-Host ""
|
|
|
|
if ($Clean -or -not (Test-Path $DistDir)) {
|
|
Write-Host "[1/5] Cleaning output..." -ForegroundColor Yellow
|
|
if (Test-Path $DistDir) {
|
|
Remove-Item -Recurse -Force $DistDir
|
|
}
|
|
New-Item -ItemType Directory -Force -Path $DistDir | Out-Null
|
|
}
|
|
|
|
$MiroFishDist = Join-Path $DistDir "MiroFish"
|
|
New-Item -ItemType Directory -Force -Path $MiroFishDist | Out-Null
|
|
New-Item -ItemType Directory -Force -Path (Join-Path $MiroFishDist "backend") | Out-Null
|
|
New-Item -ItemType Directory -Force -Path (Join-Path $MiroFishDist "frontend") | Out-Null
|
|
|
|
if (-not $SkipFrontend) {
|
|
Write-Host "[2/5] Building frontend..." -ForegroundColor Yellow
|
|
Push-Location (Join-Path $ProjectRoot "frontend")
|
|
try {
|
|
npm install
|
|
npm run build
|
|
$FrontendDist = Join-Path -Path $ProjectRoot -ChildPath "frontend\\dist"
|
|
$TargetFrontendDist = Join-Path -Path $MiroFishDist -ChildPath "frontend\\dist"
|
|
if (Test-Path $FrontendDist) {
|
|
if (Test-Path $TargetFrontendDist) {
|
|
Remove-Item -Recurse -Force $TargetFrontendDist
|
|
}
|
|
Copy-Item -Recurse -Force $FrontendDist $TargetFrontendDist
|
|
Write-Host " Frontend build complete" -ForegroundColor Green
|
|
} else {
|
|
throw "Frontend build failed: dist not found"
|
|
}
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
} else {
|
|
Write-Host "[2/5] Skipped frontend build" -ForegroundColor Gray
|
|
}
|
|
|
|
if (-not $SkipBackend) {
|
|
Write-Host "[3/5] Preparing backend..." -ForegroundColor Yellow
|
|
if ($PyInstaller) {
|
|
Write-Host " Using PyInstaller..." -ForegroundColor Gray
|
|
Push-Location (Join-Path $ProjectRoot "backend")
|
|
try {
|
|
uv sync
|
|
uv pip install pyinstaller
|
|
uv run pyinstaller `
|
|
--name "mirofish_backend" `
|
|
--distpath "$DistDir\backend_temp" `
|
|
--workpath "$DistDir\build" `
|
|
--specpath "$DistDir" `
|
|
--add-data "app;app" `
|
|
--hidden-import "flask" `
|
|
--hidden-import "flask_cors" `
|
|
--hidden-import "openai" `
|
|
--hidden-import "zep_cloud" `
|
|
--hidden-import "pydantic" `
|
|
--hidden-import "dotenv" `
|
|
--hidden-import "charset_normalizer" `
|
|
--hidden-import "chardet" `
|
|
--hidden-import "fitz" `
|
|
--noconfirm `
|
|
--console `
|
|
run.py
|
|
$BackendBuild = Join-Path -Path $DistDir -ChildPath "backend_temp\\mirofish_backend"
|
|
if (Test-Path $BackendBuild) {
|
|
Copy-Item -Recurse -Force "$BackendBuild\*" (Join-Path $MiroFishDist "backend")
|
|
Write-Host " Backend build complete" -ForegroundColor Green
|
|
} else {
|
|
throw "Backend build failed"
|
|
}
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
} else {
|
|
Write-Host " Downloading embedded Python $PythonVersion..." -ForegroundColor Gray
|
|
$PythonZip = Join-Path $DistDir "python-embed.zip"
|
|
$PythonDir = Join-Path $MiroFishDist "python"
|
|
if (-not (Test-Path $PythonZip)) {
|
|
Invoke-WebRequest -Uri $PythonEmbedUrl -OutFile $PythonZip
|
|
}
|
|
Write-Host " Extracting embedded Python..." -ForegroundColor Gray
|
|
Expand-Archive -Path $PythonZip -DestinationPath $PythonDir -Force
|
|
|
|
$PthFile = Get-ChildItem -Path $PythonDir -Filter "python*._pth" | Select-Object -First 1
|
|
if ($PthFile) {
|
|
$PthContent = Get-Content $PthFile.FullName
|
|
$PthContent = $PthContent -replace "^#import site", "import site"
|
|
if ($PthContent -notcontains "Lib\site-packages") {
|
|
$PthContent += "Lib\site-packages"
|
|
}
|
|
Set-Content -Path $PthFile.FullName -Value $PthContent
|
|
}
|
|
|
|
Write-Host " Installing pip..." -ForegroundColor Gray
|
|
$GetPipUrl = "https://bootstrap.pypa.io/get-pip.py"
|
|
$GetPipPath = Join-Path $DistDir "get-pip.py"
|
|
if (-not (Test-Path $GetPipPath)) {
|
|
Invoke-WebRequest -Uri $GetPipUrl -OutFile $GetPipPath
|
|
}
|
|
$PythonExe = Join-Path $PythonDir "python.exe"
|
|
& $PythonExe $GetPipPath --no-warn-script-location
|
|
|
|
Write-Host " Installing backend deps..." -ForegroundColor Gray
|
|
$RequirementsFile = Join-Path -Path $ProjectRoot -ChildPath "backend\\requirements.txt"
|
|
& $PythonExe -m pip install -r $RequirementsFile --no-warn-script-location -q
|
|
|
|
Write-Host " Copying backend sources..." -ForegroundColor Gray
|
|
$BackendSrc = Join-Path -Path $ProjectRoot -ChildPath "backend"
|
|
$BackendDst = Join-Path -Path $MiroFishDist -ChildPath "backend"
|
|
Copy-Item -Force (Join-Path -Path $BackendSrc -ChildPath "run.py") $BackendDst
|
|
Copy-Item -Recurse -Force (Join-Path -Path $BackendSrc -ChildPath "app") (Join-Path -Path $BackendDst -ChildPath "app")
|
|
Write-Host " Backend prepared" -ForegroundColor Green
|
|
}
|
|
} else {
|
|
Write-Host "[3/5] Skipped backend" -ForegroundColor Gray
|
|
}
|
|
|
|
Write-Host "[4/5] Building launcher..." -ForegroundColor Yellow
|
|
Push-Location $ProjectRoot
|
|
try {
|
|
$pip = pip --version 2>$null
|
|
if (-not $?) {
|
|
Write-Host " Installing PyInstaller..." -ForegroundColor Gray
|
|
}
|
|
pip install pyinstaller -q
|
|
pyinstaller `
|
|
--name "MiroFish" `
|
|
--distpath "$DistDir\launcher_temp" `
|
|
--workpath "$DistDir\build" `
|
|
--specpath "$DistDir" `
|
|
--icon "$InstallerDir\MiroFish.ico" `
|
|
--onefile `
|
|
--windowed `
|
|
--noconfirm `
|
|
launcher.py
|
|
$LauncherExe = Join-Path -Path $DistDir -ChildPath "launcher_temp\\MiroFish.exe"
|
|
Copy-Item -Force $LauncherExe $MiroFishDist
|
|
Write-Host " Launcher built" -ForegroundColor Green
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
|
|
if (-not $SkipInstaller) {
|
|
Write-Host "[5/5] Building installer..." -ForegroundColor Yellow
|
|
$ISCCPaths = @(
|
|
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe",
|
|
"C:\Program Files\Inno Setup 6\ISCC.exe",
|
|
"$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe"
|
|
)
|
|
$ISCC = $null
|
|
foreach ($path in $ISCCPaths) {
|
|
if (Test-Path $path) {
|
|
$ISCC = $path
|
|
break
|
|
}
|
|
}
|
|
if ($ISCC) {
|
|
Push-Location $InstallerDir
|
|
try {
|
|
& $ISCC "setup.iss"
|
|
Write-Host " Installer built" -ForegroundColor Green
|
|
Write-Host (" Output: {0}" -f (Join-Path $InstallerDir "output")) -ForegroundColor Cyan
|
|
} finally {
|
|
Pop-Location
|
|
}
|
|
} else {
|
|
Write-Host " Inno Setup not found; skipping installer" -ForegroundColor Yellow
|
|
Write-Host " Install Inno Setup 6: https://jrsoftware.org/isinfo.php" -ForegroundColor Yellow
|
|
}
|
|
} else {
|
|
Write-Host "[5/5] Skipped installer" -ForegroundColor Gray
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Cleaning temp files..." -ForegroundColor Gray
|
|
Remove-Item -Recurse -Force (Join-Path $DistDir "backend_temp") -ErrorAction SilentlyContinue
|
|
Remove-Item -Recurse -Force (Join-Path $DistDir "launcher_temp") -ErrorAction SilentlyContinue
|
|
Remove-Item -Recurse -Force (Join-Path $DistDir "build") -ErrorAction SilentlyContinue
|
|
Remove-Item -Force (Join-Path $DistDir "*.spec") -ErrorAction SilentlyContinue
|
|
Remove-Item -Force (Join-Path $DistDir "python-embed.zip") -ErrorAction SilentlyContinue
|
|
Remove-Item -Force (Join-Path $DistDir "get-pip.py") -ErrorAction SilentlyContinue
|
|
|
|
Write-Host ""
|
|
Write-Host "============================================" -ForegroundColor Green
|
|
Write-Host " Done" -ForegroundColor Green
|
|
Write-Host "============================================" -ForegroundColor Green
|
|
Write-Host ""
|
|
Write-Host "Output: $MiroFishDist" -ForegroundColor Cyan
|
|
if (Test-Path (Join-Path $InstallerDir "output")) {
|
|
Write-Host ("Installer: {0}" -f (Join-Path $InstallerDir "output")) -ForegroundColor Cyan
|
|
}
|
|
Write-Host ""
|