151 lines
5.0 KiB
PowerShell
151 lines
5.0 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[switch]$Clean,
|
|
[switch]$SkipTests
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$PSNativeCommandUseErrorActionPreference = $true
|
|
|
|
$projectRoot = Split-Path -Parent $PSScriptRoot
|
|
$n2nRoot = Join-Path $projectRoot 'third_party\n2n'
|
|
$cargoManifest = Join-Path $projectRoot 'src-tauri\Cargo.toml'
|
|
$packageScript = Join-Path $PSScriptRoot 'package-portable.ps1'
|
|
$n2nBuildScript = Join-Path $PSScriptRoot 'build-n2n.sh'
|
|
$archivePath = Join-Path $projectRoot 'release\super-n2n-portable.zip'
|
|
$checksumPath = $archivePath + '.sha256'
|
|
|
|
function Get-RequiredCommand {
|
|
param(
|
|
[string[]]$Names,
|
|
[string]$Purpose
|
|
)
|
|
|
|
foreach ($name in $Names) {
|
|
$command = Get-Command $name -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if ($command) {
|
|
return $command.Source
|
|
}
|
|
}
|
|
|
|
throw "Missing required tool for $Purpose. Expected one of: $($Names -join ', ')."
|
|
}
|
|
|
|
function Get-GitBash {
|
|
param([string]$GitExecutable)
|
|
|
|
$gitRoot = Split-Path -Parent (Split-Path -Parent $GitExecutable)
|
|
$candidatePaths = @(
|
|
(Join-Path $gitRoot 'bin\bash.exe')
|
|
)
|
|
$candidatePaths += Get-Command bash.exe -CommandType Application -All -ErrorAction SilentlyContinue | ForEach-Object Source
|
|
|
|
foreach ($bashPath in $candidatePaths | Select-Object -Unique) {
|
|
if (-not (Test-Path -LiteralPath $bashPath)) {
|
|
continue
|
|
}
|
|
$bashDirectory = Split-Path -Parent $bashPath
|
|
$gitUnixBinCandidates = @(
|
|
$bashDirectory,
|
|
(Join-Path (Split-Path -Parent $bashDirectory) 'usr\bin')
|
|
)
|
|
foreach ($gitUnixBin in $gitUnixBinCandidates) {
|
|
if ((Test-Path -LiteralPath (Join-Path $gitUnixBin 'sh.exe')) -and
|
|
(Test-Path -LiteralPath (Join-Path $gitUnixBin 'cygpath.exe'))) {
|
|
return [pscustomobject]@{
|
|
Bash = $bashPath
|
|
UnixBin = $gitUnixBin
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
throw 'Git Bash was not found. Install Git for Windows.'
|
|
}
|
|
|
|
function Invoke-Checked {
|
|
param(
|
|
[string]$Executable,
|
|
[string[]]$Arguments
|
|
)
|
|
|
|
& $Executable @Arguments
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Command failed with exit code ${LASTEXITCODE}: $Executable $($Arguments -join ' ')"
|
|
}
|
|
}
|
|
|
|
if ($env:OS -ne 'Windows_NT') {
|
|
throw 'This script builds the Windows portable package and must run on Windows.'
|
|
}
|
|
|
|
$git = Get-RequiredCommand -Names @('git.exe', 'git') -Purpose 'source checkout'
|
|
$npm = Get-RequiredCommand -Names @('npm.cmd', 'npm') -Purpose 'frontend dependency installation'
|
|
$cargo = Get-RequiredCommand -Names @('cargo.exe', 'cargo') -Purpose 'Tauri compilation'
|
|
$gitBash = Get-GitBash -GitExecutable $git
|
|
$make = Get-RequiredCommand -Names @('mingw32-make.exe', 'mingw32-make') -Purpose 'n2n compilation'
|
|
$null = Get-RequiredCommand -Names @('gcc.exe', 'gcc') -Purpose 'n2n compilation'
|
|
$null = Get-RequiredCommand -Names @('windres.exe', 'windres') -Purpose 'n2n Windows resource compilation'
|
|
|
|
# Make GNU utilities (rm, cp, gzip) available to n2n's Makefile on Windows.
|
|
$env:Path = "$($gitBash.UnixBin);$env:Path"
|
|
$env:SHELL = Join-Path $gitBash.UnixBin 'sh.exe'
|
|
|
|
Push-Location $projectRoot
|
|
try {
|
|
Invoke-Checked $git @('submodule', 'sync')
|
|
Invoke-Checked $git @('submodule', 'update', '--init')
|
|
|
|
if (-not (Test-Path -LiteralPath $n2nRoot)) {
|
|
throw "The n2n submodule was not initialized: $n2nRoot"
|
|
}
|
|
|
|
$cygpath = Join-Path $gitBash.UnixBin 'cygpath.exe'
|
|
$n2nRootUnix = (& $cygpath -u $n2nRoot).Trim()
|
|
$makeUnix = (& $cygpath -u $make).Trim()
|
|
$n2nBuildScriptUnix = (& $cygpath -u $n2nBuildScript).Trim()
|
|
Invoke-Checked $gitBash.Bash @($n2nBuildScriptUnix, $n2nRootUnix, $makeUnix, $(if ($Clean) { '1' } else { '0' }))
|
|
|
|
foreach ($binary in @('edge.exe', 'supernode.exe')) {
|
|
if (-not (Test-Path -LiteralPath (Join-Path $n2nRoot $binary))) {
|
|
throw "n2n build did not produce $binary."
|
|
}
|
|
}
|
|
|
|
Invoke-Checked $npm @('ci')
|
|
|
|
if (-not $SkipTests) {
|
|
Invoke-Checked $cargo @('test', '--manifest-path', $cargoManifest)
|
|
}
|
|
|
|
& $packageScript -Clean:$Clean
|
|
if ($LASTEXITCODE -ne 0) {
|
|
throw "Portable package script failed with exit code $LASTEXITCODE."
|
|
}
|
|
|
|
if (-not (Test-Path -LiteralPath $archivePath)) {
|
|
throw "Portable archive was not created: $archivePath"
|
|
}
|
|
|
|
$stream = [System.IO.File]::OpenRead($archivePath)
|
|
try {
|
|
$sha256 = [System.Security.Cryptography.SHA256]::Create()
|
|
try {
|
|
$hashBytes = $sha256.ComputeHash($stream)
|
|
$hash = -join ($hashBytes | ForEach-Object { $_.ToString('x2') })
|
|
}
|
|
finally {
|
|
$sha256.Dispose()
|
|
}
|
|
}
|
|
finally {
|
|
$stream.Dispose()
|
|
}
|
|
"$hash *$(Split-Path -Leaf $archivePath)" | Set-Content -LiteralPath $checksumPath -Encoding ascii
|
|
Write-Output "Build completed: $archivePath"
|
|
Write-Output "SHA-256 checksum: $checksumPath"
|
|
}
|
|
finally {
|
|
Pop-Location
|
|
}
|