'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 inkl. eingebautem Git) 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 "GITMGRPK"] * (das Setup liest den Anhang selbst aus, siehe installer/Payload.cs) * 4. SHA-256-Prüfsumme daneben schreiben (der Updater der App prüft sie) * 5. Zwischenstände wegräumen → übrig bleibt dist/Git-Manager-GUI-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 crypto = require('crypto'); 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 APP_EXE = 'Git Manager GUI.exe'; const WORK = path.join(DIST, '.setup'); const ZIP = path.join(WORK, 'app.zip'); const MAGIC = Buffer.from('GITMGRPK', 'ascii'); function schritt(text) { console.log(`\n» ${text}`); } function sha256(file) { const hash = crypto.createHash('sha256'); const fd = fs.openSync(file, 'r'); try { const buf = Buffer.alloc(8 * 1024 * 1024); let n; while ((n = fs.readSync(fd, buf, 0, buf.length, null)) > 0) hash.update(buf.subarray(0, n)); } finally { fs.closeSync(fd); } return hash.digest('hex'); } function main() { const version = require(path.join(ROOT, 'package.json')).version; const outName = `Git-Manager-GUI-Setup-${version}.exe`; const OUT = path.join(DIST, outName); if (!fs.existsSync(path.join(APP_DIR, APP_EXE))) { throw new Error(`${APP_DIR}\\${APP_EXE} fehlt – vorher "electron-builder --win dir" ausführen.`); } if (!fs.existsSync(path.join(APP_DIR, 'resources', 'mingit', 'cmd', 'git.exe'))) { throw new Error('Eingebautes Git fehlt in resources/mingit – extraResources in package.json prüfen.'); } 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', 'GitManagerSetup.csproj'), '-c', 'Release', `-p:Version=${version}`, '-p:DebugType=none', '--nologo', '-v', 'q', '-o', stubDir, ], { stdio: 'inherit' }); const stub = path.join(stubDir, 'Git-Manager-GUI-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('Prüfsumme wird geschrieben …'); const sum = sha256(OUT); fs.writeFileSync(`${OUT}.sha256`, `${sum} ${outName}\n`); 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)\nSHA-256: ${sum}`); } try { main(); } catch (err) { console.error(`\nFehler: ${err.message}`); process.exit(1); }