update electron to v43

This commit is contained in:
olcxja 2026-07-09 22:38:33 +02:00
commit fb6c8b6ee9
5385 changed files with 513060 additions and 123058 deletions

View file

@ -1,35 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NsisTarget = void 0;
const _7zip_bin_1 = require("7zip-bin");
const bluebird_lst_1 = require("bluebird-lst");
const builder_util_1 = require("builder-util");
const builder_util_runtime_1 = require("builder-util-runtime");
const fs_1 = require("builder-util/out/fs");
const debug_1 = require("debug");
const fs = require("fs");
const fs_extra_1 = require("fs-extra");
const path = require("path");
const binDownload_1 = require("../../binDownload");
const core_1 = require("../../core");
const CommonWindowsInstallerConfiguration_1 = require("../../options/CommonWindowsInstallerConfiguration");
const platformPackager_1 = require("../../platformPackager");
const hash_1 = require("../../util/hash");
const macosVersion_1 = require("../../util/macosVersion");
const timer_1 = require("../../util/timer");
const wine_1 = require("../../wine");
const archive_1 = require("../archive");
const differentialUpdateInfoBuilder_1 = require("../differentialUpdateInfoBuilder");
const targetUtil_1 = require("../targetUtil");
const nsisLang_1 = require("./nsisLang");
const nsisLicense_1 = require("./nsisLicense");
const nsisScriptGenerator_1 = require("./nsisScriptGenerator");
const windows_1 = require("../../toolsets/windows");
const nsisUtil_1 = require("./nsisUtil");
const debug = debug_1.default("electron-builder:nsis");
const nsisValidation_1 = require("./nsisValidation");
const WineVm_1 = require("../../vm/WineVm");
const debug = (0, debug_1.default)("electron-builder:nsis");
// noinspection SpellCheckingInspection
const ELECTRON_BUILDER_NS_UUID = builder_util_runtime_1.UUID.parse("50e065bc-3134-11e6-9bab-38c9862bdaf3");
// noinspection SpellCheckingInspection
const nsisResourcePathPromise = () => binDownload_1.getBinFromUrl("nsis-resources", "3.4.1", "Dqd6g+2buwwvoG1Vyf6BHR1b+25QMmPcwZx40atOT57gH27rkjOei1L0JTldxZu4NFoEmW4kJgZ3DlSWVON3+Q==");
const USE_NSIS_BUILT_IN_COMPRESSOR = false;
class NsisTarget extends core_1.Target {
constructor(packager, outDir, targetName, packageHelper) {
@ -39,6 +35,7 @@ class NsisTarget extends core_1.Target {
this.packageHelper = packageHelper;
/** @private */
this.archs = new Map();
this.isAsyncSupported = false;
this.packageHelper.refCount++;
this.options =
targetName === "portable"
@ -48,16 +45,22 @@ class NsisTarget extends core_1.Target {
...this.packager.config.nsis,
};
if (targetName !== "nsis") {
Object.assign(this.options, this.packager.config[targetName === "nsis-web" ? "nsisWeb" : targetName]);
(0, builder_util_runtime_1.deepAssign)(this.options, this.packager.config[targetName === "nsis-web" ? "nsisWeb" : targetName]);
}
const deps = packager.info.metadata.dependencies;
if (deps != null && deps["electron-squirrel-startup"] != null) {
builder_util_1.log.warn('"electron-squirrel-startup" dependency is not required for NSIS');
}
nsisUtil_1.NsisTargetOptions.resolve(this.options);
}
get shouldBuildUniversalInstaller() {
const buildSeparateInstallers = this.options.buildUniversalInstaller === false;
return !buildSeparateInstallers;
}
build(appOutDir, arch) {
this.archs.set(arch, appOutDir);
if (!this.shouldBuildUniversalInstaller) {
return this.buildInstaller(new Map().set(arch, appOutDir));
}
return Promise.resolve();
}
get isBuildDifferentialAware() {
@ -65,7 +68,7 @@ class NsisTarget extends core_1.Target {
}
getPreCompressedFileExtensions() {
const result = this.isWebInstaller ? null : this.options.preCompressedFileExtensions;
return result == null ? null : builder_util_1.asArray(result).map(it => (it.startsWith(".") ? it : `.${it}`));
return result == null ? null : (0, builder_util_1.asArray)(result).map(it => (it.startsWith(".") ? it : `.${it}`));
}
/** @private */
async buildAppPackage(appOutDir, arch) {
@ -80,11 +83,11 @@ class NsisTarget extends core_1.Target {
compression: packager.compression,
excluded: preCompressedFileExtensions == null ? null : preCompressedFileExtensions.map(it => `*${it}`),
};
const timer = timer_1.time(`nsis package, ${builder_util_1.Arch[arch]}`);
await archive_1.archive(format, archiveFile, appOutDir, isBuildDifferentialAware ? differentialUpdateInfoBuilder_1.configureDifferentialAwareArchiveOptions(archiveOptions) : archiveOptions);
const timer = (0, timer_1.time)(`nsis package, ${builder_util_1.Arch[arch]}`);
await (0, archive_1.archive)(format, archiveFile, appOutDir, isBuildDifferentialAware ? (0, differentialUpdateInfoBuilder_1.configureDifferentialAwareArchiveOptions)(archiveOptions) : archiveOptions);
timer.end();
if (isBuildDifferentialAware && this.isWebInstaller) {
const data = await differentialUpdateInfoBuilder_1.appendBlockmap(archiveFile);
const data = await (0, differentialUpdateInfoBuilder_1.appendBlockmap)(archiveFile);
return {
...data,
path: archiveFile,
@ -94,16 +97,21 @@ class NsisTarget extends core_1.Target {
return await createPackageFileInfo(archiveFile);
}
}
get installerFilenamePattern() {
// tslint:disable:no-invalid-template-strings
return "${productName} " + (this.isPortable ? "" : "Setup ") + "${version}.${ext}";
installerFilenamePattern(primaryArch, defaultArch) {
const setupText = this.isPortable ? "" : "Setup ";
const archSuffix = !this.shouldBuildUniversalInstaller && primaryArch != null ? (0, builder_util_1.getArchSuffix)(primaryArch, defaultArch) : "";
return "${productName} " + setupText + "${version}" + archSuffix + ".${ext}";
}
get isPortable() {
return this.name === "portable";
}
async finishBuild() {
if (!this.shouldBuildUniversalInstaller) {
await super.finishBuild();
return this.packageHelper.finishBuild();
}
try {
const { pattern } = this.packager.artifactPatternConfig(this.options, this.installerFilenamePattern);
const { pattern } = this.packager.artifactPatternConfig(this.options, this.installerFilenamePattern());
const builds = new Set([this.archs]);
if (pattern.includes("${arch}") && this.archs.size > 1) {
;
@ -115,16 +123,18 @@ class NsisTarget extends core_1.Target {
}
}
finally {
await super.finishBuild();
await this.packageHelper.finishBuild();
}
}
async buildInstaller(archs) {
var _a;
const primaryArch = archs.size === 1 ? archs.keys().next().value : null;
var _a, _b, _c;
const primaryArch = archs.size === 1 ? ((_a = archs.keys().next().value) !== null && _a !== void 0 ? _a : null) : null;
const packager = this.packager;
const appInfo = packager.appInfo;
const options = this.options;
const installerFilename = packager.expandArtifactNamePattern(options, "exe", primaryArch, this.installerFilenamePattern, false, this.packager.platformSpecificBuildOptions.defaultArch);
const defaultArch = (_b = (0, platformPackager_1.chooseNotNull)(this.packager.platformSpecificBuildOptions.defaultArch, this.packager.config.defaultArch)) !== null && _b !== void 0 ? _b : undefined;
const installerFilename = packager.expandArtifactNamePattern(options, "exe", primaryArch, this.installerFilenamePattern(primaryArch, defaultArch), false, defaultArch);
const oneClick = options.oneClick !== false;
const installerPath = path.join(this.outDir, installerFilename);
const logFields = {
@ -139,7 +149,7 @@ class NsisTarget extends core_1.Target {
logFields.oneClick = oneClick;
logFields.perMachine = isPerMachine;
}
await packager.info.callArtifactBuildStarted({
await packager.info.emitArtifactBuildStarted({
targetPresentableName: this.name,
file: installerPath,
arch: primaryArch,
@ -153,19 +163,24 @@ class NsisTarget extends core_1.Target {
UNINSTALL_APP_KEY: uninstallAppKey,
PRODUCT_NAME: appInfo.productName,
PRODUCT_FILENAME: appInfo.productFilename,
APP_FILENAME: targetUtil_1.getWindowsInstallationDirName(appInfo, !oneClick || isPerMachine),
APP_FILENAME: (0, targetUtil_1.getWindowsInstallationDirName)(appInfo, !oneClick || isPerMachine),
APP_DESCRIPTION: appInfo.description,
VERSION: appInfo.version,
PROJECT_DIR: packager.projectDir,
BUILD_RESOURCES_DIR: packager.info.buildResourcesDir,
APP_PACKAGE_NAME: targetUtil_1.getWindowsInstallationAppPackageName(appInfo.name),
APP_PACKAGE_NAME: (0, targetUtil_1.getWindowsInstallationAppPackageName)(appInfo.name),
};
if ((_a = options.customNsisBinary) === null || _a === void 0 ? void 0 : _a.debugLogging) {
if ((_c = options.customNsisBinary) === null || _c === void 0 ? void 0 : _c.debugLogging) {
defines.ENABLE_LOGGING_ELECTRON_BUILDER = null;
}
if (uninstallAppKey !== guid) {
defines.UNINSTALL_REGISTRY_KEY_2 = `Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${guid}`;
}
const { homepage } = this.packager.info.metadata;
(0, builder_util_1.use)(options.uninstallUrlHelp || homepage, it => (defines.UNINSTALL_URL_HELP = it));
(0, builder_util_1.use)(options.uninstallUrlInfoAbout || homepage, it => (defines.UNINSTALL_URL_INFO_ABOUT = it));
(0, builder_util_1.use)(options.uninstallUrlUpdateInfo || homepage, it => (defines.UNINSTALL_URL_UPDATE_INFO = it));
(0, builder_util_1.use)(options.uninstallUrlReadme || homepage, it => (defines.UNINSTALL_URL_README = it));
const commands = {
OutFile: `"${installerPath}"`,
VIProductVersion: appInfo.getVersionInWeirdWindowsForm(),
@ -191,11 +206,12 @@ class NsisTarget extends core_1.Target {
}
}
else if (USE_NSIS_BUILT_IN_COMPRESSOR && archs.size === 1) {
defines.APP_BUILD_DIR = archs.get(archs.keys().next().value);
const value = archs.keys().next().value;
(0, builder_util_1.use)(value, v => (defines.APP_BUILD_DIR = archs.get(v)));
}
else {
await bluebird_lst_1.default.map(archs.keys(), async (arch) => {
const fileInfo = await this.packageHelper.packArch(arch, this);
await Promise.all(Array.from(archs.keys()).map(async (arch) => {
const { fileInfo, unpackedSize } = await this.packageHelper.packArch(arch, this);
const file = fileInfo.path;
const defineKey = arch === builder_util_1.Arch.x64 ? "APP_64" : arch === builder_util_1.Arch.arm64 ? "APP_ARM64" : "APP_32";
defines[defineKey] = file;
@ -206,20 +222,21 @@ class NsisTarget extends core_1.Target {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const defineHashKey = `${defineKey}_HASH`;
defines[defineHashKey] = Buffer.from(fileInfo.sha512, "base64").toString("hex").toUpperCase();
// NSIS accepts size in KiloBytes and supports only whole numbers
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const defineUnpackedSizeKey = `${defineKey}_UNPACKED_SIZE`;
defines[defineUnpackedSizeKey] = Math.ceil(unpackedSize / 1024).toString();
if (this.isWebInstaller) {
await packager.dispatchArtifactCreated(file, this, arch);
await packager.info.emitArtifactBuildCompleted({
file,
target: this,
arch,
packager,
});
packageFiles[builder_util_1.Arch[arch]] = fileInfo;
}
const archiveInfo = (await builder_util_1.exec(_7zip_bin_1.path7za, ["l", file])).trim();
// after adding blockmap data will be "Warnings: 1" in the end of output
const match = /(\d+)\s+\d+\s+\d+\s+files/.exec(archiveInfo);
if (match == null) {
builder_util_1.log.warn({ output: archiveInfo }, "cannot compute size of app package");
}
else {
estimatedSize += parseInt(match[1], 10);
}
});
estimatedSize += unpackedSize;
}));
}
this.configureDefinesForAllTypeOfInstaller(defines);
if (isPortable) {
@ -227,7 +244,7 @@ class NsisTarget extends core_1.Target {
defines.REQUEST_EXECUTION_LEVEL = requestExecutionLevel || "user";
// https://github.com/electron-userland/electron-builder/issues/5764
if (typeof unpackDirName === "string" || !unpackDirName) {
defines.UNPACK_DIR_NAME = unpackDirName || (await builder_util_1.executeAppBuilder(["ksuid"]));
defines.UNPACK_DIR_NAME = unpackDirName || (0, builder_util_1.generateKsuid)();
}
if (splashImage != null) {
defines.SPLASH_IMAGE = path.resolve(packager.projectDir, splashImage);
@ -265,39 +282,51 @@ class NsisTarget extends core_1.Target {
commandsUninstaller.VIProductVersion = appInfo.shortVersionWindows;
commandsUninstaller.VIAddVersionKey = this.computeVersionKey(true);
}
const sharedHeader = await this.computeCommonInstallerScriptHeader();
const script = isPortable
? await fs_extra_1.readFile(path.join(nsisUtil_1.nsisTemplatesDir, "portable.nsi"), "utf8")
: await this.computeScriptAndSignUninstaller(definesUninstaller, commandsUninstaller, installerPath, sharedHeader, archs);
// copy outfile name into main options, as the computeScriptAndSignUninstaller function was kind enough to add important data to temporary defines.
defines.UNINSTALLER_OUT_FILE = definesUninstaller.UNINSTALLER_OUT_FILE;
await this.executeMakensis(defines, commands, sharedHeader + (await this.computeFinalScript(script, true, archs)));
await Promise.all([packager.sign(installerPath), defines.UNINSTALLER_OUT_FILE == null ? Promise.resolve() : fs_extra_1.unlink(defines.UNINSTALLER_OUT_FILE)]);
const safeArtifactName = platformPackager_1.computeSafeArtifactNameIfNeeded(installerFilename, () => this.generateGitHubInstallerName());
let updateInfo;
if (this.isWebInstaller) {
updateInfo = differentialUpdateInfoBuilder_1.createNsisWebDifferentialUpdateInfo(installerPath, packageFiles);
}
else if (this.isBuildDifferentialAware) {
updateInfo = await differentialUpdateInfoBuilder_1.createBlockmap(installerPath, this, packager, safeArtifactName);
}
if (updateInfo != null && isPerMachine && (oneClick || options.packElevateHelper)) {
updateInfo.isAdminRightsRequired = true;
}
await packager.info.callArtifactBuildCompleted({
file: installerPath,
updateInfo,
target: this,
packager,
arch: primaryArch,
safeArtifactName,
isWriteUpdateInfo: !this.isPortable,
this.buildQueueManager.add(async () => {
const sharedHeader = await this.computeCommonInstallerScriptHeader();
let rawScript;
let isCustomScript = false;
if (isPortable) {
rawScript = await (0, fs_extra_1.readFile)(path.join(nsisUtil_1.nsisTemplatesDir, "portable.nsi"), "utf8");
}
else {
const result = await this.computeScriptAndSignUninstaller(definesUninstaller, commandsUninstaller, installerPath, sharedHeader, archs);
rawScript = result.script;
isCustomScript = result.isCustomScript;
}
// copy outfile name into main options, as the computeScriptAndSignUninstaller function was kind enough to add important data to temporary defines.
defines.UNINSTALLER_OUT_FILE = definesUninstaller.UNINSTALLER_OUT_FILE;
// Skip size verification for portable (NSIS recompresses the archive, installer < archive is normal)
// and for custom scripts (may not embed archives).
await this.executeMakensis(defines, commands, sharedHeader + (await this.computeFinalScript(rawScript, true, archs)), { skipSizeVerification: isPortable || isCustomScript });
await Promise.all([packager.signIf(installerPath), defines.UNINSTALLER_OUT_FILE == null ? Promise.resolve() : (0, fs_extra_1.unlink)(defines.UNINSTALLER_OUT_FILE)]);
const safeArtifactName = (0, platformPackager_1.computeSafeArtifactNameIfNeeded)(installerFilename, () => this.generateGitHubInstallerName(primaryArch, defaultArch));
let updateInfo;
if (this.isWebInstaller) {
updateInfo = (0, differentialUpdateInfoBuilder_1.createNsisWebDifferentialUpdateInfo)(installerPath, packageFiles);
}
else if (this.isBuildDifferentialAware) {
updateInfo = await (0, differentialUpdateInfoBuilder_1.createBlockmap)(installerPath, this, packager, safeArtifactName);
}
if (updateInfo != null && isPerMachine && (oneClick || options.packElevateHelper)) {
updateInfo.isAdminRightsRequired = true;
}
await packager.info.emitArtifactBuildCompleted({
file: installerPath,
updateInfo,
target: this,
packager,
arch: primaryArch,
safeArtifactName,
isWriteUpdateInfo: !this.isPortable,
});
});
}
generateGitHubInstallerName() {
generateGitHubInstallerName(primaryArch, defaultArch) {
const appInfo = this.packager.appInfo;
const classifier = appInfo.name.toLowerCase() === appInfo.name ? "setup-" : "Setup-";
return `${appInfo.name}-${this.isPortable ? "" : classifier}${appInfo.version}.exe`;
const archSuffix = !this.shouldBuildUniversalInstaller && primaryArch != null ? (0, builder_util_1.getArchSuffix)(primaryArch, defaultArch) : "";
return `${appInfo.name}-${this.isPortable ? "" : classifier}${appInfo.version}${archSuffix}.exe`;
}
get isUnicodeEnabled() {
return this.options.unicode !== false;
@ -306,22 +335,25 @@ class NsisTarget extends core_1.Target {
return false;
}
async computeScriptAndSignUninstaller(defines, commands, installerPath, sharedHeader, archs) {
var _a;
const packager = this.packager;
const customScriptPath = await packager.getResource(this.options.script, "installer.nsi");
const script = await fs_extra_1.readFile(customScriptPath || path.join(nsisUtil_1.nsisTemplatesDir, "installer.nsi"), "utf8");
const script = await (0, fs_extra_1.readFile)(customScriptPath || path.join(nsisUtil_1.nsisTemplatesDir, "installer.nsi"), "utf8");
if (customScriptPath != null) {
builder_util_1.log.info({ reason: "custom NSIS script is used" }, "uninstaller is not signed by electron-builder");
return script;
return { script, isCustomScript: true };
}
// https://github.com/electron-userland/electron-builder/issues/2103
// it is more safe and reliable to write uninstaller to our out dir
const uninstallerPath = path.join(this.outDir, `__uninstaller-${this.name}-${this.packager.appInfo.sanitizedName}.exe`);
// to support parallel builds, the uninstaller path must be unique to each target and arch combination
const uninstallerPath = path.join(this.outDir, `${path.basename(installerPath, "exe")}__uninstaller.exe`);
const isWin = process.platform === "win32";
defines.BUILD_UNINSTALLER = null;
defines.UNINSTALLER_OUT_FILE = isWin ? uninstallerPath : path.win32.join("Z:", uninstallerPath);
await this.executeMakensis(defines, commands, sharedHeader + (await this.computeFinalScript(script, false, archs)));
// http://forums.winamp.com/showthread.php?p=3078545
if (macosVersion_1.isMacOsCatalina()) {
// TODO: remove workaround when wine is fully upgraded to 11
if ((0, macosVersion_1.isMacOsCatalina)()) {
try {
await nsisUtil_1.UninstallerReader.exec(installerPath, uninstallerPath);
}
@ -331,21 +363,21 @@ class NsisTarget extends core_1.Target {
await vm.exec(installerPath, []);
// Parallels VM can exit after command execution, but NSIS continue to be running
let i = 0;
while (!(await fs_1.exists(uninstallerPath)) && i++ < 100) {
while (!(await (0, builder_util_1.exists)(uninstallerPath)) && i++ < 100) {
// noinspection JSUnusedLocalSymbols
// eslint-disable-next-line @typescript-eslint/no-unused-vars
await new Promise((resolve, _reject) => setTimeout(resolve, 300));
}
}
}
else {
await wine_1.execWine(installerPath, null, [], { env: { __COMPAT_LAYER: "RunAsInvoker" } });
const wineVm = new WineVm_1.WineVmManager((_a = packager.config.toolsets) === null || _a === void 0 ? void 0 : _a.wine);
await wineVm.exec(installerPath, [], { env: { __COMPAT_LAYER: "RunAsInvoker" } });
}
await packager.sign(uninstallerPath, " Signing NSIS uninstaller");
await packager.signIf(uninstallerPath);
delete defines.BUILD_UNINSTALLER;
// platform-specific path, not wine
defines.UNINSTALLER_OUT_FILE = uninstallerPath;
return script;
return { script, isCustomScript: false };
}
computeVersionKey(short = false) {
// Error: invalid VIProductVersion format, should be X.X.X.X
@ -353,18 +385,18 @@ class NsisTarget extends core_1.Target {
const localeId = this.options.language || "1033";
const appInfo = this.packager.appInfo;
const versionKey = [
`/LANG=${localeId} ProductName "${appInfo.productName}"`,
`/LANG=${localeId} ProductVersion "${appInfo.version}"`,
`/LANG=${localeId} LegalCopyright "${appInfo.copyright}"`,
`/LANG=${localeId} FileDescription "${appInfo.description}"`,
`/LANG=${localeId} FileVersion "${appInfo.buildVersion}"`,
`/LANG=${localeId} ProductName "${(0, nsisScriptGenerator_1.nsisEscapeString)(appInfo.productName)}"`,
`/LANG=${localeId} ProductVersion "${(0, nsisScriptGenerator_1.nsisEscapeString)(appInfo.version)}"`,
`/LANG=${localeId} LegalCopyright "${(0, nsisScriptGenerator_1.nsisEscapeString)(appInfo.copyright)}"`,
`/LANG=${localeId} FileDescription "${(0, nsisScriptGenerator_1.nsisEscapeString)(appInfo.description)}"`,
`/LANG=${localeId} FileVersion "${(0, nsisScriptGenerator_1.nsisEscapeString)(appInfo.buildVersion)}"`,
];
if (short) {
versionKey[1] = `/LANG=${localeId} ProductVersion "${appInfo.shortVersion}"`;
versionKey[4] = `/LANG=${localeId} FileVersion "${appInfo.shortVersion}"`;
versionKey[1] = `/LANG=${localeId} ProductVersion "${(0, nsisScriptGenerator_1.nsisEscapeString)(appInfo.shortVersion)}"`;
versionKey[4] = `/LANG=${localeId} FileVersion "${(0, nsisScriptGenerator_1.nsisEscapeString)(appInfo.shortVersion)}"`;
}
builder_util_1.use(this.packager.platformSpecificBuildOptions.legalTrademarks, it => versionKey.push(`/LANG=${localeId} LegalTrademarks "${it}"`));
builder_util_1.use(appInfo.companyName, it => versionKey.push(`/LANG=${localeId} CompanyName "${it}"`));
(0, builder_util_1.use)(this.packager.platformSpecificBuildOptions.legalTrademarks, it => versionKey.push(`/LANG=${localeId} LegalTrademarks "${(0, nsisScriptGenerator_1.nsisEscapeString)(it)}"`));
(0, builder_util_1.use)(appInfo.companyName, it => versionKey.push(`/LANG=${localeId} CompanyName "${(0, nsisScriptGenerator_1.nsisEscapeString)(it)}"`));
return versionKey;
}
configureDefines(oneClick, defines) {
@ -407,6 +439,9 @@ class NsisTarget extends core_1.Target {
if (options.perMachine === true) {
defines.INSTALL_MODE_PER_ALL_USERS = null;
}
if (options.selectPerMachineByDefault === true) {
defines.INSTALL_MODE_PER_ALL_USERS_DEFAULT = null;
}
if (!oneClick || options.perMachine === true) {
defines.INSTALL_MODE_PER_ALL_USERS_REQUIRED = null;
}
@ -419,7 +454,7 @@ class NsisTarget extends core_1.Target {
if (options.removeDefaultUninstallWelcomePage) {
defines.removeDefaultUninstallWelcomePage = null;
}
const commonOptions = CommonWindowsInstallerConfiguration_1.getEffectiveOptions(options, packager);
const commonOptions = (0, CommonWindowsInstallerConfiguration_1.getEffectiveOptions)(options, packager);
if (commonOptions.menuCategory != null) {
defines.MENU_FILENAME = commonOptions.menuCategory;
}
@ -474,7 +509,8 @@ class NsisTarget extends core_1.Target {
defines.COMPRESSION_METHOD = options.useZip ? "zip" : "7z";
}
}
async executeMakensis(defines, commands, script) {
async executeMakensis(defines, commands, script, opts = {}) {
var _a, _b;
const args = this.options.warningsAsErrors === false ? [] : ["-WX"];
args.push("-INPUTCHARSET", "UTF8");
for (const name of Object.keys(defines)) {
@ -483,7 +519,17 @@ class NsisTarget extends core_1.Target {
args.push(`-D${name}`);
}
else {
args.push(`-D${name}=${value}`);
// nsisEscapeString prevents three classes of injection:
// 1. Newlines → replaced with spaces; a bare \n in a define value
// would terminate the current script line and let whatever follows
// be parsed as a new preprocessor directive (e.g. !system, !include).
// 2. bare $ → escaped to $$; unescaped $ in a define value would cause
// NSIS to expand an unintended variable reference. ${...} references
// are left intact so NSIS compile-time defines like ${NSISDIR} still
// expand correctly.
// 3. " chars → escaped to $\"; an unescaped " would break out of
// double-quoted NSIS string literals where ${DEFINE} is expanded.
args.push(`-D${name}=${(0, nsisScriptGenerator_1.nsisEscapeString)(String(value))}`);
}
}
for (const name of Object.keys(commands)) {
@ -501,18 +547,26 @@ class NsisTarget extends core_1.Target {
if (this.packager.debugLogger.isEnabled) {
this.packager.debugLogger.add("nsis.script", script);
}
const nsisPath = await nsisUtil_1.NSIS_PATH();
const command = path.join(nsisPath, process.platform === "darwin" ? "mac" : process.platform === "win32" ? "Bin" : "linux", process.platform === "win32" ? "makensis.exe" : "makensis");
// if (process.platform === "win32") {
// fix for an issue caused by virus scanners, locking the file during write
// https://github.com/electron-userland/electron-builder/issues/5005
await ensureNotBusy(commands["OutFile"].replace(/"/g, ""));
// }
await builder_util_1.spawnAndWrite(command, args, script, {
// we use NSIS_CONFIG_CONST_DATA_PATH=no to build makensis on Linux, but in any case it doesn't use stubs as MacOS/Windows version, so, we explicitly set NSISDIR
env: { ...process.env, NSISDIR: nsisPath },
if (process.platform === "win32") {
// fix for an issue caused by virus scanners, locking the file during write
// https://github.com/electron-userland/electron-builder/issues/5005
await ensureNotBusy(commands["OutFile"].replace(/"/g, ""));
}
const makensis = await (0, windows_1.getMakeNsisPath)((_a = this.packager.config.toolsets) === null || _a === void 0 ? void 0 : _a.nsis, this.options.customNsisBinary);
const { stdout, stderr } = await (0, builder_util_1.spawnAndWriteWithOutput)(makensis.path, args, script, {
env: { ...process.env, ...((_b = makensis.env) !== null && _b !== void 0 ? _b : {}) },
cwd: nsisUtil_1.nsisTemplatesDir,
});
(0, nsisValidation_1.checkMakensisOutput)(stdout, stderr);
// Only verify output size for the final, non-web installer.
// BUILD_UNINSTALLER: intermediate uninstaller build — no embedded archives.
// APP_PACKAGE_STORE_FILE: nsis-web — archives downloaded at install-time.
// skipSizeVerification: portable builds (NSIS recompresses the archive, so
// installer < archive_size is normal) and custom scripts (may not embed archives).
if (!("BUILD_UNINSTALLER" in defines) && !("APP_PACKAGE_STORE_FILE" in defines) && !opts.skipSizeVerification) {
const outFile = commands["OutFile"].replace(/^"|"$/g, "");
await (0, nsisValidation_1.verifyInstallerSize)(outFile, defines);
}
}
async computeCommonInstallerScriptHeader() {
const packager = this.packager;
@ -523,23 +577,24 @@ class NsisTarget extends core_1.Target {
const includeDir = path.join(nsisUtil_1.nsisTemplatesDir, "include");
scriptGenerator.addIncludeDir(includeDir);
scriptGenerator.flags(["updated", "force-run", "keep-shortcuts", "no-desktop-shortcut", "delete-app-data", "allusers", "currentuser"]);
nsisLang_1.createAddLangsMacro(scriptGenerator, langConfigurator);
(0, nsisLang_1.createAddLangsMacro)(scriptGenerator, langConfigurator);
const taskManager = new builder_util_1.AsyncTaskManager(packager.info.cancellationToken);
const pluginArch = this.isUnicodeEnabled ? "x86-unicode" : "x86-ansi";
taskManager.add(async () => {
scriptGenerator.addPluginDir(pluginArch, path.join(await nsisResourcePathPromise(), "plugins", pluginArch));
var _a;
scriptGenerator.addPluginDir(pluginArch, path.join(await (0, windows_1.getNsisPluginsPath)((_a = this.packager.config.toolsets) === null || _a === void 0 ? void 0 : _a.nsis, this.options.customNsisResources), pluginArch));
});
taskManager.add(async () => {
const userPluginDir = path.join(packager.info.buildResourcesDir, pluginArch);
const stat = await fs_1.statOrNull(userPluginDir);
const stat = await (0, builder_util_1.statOrNull)(userPluginDir);
if (stat != null && stat.isDirectory()) {
scriptGenerator.addPluginDir(pluginArch, userPluginDir);
}
});
taskManager.addTask(nsisLang_1.addCustomMessageFileInclude("messages.yml", packager, scriptGenerator, langConfigurator));
taskManager.addTask((0, nsisLang_1.addCustomMessageFileInclude)("messages.yml", packager, scriptGenerator, langConfigurator));
if (!this.isPortable) {
if (options.oneClick === false) {
taskManager.addTask(nsisLang_1.addCustomMessageFileInclude("assistedMessages.yml", packager, scriptGenerator, langConfigurator));
taskManager.addTask((0, nsisLang_1.addCustomMessageFileInclude)("assistedMessages.yml", packager, scriptGenerator, langConfigurator));
}
taskManager.add(async () => {
const customInclude = await packager.getResource(this.options.include, "installer.nsh");
@ -560,7 +615,7 @@ class NsisTarget extends core_1.Target {
const taskManager = new builder_util_1.AsyncTaskManager(packager.info.cancellationToken);
if (isInstaller) {
// http://stackoverflow.com/questions/997456/nsis-license-file-based-on-language-selection
taskManager.add(() => nsisLicense_1.computeLicensePage(packager, options, scriptGenerator, langConfigurator.langs));
taskManager.add(() => (0, nsisLicense_1.computeLicensePage)(packager, options, scriptGenerator, langConfigurator.langs));
}
await taskManager.awaitTasks();
if (this.isPortable) {
@ -578,18 +633,18 @@ class NsisTarget extends core_1.Target {
if (isInstaller) {
const registerFileAssociationsScript = new nsisScriptGenerator_1.NsisScriptGenerator();
for (const item of fileAssociations) {
const extensions = builder_util_1.asArray(item.ext).map(platformPackager_1.normalizeExt);
const extensions = (0, builder_util_1.asArray)(item.ext).map(platformPackager_1.normalizeExt);
for (const ext of extensions) {
const customIcon = await packager.getResource(builder_util_1.getPlatformIconFileName(item.icon, false), `${extensions[0]}.ico`);
const customIcon = await packager.getResource((0, builder_util_1.getPlatformIconFileName)(item.icon, false), `${extensions[0]}.ico`);
let installedIconPath = "$appExe,0";
if (customIcon != null) {
installedIconPath = `$INSTDIR\\resources\\${path.basename(customIcon)}`;
installedIconPath = `$INSTDIR\\resources\\${(0, nsisScriptGenerator_1.nsisEscapeString)(path.basename(customIcon))}`;
registerFileAssociationsScript.file(installedIconPath, customIcon);
}
const icon = `"${installedIconPath}"`;
const commandText = `"Open with ${packager.appInfo.productName}"`;
const commandText = `"Open with ${(0, nsisScriptGenerator_1.nsisEscapeString)(packager.appInfo.productName)}"`;
const command = '"$appExe $\\"%1$\\""';
registerFileAssociationsScript.insertMacro("APP_ASSOCIATE", `"${ext}" "${item.name || ext}" "${item.description || ""}" ${icon} ${commandText} ${command}`);
registerFileAssociationsScript.insertMacro("APP_ASSOCIATE", `"${(0, nsisScriptGenerator_1.nsisEscapeString)(ext)}" "${(0, nsisScriptGenerator_1.nsisEscapeString)(item.name || ext)}" "${(0, nsisScriptGenerator_1.nsisEscapeString)(item.description || "")}" ${icon} ${commandText} ${command}`);
}
}
scriptGenerator.macro("registerFileAssociations", registerFileAssociationsScript);
@ -597,8 +652,8 @@ class NsisTarget extends core_1.Target {
else {
const unregisterFileAssociationsScript = new nsisScriptGenerator_1.NsisScriptGenerator();
for (const item of fileAssociations) {
for (const ext of builder_util_1.asArray(item.ext)) {
unregisterFileAssociationsScript.insertMacro("APP_UNASSOCIATE", `"${platformPackager_1.normalizeExt(ext)}" "${item.name || ext}"`);
for (const ext of (0, builder_util_1.asArray)(item.ext)) {
unregisterFileAssociationsScript.insertMacro("APP_UNASSOCIATE", `"${(0, platformPackager_1.normalizeExt)(ext)}" "${item.name || ext}"`);
}
}
scriptGenerator.macro("unregisterFileAssociations", unregisterFileAssociationsScript);
@ -610,12 +665,12 @@ class NsisTarget extends core_1.Target {
exports.NsisTarget = NsisTarget;
async function generateForPreCompressed(preCompressedFileExtensions, dir, arch, scriptGenerator) {
const resourcesDir = path.join(dir, "resources");
const dirInfo = await fs_1.statOrNull(resourcesDir);
const dirInfo = await (0, builder_util_1.statOrNull)(resourcesDir);
if (dirInfo == null || !dirInfo.isDirectory()) {
return;
}
const nodeModules = `${path.sep}node_modules`;
const preCompressedAssets = await fs_1.walk(resourcesDir, (file, stat) => {
const preCompressedAssets = await (0, builder_util_1.walk)(resourcesDir, (file, stat) => {
if (stat.isDirectory()) {
return !file.endsWith(nodeModules);
}
@ -626,7 +681,7 @@ async function generateForPreCompressed(preCompressedFileExtensions, dir, arch,
if (preCompressedAssets.length !== 0) {
const macro = new nsisScriptGenerator_1.NsisScriptGenerator();
for (const file of preCompressedAssets) {
macro.file(`$INSTDIR\\${path.relative(dir, file).replace(/\//g, "\\")}`, file);
macro.file(`$INSTDIR\\${(0, nsisScriptGenerator_1.nsisEscapeString)(path.relative(dir, file).replace(/\//g, "\\"))}`, file);
}
scriptGenerator.macro(`customFiles_${builder_util_1.Arch[arch]}`, macro);
}
@ -667,8 +722,8 @@ async function ensureNotBusy(outFile) {
async function createPackageFileInfo(file) {
return {
path: file,
size: (await fs_extra_1.stat(file)).size,
sha512: await hash_1.hashFile(file),
size: (await (0, fs_extra_1.stat)(file)).size,
sha512: await (0, hash_1.hashFile)(file),
};
}
//# sourceMappingURL=NsisTarget.js.map