/** * Downloads winCodeSign-2.6.0.7z and extracts it WITHOUT symlinks * into the electron-builder cache, so electron-builder doesn't re-download. * * Run once: node scripts/fix-wincodeSign.js */ 'use strict' const https = require('https') const http = require('http') const fs = require('fs') const path = require('path') const os = require('os') const { execFileSync } = require('child_process') const VERSION = 'winCodeSign-2.6.0' const URL_7Z = `https://github.com/electron-userland/electron-builder-binaries/releases/download/${VERSION}/${VERSION}.7z` const CACHE = path.join(os.homedir(), 'AppData', 'Local', 'electron-builder', 'Cache', 'winCodeSign', VERSION) const TMP_7Z = path.join(os.tmpdir(), `${VERSION}.7z`) const SEVEN_ZIP = path.join(__dirname, '..', 'node_modules', '7zip-bin', 'win', 'x64', '7za.exe') function download(url, dest, redirects = 0) { return new Promise((resolve, reject) => { if (redirects > 5) return reject(new Error('Too many redirects')) console.log(`Downloading${redirects > 0 ? ' (redirect)' : ''}: ${url}`) const proto = url.startsWith('https') ? https : http const req = proto.get(url, { headers: { 'User-Agent': 'node' } }, res => { if (res.statusCode === 301 || res.statusCode === 302 || res.statusCode === 307 || res.statusCode === 308) { return download(res.headers.location, dest, redirects + 1).then(resolve).catch(reject) } if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`)) const total = parseInt(res.headers['content-length'] || '0', 10) let received = 0 const out = fs.createWriteStream(dest) res.on('data', chunk => { received += chunk.length if (total > 0) { const pct = Math.round(received / total * 100) process.stdout.write(`\r ${pct}% (${(received/1024/1024).toFixed(1)} MB) `) } }) res.pipe(out) out.on('finish', () => { process.stdout.write('\n'); resolve() }) out.on('error', reject) }) req.on('error', reject) }) } async function main() { // Already extracted? const nsisBin = path.join(CACHE, 'windows', 'nsis', 'Bin', 'makensis.exe') if (fs.existsSync(nsisBin)) { console.log('✓ winCodeSign already cached at:', CACHE) return } console.log('=== Fixing winCodeSign cache ===') console.log('Cache target:', CACHE) // Download if (!fs.existsSync(TMP_7Z)) { await download(URL_7Z, TMP_7Z) } else { console.log('Using cached download:', TMP_7Z) } // Extract — ignoring exit code 1 or 2 (only symlinks fail, all real binaries extract fine) fs.mkdirSync(CACHE, { recursive: true }) console.log('Extracting…') try { execFileSync(SEVEN_ZIP, ['x', '-y', '-bd', TMP_7Z, `-o${CACHE}`], { stdio: ['ignore', 'pipe', 'pipe'] }) } catch (e) { // Exit code 1 = warnings, exit code 2 = fatal but only for macOS symlinks — safe to ignore if (e.status !== 1 && e.status !== 2) throw e console.log(' (macOS symlinks skipped — expected on Windows, continuing…)') } // Create placeholder empty files for the macOS symlinks that 7-Zip can't create const macSymlinks = [ 'darwin/10.12/lib/libcrypto.dylib', 'darwin/10.12/lib/libssl.dylib', ] for (const rel of macSymlinks) { const full = path.join(CACHE, rel) if (!fs.existsSync(full)) { fs.mkdirSync(path.dirname(full), { recursive: true }) fs.writeFileSync(full, '') console.log(' Created placeholder:', rel) } } // Verify NSIS was extracted if (fs.existsSync(nsisBin)) { console.log('✓ NSIS extracted successfully:', nsisBin) } else { // List what we got console.log('Contents of cache:') const list = fs.readdirSync(CACHE) list.forEach(f => console.log(' ', f)) } console.log('Done! Run npm run build:win again.') } main().catch(e => { console.error('ERROR:', e.message); process.exit(1) })