95 lines
3.6 KiB
JavaScript
95 lines
3.6 KiB
JavaScript
'use strict';
|
||
|
||
/*
|
||
* build-setup.js – eigenes Setup (installer/) mit der App zusammenbauen
|
||
* ---------------------------------------------------------------------
|
||
* Läuft nach "electron-builder --win dir" (siehe "build" in package.json):
|
||
*
|
||
* 1. dist/win-unpacked (die fertige App) als ZIP packen
|
||
* 2. installer/ (WPF, .NET Framework 4.8) mit der Version aus package.json bauen
|
||
* 3. ZIP hinten an die Setup-.exe hängen:
|
||
* [Setup.exe][ZIP][8 Byte ZIP-Länge][8 Byte "AEROMCPK"]
|
||
* (das Setup liest den Anhang selbst aus, siehe installer/Payload.cs)
|
||
* 4. Zwischenstände wegräumen → übrig bleibt dist/AeroMC-Setup.exe
|
||
*
|
||
* Benötigt das .NET SDK (dotnet) – das Setup selbst läuft danach auf jedem
|
||
* Windows 10/11 ohne Zusatzinstallation.
|
||
*/
|
||
|
||
const fs = require('fs');
|
||
const path = require('path');
|
||
const { execFileSync } = require('child_process');
|
||
|
||
const ROOT = path.join(__dirname, '..');
|
||
const DIST = path.join(ROOT, 'dist');
|
||
const APP_DIR = path.join(DIST, 'win-unpacked');
|
||
const WORK = path.join(DIST, '.setup');
|
||
const ZIP = path.join(WORK, 'app.zip');
|
||
const OUT = path.join(DIST, 'AeroMC-Setup.exe');
|
||
const MAGIC = Buffer.from('AEROMCPK', 'ascii');
|
||
|
||
function schritt(text) {
|
||
console.log(`\n» ${text}`);
|
||
}
|
||
|
||
function main() {
|
||
const version = require(path.join(ROOT, 'package.json')).version;
|
||
if (!fs.existsSync(path.join(APP_DIR, 'AeroMC.exe'))) {
|
||
throw new Error(`${APP_DIR}\\AeroMC.exe fehlt – vorher "electron-builder --win dir" ausführen.`);
|
||
}
|
||
fs.rmSync(WORK, { recursive: true, force: true });
|
||
fs.mkdirSync(WORK, { recursive: true });
|
||
|
||
schritt('App wird gepackt …');
|
||
// .NET-ZIP über PowerShell: in jedem Windows enthalten, keine zusätzliche npm-Abhängigkeit
|
||
const ps = [
|
||
'Add-Type -AssemblyName System.IO.Compression.FileSystem',
|
||
`[System.IO.Compression.ZipFile]::CreateFromDirectory('${APP_DIR.replace(/'/g, "''")}', '${ZIP.replace(/'/g, "''")}', [System.IO.Compression.CompressionLevel]::Optimal, $false)`,
|
||
].join('; ');
|
||
execFileSync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', ps], { stdio: 'inherit' });
|
||
|
||
schritt(`Setup ${version} wird gebaut …`);
|
||
const stubDir = path.join(WORK, 'stub');
|
||
execFileSync('dotnet', [
|
||
'build', path.join(ROOT, 'installer', 'AeroMCSetup.csproj'),
|
||
'-c', 'Release', `-p:Version=${version}`, '-p:DebugType=none',
|
||
'--nologo', '-v', 'q', '-o', stubDir,
|
||
], { stdio: 'inherit' });
|
||
const stub = path.join(stubDir, 'AeroMC-Setup.exe');
|
||
if (!fs.existsSync(stub)) throw new Error('Build des Setups fehlgeschlagen.');
|
||
|
||
schritt('App wird ans Setup angehängt …');
|
||
const zipSize = fs.statSync(ZIP).size;
|
||
const footer = Buffer.alloc(16);
|
||
footer.writeBigInt64LE(BigInt(zipSize), 0);
|
||
MAGIC.copy(footer, 8);
|
||
fs.rmSync(OUT, { force: true });
|
||
fs.copyFileSync(stub, OUT);
|
||
// ZIP in Blöcken anhängen statt komplett in den Speicher zu laden
|
||
const fd = fs.openSync(OUT, 'a');
|
||
try {
|
||
const src = fs.openSync(ZIP, 'r');
|
||
try {
|
||
const buf = Buffer.alloc(8 * 1024 * 1024);
|
||
let n;
|
||
while ((n = fs.readSync(src, buf, 0, buf.length, null)) > 0) fs.writeSync(fd, buf, 0, n);
|
||
} finally { fs.closeSync(src); }
|
||
fs.writeSync(fd, footer);
|
||
} finally { fs.closeSync(fd); }
|
||
|
||
schritt('Aufräumen …');
|
||
for (const t of [WORK, APP_DIR, path.join(DIST, 'builder-debug.yml'), path.join(DIST, 'builder-effective-config.yaml')]) {
|
||
fs.rmSync(t, { recursive: true, force: true });
|
||
}
|
||
|
||
const mb = (fs.statSync(OUT).size / 1024 / 1024).toFixed(1);
|
||
console.log(`\nFertig: ${OUT} (${mb} MB)`);
|
||
}
|
||
|
||
try {
|
||
main();
|
||
} catch (err) {
|
||
console.error(`\nFehler: ${err.message}`);
|
||
process.exit(1);
|
||
}
|