$ErrorActionPreference = "Stop" $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $projectRoot = (Resolve-Path (Join-Path $scriptDir "..")).Path Set-Location $projectRoot function Assert-InProject { param([string]$Path) $resolved = Resolve-Path -LiteralPath $Path -ErrorAction SilentlyContinue if ($null -eq $resolved) { return } $rootText = $projectRoot.TrimEnd("\") $pathText = $resolved.Path.TrimEnd("\") if (-not $pathText.StartsWith($rootText, [System.StringComparison]::OrdinalIgnoreCase)) { throw "Refusing to remove path outside project: $pathText" } } function Invoke-Checked { param( [string]$FilePath, [string[]]$Arguments ) & $FilePath @Arguments if ($LASTEXITCODE -ne 0) { throw "Command failed with exit code ${LASTEXITCODE}: $FilePath $($Arguments -join ' ')" } } function Test-PackagingPython { param([string]$Candidate) if ($Candidate -ne "python" -and -not (Test-Path -LiteralPath $Candidate)) { return $false } & $Candidate -c "import OCC; import PyInstaller" *> $null return $LASTEXITCODE -eq 0 } $pythonCandidates = @() if ($env:CONDA_DEFAULT_ENV -eq "pyocc" -and $env:CONDA_PREFIX) { $pythonCandidates += (Join-Path $env:CONDA_PREFIX "python.exe") } if ($env:USERPROFILE) { $pythonCandidates += (Join-Path $env:USERPROFILE "miniforge3\envs\pyocc\python.exe") $pythonCandidates += (Join-Path $env:USERPROFILE "miniconda3\envs\pyocc\python.exe") $pythonCandidates += (Join-Path $env:USERPROFILE "anaconda3\envs\pyocc\python.exe") } $pythonCandidates += "python" $python = $null foreach ($candidate in $pythonCandidates) { if (Test-PackagingPython $candidate) { $python = $candidate break } } if (-not $python) { throw "Could not find a Python environment with OCC and PyInstaller. Activate pyocc or install PyInstaller into pyocc." } Write-Host "Using Python: $python" Write-Host "Running smoke test with source..." Invoke-Checked $python @("main.py", "--smoke-test") $buildDir = Join-Path $projectRoot "build" $appDir = Join-Path $projectRoot "dist\GeometryParametric" $zipPath = Join-Path $projectRoot "dist\GeometryParametric_windows_x64.zip" $specPath = Join-Path $scriptDir "GeometryParametric.spec" foreach ($target in @($buildDir, $appDir, $zipPath)) { Assert-InProject $target if (Test-Path -LiteralPath $target) { Remove-Item -LiteralPath $target -Recurse -Force } } Write-Host "Building PyInstaller folder..." Invoke-Checked $python @("-m", "PyInstaller", "--clean", "--noconfirm", $specPath) if (-not (Test-Path -LiteralPath $appDir)) { throw "PyInstaller did not create $appDir" } $guideName = (-join @( [char]0x51E0, [char]0x4F55, [char]0x53C2, [char]0x6570, [char]0x5316, [char]0x6D4B, [char]0x8BD5, [char]0x8BF4, [char]0x660E )) + ".txt" $docSource = Join-Path (Join-Path $projectRoot "local") $guideName if (Test-Path -LiteralPath $docSource) { Copy-Item -LiteralPath $docSource -Destination (Join-Path $appDir $guideName) -Force } else { Write-Warning "Local test document not found: $docSource" } $modelSourceDir = Join-Path $projectRoot "assets\models" $modelDestDir = Join-Path $appDir "model" New-Item -ItemType Directory -Path $modelDestDir -Force | Out-Null $modelFiles = @() foreach ($pattern in @("*.step", "*.stp")) { $modelFiles += Get-ChildItem -LiteralPath $modelSourceDir -Filter $pattern -File -ErrorAction SilentlyContinue } if ($modelFiles.Count -eq 0) { throw "No STEP model files found in $modelSourceDir" } foreach ($file in $modelFiles) { Copy-Item -LiteralPath $file.FullName -Destination $modelDestDir -Force } Write-Host "Running smoke test with packaged exe..." Invoke-Checked (Join-Path $appDir "main.exe") @("--smoke-test") Write-Host "Creating zip in dist..." Compress-Archive -Path $appDir -DestinationPath $zipPath -Force Write-Host "Package ready:" Write-Host $zipPath