76 lines
2.7 KiB
JavaScript
76 lines
2.7 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import fs from 'node:fs';
|
|
import path from 'node:path';
|
|
import { createRequire } from 'node:module';
|
|
|
|
const require = createRequire(import.meta.url);
|
|
const targetFile = require.resolve('app-builder-lib/out/targets/nsis/NsisTarget.js');
|
|
const patchMarker = 'zn-ai patch: retry NSIS stub execution on Windows';
|
|
|
|
const helperSnippet = `
|
|
// ${patchMarker}
|
|
function isRetryableWindowsSpawnError(error) {
|
|
const code = error != null && typeof error.code === "string" ? error.code : "";
|
|
const message = error != null && typeof error.message === "string" ? error.message : "";
|
|
return (code === "EPERM" ||
|
|
code === "EACCES" ||
|
|
message.includes("spawn EPERM") ||
|
|
message.includes("spawn EACCES") ||
|
|
message.includes("used by another process"));
|
|
}
|
|
async function execWineWithRetry(file, file64 = null, appArgs = [], options = {}) {
|
|
const maxAttempts = process.platform === "win32" ? 12 : 1;
|
|
let attempt = 0;
|
|
while (true) {
|
|
attempt++;
|
|
try {
|
|
return await (0, wine_1.execWine)(file, file64, appArgs, options);
|
|
}
|
|
catch (error) {
|
|
const shouldRetry = process.platform === "win32" &&
|
|
attempt < maxAttempts &&
|
|
isRetryableWindowsSpawnError(error);
|
|
if (!shouldRetry) {
|
|
throw error;
|
|
}
|
|
builder_util_1.log.warn({
|
|
attempt,
|
|
maxAttempts,
|
|
file,
|
|
reason: error.message || String(error),
|
|
}, "retrying NSIS stub execution after transient Windows spawn failure");
|
|
await new Promise(resolve => setTimeout(resolve, attempt * 1000));
|
|
}
|
|
}
|
|
}
|
|
`;
|
|
|
|
const originalCall = 'await (0, wine_1.execWine)(installerPath, null, [], { env: { __COMPAT_LAYER: "RunAsInvoker" } });';
|
|
const patchedCall = 'await execWineWithRetry(installerPath, null, [], { env: { __COMPAT_LAYER: "RunAsInvoker" } });';
|
|
|
|
const source = fs.readFileSync(targetFile, 'utf8');
|
|
|
|
if (source.includes(patchMarker)) {
|
|
console.log(`[patch-electron-builder-nsis] already patched: ${targetFile}`);
|
|
process.exit(0);
|
|
}
|
|
|
|
if (!source.includes(originalCall)) {
|
|
console.error(`[patch-electron-builder-nsis] target call not found in ${targetFile}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const classToken = 'class NsisTarget extends core_1.Target {';
|
|
if (!source.includes(classToken)) {
|
|
console.error(`[patch-electron-builder-nsis] class token not found in ${targetFile}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const patchedSource = source
|
|
.replace(classToken, `${helperSnippet}\n${classToken}`)
|
|
.replace(originalCall, patchedCall);
|
|
|
|
fs.writeFileSync(targetFile, patchedSource, 'utf8');
|
|
console.log(`[patch-electron-builder-nsis] patched ${targetFile}`);
|