Initial Super N2N desktop application
Build Windows Portable Package / portable (push) Has been cancelled
Build Windows Portable Package / portable (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
Super N2N Portable
|
||||
|
||||
Run super-n2n.exe to open the desktop control plane.
|
||||
|
||||
The directory includes n2n\edge.exe and n2n\supernode.exe. The application starts
|
||||
them as .\n2n\edge.exe and .\n2n\supernode.exe, so no PATH configuration is required.
|
||||
|
||||
Windows WebView2 is required. It is included by default on current Windows 10 and
|
||||
Windows 11 installations.
|
||||
|
||||
The bundled n2n programs are distributed under n2n\LICENSE-n2n.txt.
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
n2n_root="${1:?n2n source path is required}"
|
||||
make_bin="${2:?MinGW make path is required}"
|
||||
clean="${3:-0}"
|
||||
|
||||
cd "$n2n_root"
|
||||
if [[ ! -f config.mak || ! -f include/config.h ]]; then
|
||||
./scripts/hack_fakeautoconf.sh
|
||||
fi
|
||||
|
||||
if [[ "$clean" == "1" ]]; then
|
||||
"$make_bin" clean
|
||||
fi
|
||||
|
||||
"$make_bin" edge supernode
|
||||
@@ -0,0 +1,150 @@
|
||||
[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
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
param(
|
||||
[switch]$Clean
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$projectRoot = Split-Path -Parent $PSScriptRoot
|
||||
$n2nRoot = Join-Path $projectRoot 'third_party\n2n'
|
||||
$releaseRoot = Join-Path $projectRoot 'release'
|
||||
$portableRoot = Join-Path $projectRoot 'release\super-n2n-portable'
|
||||
$stagingRoot = Join-Path $releaseRoot 'super-n2n-portable-staging'
|
||||
$archivePath = Join-Path $releaseRoot 'super-n2n-portable.zip'
|
||||
$releaseRootFull = [System.IO.Path]::GetFullPath($releaseRoot)
|
||||
$portableRootFull = [System.IO.Path]::GetFullPath($portableRoot)
|
||||
$stagingRootFull = [System.IO.Path]::GetFullPath($stagingRoot)
|
||||
$archivePathFull = [System.IO.Path]::GetFullPath($archivePath)
|
||||
|
||||
if ((Split-Path -Parent $portableRootFull) -ne $releaseRootFull -or (Split-Path -Leaf $portableRootFull) -ne 'super-n2n-portable') {
|
||||
throw "Refusing to replace an unexpected portable output directory: $portableRootFull"
|
||||
}
|
||||
if ((Split-Path -Parent $stagingRootFull) -ne $releaseRootFull -or (Split-Path -Leaf $stagingRootFull) -ne 'super-n2n-portable-staging') {
|
||||
throw "Refusing to replace an unexpected staging directory: $stagingRootFull"
|
||||
}
|
||||
if ((Split-Path -Parent $archivePathFull) -ne $releaseRootFull -or (Split-Path -Leaf $archivePathFull) -ne 'super-n2n-portable.zip') {
|
||||
throw "Refusing to replace an unexpected portable archive: $archivePathFull"
|
||||
}
|
||||
|
||||
if ($Clean) {
|
||||
if (Test-Path -LiteralPath $portableRoot) {
|
||||
Remove-Item -LiteralPath $portableRoot -Recurse -Force
|
||||
}
|
||||
if (Test-Path -LiteralPath $archivePath) {
|
||||
Remove-Item -LiteralPath $archivePath -Force
|
||||
}
|
||||
}
|
||||
|
||||
Push-Location $projectRoot
|
||||
try {
|
||||
& npm.cmd run tauri:portable:raw
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
exit $LASTEXITCODE
|
||||
}
|
||||
|
||||
$files = @{
|
||||
'super-n2n.exe' = Join-Path $projectRoot 'src-tauri\target\release\super-n2n.exe'
|
||||
'n2n\edge.exe' = Join-Path $n2nRoot 'edge.exe'
|
||||
'n2n\supernode.exe' = Join-Path $n2nRoot 'supernode.exe'
|
||||
'n2n\LICENSE-n2n.txt' = Join-Path $n2nRoot 'LICENSE'
|
||||
'README.txt' = Join-Path $projectRoot 'scripts\PORTABLE-README.txt'
|
||||
}
|
||||
|
||||
foreach ($entry in $files.GetEnumerator()) {
|
||||
if (-not (Test-Path -LiteralPath $entry.Value)) {
|
||||
throw "Required portable artifact is missing: $($entry.Value)"
|
||||
}
|
||||
}
|
||||
|
||||
if (Test-Path -LiteralPath $stagingRoot) {
|
||||
Remove-Item -LiteralPath $stagingRoot -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Force -Path $stagingRoot | Out-Null
|
||||
foreach ($entry in $files.GetEnumerator()) {
|
||||
$destination = Join-Path $stagingRoot $entry.Key
|
||||
$destinationDirectory = Split-Path -Parent $destination
|
||||
New-Item -ItemType Directory -Force -Path $destinationDirectory | Out-Null
|
||||
Copy-Item -LiteralPath $entry.Value -Destination $destination -Force
|
||||
}
|
||||
|
||||
Compress-Archive -Path (Join-Path $stagingRoot '*') -DestinationPath $archivePath -CompressionLevel Optimal -Force
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $portableRoot | Out-Null
|
||||
foreach ($legacyName in @('edge.exe', 'supernode.exe', 'LICENSE-n2n.txt')) {
|
||||
$legacyPath = Join-Path $portableRoot $legacyName
|
||||
if (Test-Path -LiteralPath $legacyPath) {
|
||||
try {
|
||||
Remove-Item -LiteralPath $legacyPath -Force
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Could not remove legacy artifact $legacyPath because it is in use."
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($entry in $files.GetEnumerator()) {
|
||||
$destination = Join-Path $portableRoot $entry.Key
|
||||
$destinationDirectory = Split-Path -Parent $destination
|
||||
New-Item -ItemType Directory -Force -Path $destinationDirectory | Out-Null
|
||||
try {
|
||||
Copy-Item -LiteralPath $entry.Value -Destination $destination -Force
|
||||
}
|
||||
catch {
|
||||
Write-Warning "Could not update $destination because it is in use. The zip archive is current."
|
||||
}
|
||||
}
|
||||
|
||||
Write-Output "Portable package created: $archivePath"
|
||||
}
|
||||
finally {
|
||||
if (Test-Path -LiteralPath $stagingRoot) {
|
||||
Remove-Item -LiteralPath $stagingRoot -Recurse -Force
|
||||
}
|
||||
Pop-Location
|
||||
}
|
||||
Reference in New Issue
Block a user