127 lines
4.0 KiB
PowerShell
127 lines
4.0 KiB
PowerShell
# Build script: packages the CLI as a single self-executing .exe
|
|
#
|
|
# Usage:
|
|
# .\build.ps1 -> dist\mitsubishi-label-converter.exe
|
|
# .\build.ps1 -Clean -> remove build artifacts first
|
|
# .\build.ps1 -Onefile -> single-file exe (slower start, one file)
|
|
# default is one-folder mode (fast start)
|
|
# .\build.ps1 -Test -> run the exe against the real assets afterwards
|
|
#
|
|
# Requirements: pyinstaller installed in the active environment
|
|
# pip install pyinstaller
|
|
|
|
[CmdletBinding()]
|
|
param(
|
|
[switch]$Clean,
|
|
[switch]$Onefile,
|
|
[switch]$Test,
|
|
# Explicit interpreter, e.g. -Python C:\Path\To\python.exe
|
|
[string]$Python
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
$root = $PSScriptRoot
|
|
$exename = "mitsubishi-label-converter"
|
|
$dist = Join-Path $root "dist"
|
|
|
|
# Resolve a working Python interpreter -------------------------------
|
|
# The Microsoft Store 'python' alias can shadow a real install, so verify
|
|
# each candidate by actually running it.
|
|
function Test-Python([string]$cmd) {
|
|
if (-not $cmd) { return $false }
|
|
try {
|
|
& $cmd -c "import sys; sys.exit(0)" 2>$null
|
|
return ($LASTEXITCODE -eq 0)
|
|
} catch {
|
|
return $false
|
|
}
|
|
}
|
|
|
|
if (-not $Python) {
|
|
$candidates = @(
|
|
(Join-Path $root ".venv\Scripts\python.exe"), # project venv first
|
|
"python",
|
|
"py"
|
|
)
|
|
foreach ($c in $candidates) {
|
|
if (Test-Python $c) { $Python = $c; break }
|
|
}
|
|
}
|
|
if (-not $Python -or -not (Test-Python $Python)) {
|
|
Write-Error @"
|
|
No working Python interpreter found.
|
|
Tried: project .venv, 'python' on PATH, 'py' launcher.
|
|
Create a venv (python -m venv .venv) or pass one explicitly:
|
|
.\build.ps1 -Python C:\Path\To\python.exe
|
|
"@
|
|
}
|
|
Write-Host "==> Using Python: $Python"
|
|
|
|
# Sanity checks ------------------------------------------------------------
|
|
& $Python -m PyInstaller --version 2>$null | Out-Null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "PyInstaller not found in '$Python'. Run: $Python -m pip install pyinstaller"
|
|
}
|
|
|
|
if ($Clean) {
|
|
Write-Host "==> Cleaning build artifacts..."
|
|
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue `
|
|
(Join-Path $root "build"), $dist
|
|
# remove the egg-info generated by editable installs
|
|
Get-ChildItem $root -Filter "*.egg-info" -Directory -ErrorAction SilentlyContinue |
|
|
Remove-Item -Recurse -Force -ErrorAction SilentlyContinue
|
|
}
|
|
|
|
# Build --------------------------------------------------------------------
|
|
$modeArgs = @()
|
|
if ($Onefile) { $modeArgs += "--onefile" } else { $modeArgs += "--onedir" }
|
|
|
|
Write-Host "==> Building $exename ($($modeArgs -join ' '))..."
|
|
& $Python -m PyInstaller @modeArgs `
|
|
--name $exename `
|
|
--noconfirm `
|
|
--clean `
|
|
--console `
|
|
--paths "$root\src" `
|
|
"$root\run.py"
|
|
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "PyInstaller failed with exit code $LASTEXITCODE"
|
|
}
|
|
|
|
# Locate the exe -----------------------------------------------------------
|
|
if ($Onefile) {
|
|
$exe = Join-Path $dist "$exename.exe"
|
|
} else {
|
|
$exe = Join-Path $dist "$exename\$exename.exe"
|
|
}
|
|
if (-not (Test-Path $exe)) {
|
|
Write-Error "Build finished but exe not found at $exe"
|
|
}
|
|
|
|
$size = "{0:N1} MB" -f ((Get-Item $exe).Length / 1MB)
|
|
Write-Host "==> Built: $exe ($size)"
|
|
|
|
# Optional smoke test -------------------------------------------------------
|
|
if ($Test) {
|
|
Write-Host "==> Smoke testing against assets/Global.xml..."
|
|
$testOut = Join-Path $dist "smoketest.xlsx"
|
|
& $exe to-xlsx (Join-Path $root "assets\Global.xml") `
|
|
--sdt (Join-Path $root "assets\SDT.xml") `
|
|
-o $testOut --force
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "Smoke test failed"
|
|
}
|
|
& $exe report (Join-Path $root "assets\Global.xml") --sdt (Join-Path $root "assets\SDT.xml")
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "Smoke test (report) failed"
|
|
}
|
|
Remove-Item $testOut -Force -ErrorAction SilentlyContinue
|
|
Write-Host "==> Smoke test OK"
|
|
}
|
|
|
|
Write-Host ""
|
|
Write-Host "Done. Distribute: $exe"
|
|
if (-not $Onefile) {
|
|
Write-Host "Note: one-folder mode requires the whole dist\$exename folder."
|
|
} |