166 lines
10 KiB
PowerShell
166 lines
10 KiB
PowerShell
# Builds dist\Igneum-Miner-Setup-<version>.exe on a Windows PC (started by BUILD-INSTALLER.bat, or run directly).
|
|
# 1. Finds ISCC.exe (Inno Setup 6.3 or newer); installs Inno Setup 6 through winget when it is missing.
|
|
# 2. Finds the art (brand\icons in the repo layout, or an art\ folder next to this script).
|
|
# 3. Finds the payload: the extracted igneum-windows-app folder (igneum-app.exe, igneumd.exe, igneum-miner.exe, made by
|
|
# make-payload.sh on the Mac) next to this script, in the parent folder, or given with -Payload; otherwise the zip at
|
|
# -PayloadUrl is downloaded. "Igneum Miner.exe" (app\windows\BUILD-APP.bat) is shipped when it is in the payload.
|
|
# 4. Copies the payload into build\payload without logs, packs and per-PC worker builds.
|
|
# 5. Stamps the coin icon and the version block into igneum-app.exe, igneumd.exe and igneum-miner.exe with rcedit when
|
|
# the exes do not carry them yet (the Mac relink with packaging\windows\embed-resources.sh --relink makes this a no-op).
|
|
# 6. Compiles Igneum-Miner.iss and prints where the installer is.
|
|
#
|
|
# build-installer.ps1 [-Payload <folder>] [-PayloadUrl <zip url>] [-Version 0.3.0] [-NoRcedit] [-NoWinget]
|
|
param(
|
|
[string]$Payload = '',
|
|
[string]$PayloadUrl = $(if ($env:IGNEUM_PAYLOAD_URL) { $env:IGNEUM_PAYLOAD_URL } else { 'https://dl.igneum.network/igneum-windows-app.zip' }),
|
|
[string]$Version = '0.3.0',
|
|
[switch]$NoRcedit,
|
|
[switch]$NoWinget
|
|
)
|
|
$ErrorActionPreference = 'Stop'
|
|
$ProgressPreference = 'SilentlyContinue'
|
|
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
|
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$build = Join-Path $here 'build'
|
|
$dist = Join-Path $here 'dist'
|
|
$rceditUrl = 'https://github.com/electron/rcedit/releases/download/v2.0.0/rcedit-x64.exe'
|
|
New-Item -ItemType Directory -Force -Path $build, $dist | Out-Null
|
|
|
|
function Say([string]$text) { Write-Host ('[build] ' + $text) }
|
|
|
|
function Find-Iscc {
|
|
$candidates = @()
|
|
foreach ($base in @(${env:ProgramFiles(x86)}, $env:ProgramFiles, (Join-Path $env:LOCALAPPDATA 'Programs'))) {
|
|
if ($base) { $candidates += (Join-Path $base 'Inno Setup 6\ISCC.exe') }
|
|
}
|
|
foreach ($key in @('HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Inno Setup 6_is1',
|
|
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Inno Setup 6_is1',
|
|
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Inno Setup 6_is1')) {
|
|
try {
|
|
$loc = (Get-ItemProperty -Path $key -ErrorAction Stop).InstallLocation
|
|
if ($loc) { $candidates += (Join-Path $loc 'ISCC.exe') }
|
|
} catch { }
|
|
}
|
|
foreach ($c in $candidates) { if ($c -and (Test-Path $c)) { return $c } }
|
|
return $null
|
|
}
|
|
|
|
# ---- 1. Inno Setup ----------------------------------------------------------------------------------------------------
|
|
$iscc = Find-Iscc
|
|
if (-not $iscc) {
|
|
if ($NoWinget) { throw 'Inno Setup 6 is not installed (and -NoWinget was given). Install it from https://jrsoftware.org/isdl.php and run again.' }
|
|
if (-not (Get-Command winget.exe -ErrorAction SilentlyContinue)) { throw 'Inno Setup 6 is not installed and winget is not available. Install Inno Setup 6 from https://jrsoftware.org/isdl.php and run again.' }
|
|
Say 'Inno Setup 6 is not installed; installing it through winget (a UAC prompt may appear)'
|
|
& winget.exe install --id JRSoftware.InnoSetup --exact --silent --accept-package-agreements --accept-source-agreements
|
|
$iscc = Find-Iscc
|
|
if (-not $iscc) { throw 'winget finished but ISCC.exe was not found. Install Inno Setup 6 from https://jrsoftware.org/isdl.php and run again.' }
|
|
}
|
|
$isccVersion = (Get-Item $iscc).VersionInfo.FileVersion
|
|
Say "Inno Setup $isccVersion at $iscc"
|
|
$v = [Version]($isccVersion -replace '[^0-9.].*$', '')
|
|
if ($v -lt [Version]'6.3.0') { throw "Inno Setup $isccVersion is too old; 6.3 or newer is needed (winget upgrade --id JRSoftware.InnoSetup)." }
|
|
|
|
# ---- 2. the art ------------------------------------------------------------------------------------------------------
|
|
$art = $null
|
|
foreach ($dir in @((Join-Path $here '..\..\brand\icons'), (Join-Path $here 'art'))) {
|
|
if (Test-Path (Join-Path $dir 'igneum.ico')) { $art = (Resolve-Path $dir).Path; break }
|
|
}
|
|
if (-not $art) { throw "No art folder: expected brand\icons two levels up (the repo layout) or an art\ folder next to this script with igneum.ico, inno-wizard-164x314.bmp and inno-wizard-small-55x58.bmp (made by brand\icons\make-icons.py)." }
|
|
foreach ($f in @('igneum.ico', 'inno-wizard-164x314.bmp', 'inno-wizard-small-55x58.bmp')) {
|
|
if (-not (Test-Path (Join-Path $art $f))) { throw "missing $f in $art" }
|
|
}
|
|
Say "art: $art"
|
|
|
|
# ---- 3. the payload --------------------------------------------------------------------------------------------------
|
|
function Test-PayloadDir([string]$dir) {
|
|
if (-not $dir -or -not (Test-Path $dir)) { return $false }
|
|
foreach ($f in @('igneum-app.exe', 'stop-igneum.ps1', 'igneumd.exe', 'igneum-miner.exe')) {
|
|
if (-not (Test-Path (Join-Path $dir $f))) { return $false }
|
|
}
|
|
return $true
|
|
}
|
|
$source = $null
|
|
if ($Payload) {
|
|
if (-not (Test-PayloadDir $Payload)) { throw "-Payload $Payload does not hold START-IGNEUM.bat, the .ps1 files and both exes." }
|
|
$source = (Resolve-Path $Payload).Path
|
|
} else {
|
|
foreach ($dir in @((Join-Path $here 'igneum-windows-app'), (Join-Path $here '..\igneum-windows-app'), (Join-Path $here 'payload'), (Join-Path $here '..\..\igneum-windows-app'))) {
|
|
if (Test-PayloadDir $dir) { $source = (Resolve-Path $dir).Path; break }
|
|
}
|
|
}
|
|
if (-not $source) {
|
|
$zip = Join-Path $build 'igneum-windows.zip'
|
|
$unpacked = Join-Path $build 'payload-src'
|
|
Say "no igneum-windows folder next to this script; downloading $PayloadUrl"
|
|
Invoke-WebRequest -Uri $PayloadUrl -OutFile $zip -UseBasicParsing
|
|
if (Test-Path $unpacked) { Remove-Item -Recurse -Force $unpacked }
|
|
Expand-Archive -Path $zip -DestinationPath $unpacked -Force
|
|
$hit = Get-ChildItem -Path $unpacked -Recurse -Filter 'igneum-app.exe' | Select-Object -First 1
|
|
if (-not $hit -or -not (Test-PayloadDir $hit.DirectoryName)) { throw "the zip from $PayloadUrl holds no complete payload (igneum-app.exe, igneumd.exe, igneum-miner.exe, stop-igneum.ps1)." }
|
|
$source = $hit.DirectoryName
|
|
}
|
|
Say "payload source: $source"
|
|
|
|
# ---- 4. assemble build\payload ---------------------------------------------------------------------------------------
|
|
$payloadDir = Join-Path $build 'payload'
|
|
if (Test-Path $payloadDir) { Remove-Item -Recurse -Force $payloadDir }
|
|
New-Item -ItemType Directory -Force -Path $payloadDir | Out-Null
|
|
$skipNames = @('.DS_Store')
|
|
Get-ChildItem -Path $source -Recurse -Force | ForEach-Object {
|
|
$rel = $_.FullName.Substring($source.Length).TrimStart('\')
|
|
if ($rel -match '(^|\\)packs(\\|$)') { return }
|
|
if ($rel -match '\.(log|seeds)$') { return }
|
|
if ($rel -match '^proto-(cuda|opencl)\\[^\\]+\.exe$') { return } # GPU workers built per PC by the fallback path
|
|
if ($rel -match '^app\\windows\\(build|dist)(\\|$)') { return } # BUILD-APP.bat's intermediate files
|
|
if ($skipNames -contains $_.Name) { return }
|
|
$dest = Join-Path $payloadDir $rel
|
|
if ($_.PSIsContainer) { New-Item -ItemType Directory -Force -Path $dest | Out-Null }
|
|
else {
|
|
New-Item -ItemType Directory -Force -Path (Split-Path -Parent $dest) | Out-Null
|
|
Copy-Item -Path $_.FullName -Destination $dest -Force
|
|
}
|
|
}
|
|
$count = (Get-ChildItem -Path $payloadDir -Recurse -File | Measure-Object).Count
|
|
$bytes = (Get-ChildItem -Path $payloadDir -Recurse -File | Measure-Object -Property Length -Sum).Sum
|
|
Say ("payload: {0} files, {1:N1} MB" -f $count, ($bytes / 1MB))
|
|
|
|
# ---- 5. icon and version block in the exes ---------------------------------------------------------------------------
|
|
$rcedit = $null
|
|
foreach ($exeName in @('igneum-app.exe', 'igneumd.exe', 'igneum-miner.exe')) {
|
|
$exe = Join-Path $payloadDir $exeName
|
|
if (-not (Test-Path $exe)) { continue }
|
|
$info = (Get-Item $exe).VersionInfo
|
|
if ($info.ProductName -eq 'Igneum Miner') { Say "$exeName already carries the Igneum Miner version block (relinked on the Mac)"; continue }
|
|
if ($NoRcedit) { Say "$exeName has no version block; -NoRcedit given, so Explorer shows it without the coin icon"; continue }
|
|
if (-not $rcedit) {
|
|
if ($env:RCEDIT -and (Test-Path $env:RCEDIT)) { $rcedit = $env:RCEDIT }
|
|
else {
|
|
$rcedit = Join-Path $build 'rcedit-x64.exe'
|
|
if (-not (Test-Path $rcedit)) { Say "downloading rcedit from $rceditUrl"; Invoke-WebRequest -Uri $rceditUrl -OutFile $rcedit -UseBasicParsing }
|
|
}
|
|
}
|
|
$desc = switch ($exeName) { 'igneumd.exe' { 'Igneum Miner node' } 'igneum-app.exe' { 'Igneum Miner engine' } default { 'Igneum Miner' } }
|
|
$rcArgs = @($exe, '--set-icon', (Join-Path $art 'igneum.ico'),
|
|
'--set-version-string', 'CompanyName', 'Igneum',
|
|
'--set-version-string', 'ProductName', 'Igneum Miner',
|
|
'--set-version-string', 'FileDescription', $desc,
|
|
'--set-version-string', 'OriginalFilename', $exeName,
|
|
'--set-version-string', 'LegalCopyright', 'Igneum. Nothing is bought or sold.',
|
|
'--set-file-version', $Version,
|
|
'--set-product-version', $Version)
|
|
& $rcedit @rcArgs
|
|
if ($LASTEXITCODE -ne 0) { throw "rcedit failed on $exeName (exit $LASTEXITCODE)" }
|
|
Say "$exeName stamped: coin icon, Igneum Miner $Version"
|
|
}
|
|
|
|
# ---- 6. compile ------------------------------------------------------------------------------------------------------
|
|
$iss = Join-Path $here 'Igneum-Miner.iss'
|
|
$isccArgs = @('/Qp', "/DPayload=$payloadDir", "/DArtDir=$art", "/DAppVersion=$Version", "/O$dist", $iss)
|
|
Say "compiling $iss"
|
|
& $iscc @isccArgs
|
|
if ($LASTEXITCODE -ne 0) { throw "ISCC failed (exit $LASTEXITCODE)" }
|
|
$out = Join-Path $dist "Igneum-Miner-Setup-$Version.exe"
|
|
if (-not (Test-Path $out)) { throw "ISCC finished but $out is missing" }
|
|
$size = (Get-Item $out).Length
|
|
Say ("done: {0} ({1:N1} MB)" -f $out, ($size / 1MB))
|
|
Say 'The installer is unsigned until Igneum has a code-signing certificate: SmartScreen shows "Windows protected your PC" (More info > Run anyway).'
|