🚧 Add build script
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
# 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."
|
||||
}
|
||||
Reference in New Issue
Block a user