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

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Loopline Systems
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,19 @@
import { Arch, SquirrelWindowsOptions, Target, WinPackager } from "app-builder-lib";
import { Options as SquirrelOptions } from "electron-winstaller";
export default class SquirrelWindowsTarget extends Target {
private readonly packager;
readonly outDir: string;
readonly options: SquirrelWindowsOptions;
isAsyncSupported: boolean;
constructor(packager: WinPackager, outDir: string);
private prepareSignedVendorDirectory;
private assertShellSafePath;
private ensurePathInside;
private generateStubExecutableExe;
build(appOutDir: string, arch: Arch): Promise<void>;
private get appName();
private get exeName();
private select7zipArch;
private createNuspecTemplateWithProjectUrl;
computeEffectiveDistOptions(appDirectory: string, outputDirectory: string, setupFile: string): Promise<SquirrelOptions>;
}

View file

@ -0,0 +1,289 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const builder_util_1 = require("builder-util");
const binDownload_1 = require("app-builder-lib/out/binDownload");
const filename_1 = require("builder-util/out/filename");
const app_builder_lib_1 = require("app-builder-lib");
const toolsetLock_1 = require("app-builder-lib/out/util/toolsetLock");
const path = require("path");
const fs = require("fs");
const os = require("os");
const electron_winstaller_1 = require("electron-winstaller");
const WineVm_1 = require("app-builder-lib/out/vm/WineVm");
class SquirrelWindowsTarget extends app_builder_lib_1.Target {
constructor(packager, outDir) {
super("squirrel");
this.packager = packager;
this.outDir = outDir;
//tslint:disable-next-line:no-object-literal-type-assertion
this.options = { ...this.packager.platformSpecificBuildOptions, ...this.packager.config.squirrelWindows };
this.isAsyncSupported = false;
}
async prepareSignedVendorDirectory() {
const customSquirrelVendorDirectory = this.options.customSquirrelVendorDir;
const tmpVendorDirectory = await this.packager.info.tempDirManager.createTempDir({ prefix: "squirrel-windows-vendor" });
if (customSquirrelVendorDirectory && (await (0, builder_util_1.exists)(customSquirrelVendorDirectory))) {
await fs.promises.cp(customSquirrelVendorDirectory, tmpVendorDirectory, { recursive: true });
}
else {
if (!(0, builder_util_1.isEmptyOrSpaces)(customSquirrelVendorDirectory)) {
builder_util_1.log.warn({ customSquirrelVendorDirectory }, "unable to access custom Squirrel.Windows vendor directory, falling back to default vendor");
}
const windowInstallerPackage = require.resolve("electron-winstaller/package.json");
const [squirrelBin] = await Promise.all([
(0, binDownload_1.getBinFromUrl)("squirrel.windows@1.0.0", "squirrel.windows-2.0.1-patched.7z", "76851f0c192eaf9bc6f8f3eecdfe325857ebe70d7833ec62ed846a1acd50c846"),
fs.promises.cp(path.join(path.dirname(windowInstallerPackage), "vendor"), tmpVendorDirectory, { recursive: true }),
]);
await fs.promises.cp(path.join(squirrelBin, "electron-winstaller", "vendor"), tmpVendorDirectory, { recursive: true });
}
const files = await fs.promises.readdir(tmpVendorDirectory);
const squirrelExe = files.find(f => f === "Squirrel.exe");
if (squirrelExe) {
const filePath = path.join(tmpVendorDirectory, squirrelExe);
builder_util_1.log.debug({ file: filePath }, "signing vendor executable");
await this.packager.signIf(filePath);
}
else {
builder_util_1.log.warn("Squirrel.exe not found in vendor directory, skipping signing");
}
return tmpVendorDirectory;
}
assertShellSafePath(filePath, description) {
if (/[\r\n`$;&|<>]/.test(filePath)) {
throw new builder_util_1.InvalidConfigurationError(`${description} contains unsafe shell characters: ${filePath}`);
}
}
async ensurePathInside(baseDir, targetPath, description) {
const resolvedBaseDir = path.resolve(baseDir);
const resolvedTargetPath = path.resolve(targetPath);
let canonicalBaseDir = resolvedBaseDir;
let canonicalTargetPath = resolvedTargetPath;
try {
canonicalBaseDir = await fs.promises.realpath(resolvedBaseDir);
}
catch {
canonicalBaseDir = resolvedBaseDir;
}
try {
canonicalTargetPath = await fs.promises.realpath(resolvedTargetPath);
}
catch {
// Target may not exist yet; resolve the parent to handle symlinks/junctions consistently
try {
const resolvedTargetParent = path.dirname(resolvedTargetPath);
const canonicalTargetParent = await fs.promises.realpath(resolvedTargetParent);
const relativeFromResolvedParent = path.relative(resolvedTargetParent, resolvedTargetPath);
if ((0, builder_util_1.isEmptyOrSpaces)(relativeFromResolvedParent) ||
path.isAbsolute(relativeFromResolvedParent) ||
relativeFromResolvedParent.split(path.sep).includes("..") ||
/[\0\r\n]/.test(relativeFromResolvedParent)) {
throw new builder_util_1.InvalidConfigurationError(`${description} contains invalid path segments`);
}
canonicalTargetPath = path.resolve(canonicalTargetParent, relativeFromResolvedParent);
}
catch {
canonicalTargetPath = resolvedTargetPath;
}
}
const relativePath = path.relative(canonicalBaseDir, canonicalTargetPath);
if (relativePath.startsWith("..") || path.isAbsolute(relativePath)) {
throw new builder_util_1.InvalidConfigurationError(`${description} must be inside ${canonicalBaseDir}`);
}
this.assertShellSafePath(canonicalTargetPath, description);
return canonicalTargetPath;
}
async generateStubExecutableExe(appOutDir, vendorDir) {
var _a;
if (!path.isAbsolute(appOutDir) || !path.isAbsolute(vendorDir)) {
throw new builder_util_1.InvalidConfigurationError("appOutDir and vendorDir must be absolute paths");
}
const files = await fs.promises.readdir(appOutDir, { withFileTypes: true });
const appExe = files.find(f => f.name === `${this.exeName}.exe`);
if (!appExe) {
throw new Error(`App executable not found in app directory: ${appOutDir}`);
}
const filePath = await this.ensurePathInside(appOutDir, path.join(appOutDir, appExe.name), "App executable path");
const stubExePath = await this.ensurePathInside(appOutDir, path.join(appOutDir, `${this.exeName}_ExecutionStub.exe`), "Stub executable path");
const stubExecutableSource = await this.ensurePathInside(vendorDir, path.join(vendorDir, "StubExecutable.exe"), "Stub executable source");
const writeZipToSetupExe = await this.ensurePathInside(vendorDir, path.join(vendorDir, "WriteZipToSetup.exe"), "WriteZipToSetup executable");
await fs.promises.copyFile(stubExecutableSource, stubExePath);
const wineVm = new WineVm_1.WineVmManager((_a = this.packager.config.toolsets) === null || _a === void 0 ? void 0 : _a.wine);
await wineVm.exec(writeZipToSetupExe, ["--copy-stub-resources", filePath, stubExePath]);
await this.packager.signIf(stubExePath);
builder_util_1.log.debug({ file: filePath }, "signing app executable");
await this.packager.signIf(filePath);
}
async build(appOutDir, arch) {
const packager = this.packager;
const version = packager.appInfo.version;
const sanitizedName = (0, filename_1.sanitizeFileName)(this.appName);
const setupFile = packager.expandArtifactNamePattern(this.options, "exe", arch, "${productName} Setup ${version}.${ext}");
const installerOutDir = path.join(this.outDir, `squirrel-windows${(0, app_builder_lib_1.getArchSuffix)(arch)}`);
const artifactPath = path.join(installerOutDir, setupFile);
const msiArtifactPath = path.join(installerOutDir, packager.expandArtifactNamePattern(this.options, "msi", arch, "${productName} Setup ${version}.${ext}"));
this.buildQueueManager.add(async () => {
await packager.info.emitArtifactBuildStarted({
targetPresentableName: "Squirrel.Windows",
file: artifactPath,
arch,
});
const distOptions = await this.computeEffectiveDistOptions(appOutDir, installerOutDir, setupFile);
await this.generateStubExecutableExe(appOutDir, distOptions.vendorDirectory);
await (0, toolsetLock_1.withToolsetLock)(() => (0, electron_winstaller_1.createWindowsInstaller)(distOptions));
await packager.signAndEditResources(artifactPath, arch, installerOutDir);
if (this.options.msi) {
await packager.signIf(msiArtifactPath);
}
const safeArtifactName = (ext) => `${sanitizedName}-Setup-${version}${(0, app_builder_lib_1.getArchSuffix)(arch)}.${ext}`;
await packager.info.emitArtifactBuildCompleted({
file: artifactPath,
target: this,
arch,
safeArtifactName: safeArtifactName("exe"),
packager: this.packager,
});
if (this.options.msi) {
await packager.info.emitArtifactCreated({
file: msiArtifactPath,
target: this,
arch,
safeArtifactName: safeArtifactName("msi"),
packager: this.packager,
});
}
const packagePrefix = `${this.appName}-${(0, electron_winstaller_1.convertVersion)(version)}-`;
await packager.info.emitArtifactCreated({
file: path.join(installerOutDir, `${packagePrefix}full.nupkg`),
target: this,
arch,
packager,
});
if (distOptions.remoteReleases != null) {
await packager.info.emitArtifactCreated({
file: path.join(installerOutDir, `${packagePrefix}delta.nupkg`),
target: this,
arch,
packager,
});
}
await packager.info.emitArtifactCreated({
file: path.join(installerOutDir, "RELEASES"),
target: this,
arch,
packager,
});
});
return Promise.resolve();
}
get appName() {
return this.options.name || this.packager.appInfo.name;
}
get exeName() {
const name = this.packager.appInfo.productFilename || this.options.name || this.packager.appInfo.productName;
return (0, filename_1.sanitizeFileName)(name);
}
select7zipArch(vendorDirectory) {
// https://github.com/electron/windows-installer/blob/main/script/select-7z-arch.js
// Even if we're cross-compiling for a different arch like arm64,
// we still need to use the 7-Zip executable for the host arch
const resolvedArch = os.arch;
fs.copyFileSync(path.join(vendorDirectory, `7z-${resolvedArch}.exe`), path.join(vendorDirectory, "7z.exe"));
fs.copyFileSync(path.join(vendorDirectory, `7z-${resolvedArch}.dll`), path.join(vendorDirectory, "7z.dll"));
}
async createNuspecTemplateWithProjectUrl() {
const templatePath = path.resolve(__dirname, "..", "template.nuspectemplate");
const projectUrl = await this.packager.appInfo.computePackageUrl();
if (projectUrl != null) {
const nuspecTemplate = await this.packager.info.tempDirManager.getTempFile({ prefix: "template", suffix: ".nuspectemplate" });
let templateContent = await fs.promises.readFile(templatePath, "utf8");
const searchString = "<copyright><%- copyright %></copyright>";
templateContent = templateContent.replace(searchString, `${searchString}\n <projectUrl>${projectUrl}</projectUrl>`);
await fs.promises.writeFile(nuspecTemplate, templateContent);
return nuspecTemplate;
}
return templatePath;
}
async computeEffectiveDistOptions(appDirectory, outputDirectory, setupFile) {
const packager = this.packager;
let iconUrl = this.options.iconUrl;
if (iconUrl == null) {
const info = await packager.info.repositoryInfo;
if (info != null) {
iconUrl = `https://github.com/${info.user}/${info.project}/blob/master/${packager.info.relativeBuildResourcesDirname}/icon.ico?raw=true`;
}
if (iconUrl == null) {
throw new builder_util_1.InvalidConfigurationError("squirrelWindows.iconUrl is not specified, please see https://www.electron.build/squirrel-windows#SquirrelWindowsOptions-iconUrl");
}
}
checkConflictingOptions(this.options);
const appInfo = packager.appInfo;
const options = {
appDirectory: appDirectory,
outputDirectory: outputDirectory,
name: this.options.useAppIdAsId ? appInfo.id : this.appName,
title: appInfo.productName || appInfo.name,
version: appInfo.version,
description: appInfo.description,
exe: `${this.exeName}.exe`,
authors: appInfo.companyName || "",
nuspecTemplate: await this.createNuspecTemplateWithProjectUrl(),
iconUrl,
copyright: appInfo.copyright,
noMsi: !this.options.msi,
usePackageJson: false,
};
options.vendorDirectory = await this.prepareSignedVendorDirectory();
this.select7zipArch(options.vendorDirectory);
options.fixUpPaths = true;
options.setupExe = setupFile;
if (this.options.msi) {
options.setupMsi = setupFile.replace(".exe", ".msi");
}
if ((0, builder_util_1.isEmptyOrSpaces)(options.description)) {
options.description = this.options.name || appInfo.productName;
}
if (options.remoteToken == null) {
options.remoteToken = process.env.GH_TOKEN || process.env.GITHUB_TOKEN;
}
if (this.options.remoteReleases === true) {
const info = await packager.info.repositoryInfo;
if (info == null) {
builder_util_1.log.warn("remoteReleases set to true, but cannot get repository info");
}
else {
options.remoteReleases = `https://github.com/${info.user}/${info.project}`;
builder_util_1.log.info({ remoteReleases: options.remoteReleases }, `remoteReleases is set`);
}
}
else if (typeof this.options.remoteReleases === "string" && !(0, builder_util_1.isEmptyOrSpaces)(this.options.remoteReleases)) {
options.remoteReleases = this.options.remoteReleases;
}
if (this.options.loadingGif) {
options.loadingGif = path.resolve(packager.projectDir, this.options.loadingGif);
}
else {
const resourceList = await packager.resourceList;
if (resourceList.includes("install-spinner.gif")) {
options.loadingGif = path.join(packager.buildResourcesDir, "install-spinner.gif");
}
}
return options;
}
}
exports.default = SquirrelWindowsTarget;
function checkConflictingOptions(options) {
for (const name of ["outputDirectory", "appDirectory", "exe", "fixUpPaths", "usePackageJson", "extraFileSpecs", "extraMetadataSpecs", "skipUpdateIcon", "setupExe"]) {
if (name in options) {
throw new builder_util_1.InvalidConfigurationError(`Option ${name} is ignored, do not specify it.`);
}
}
if ("noMsi" in options) {
builder_util_1.log.warn(`noMsi is deprecated, please specify as "msi": true if you want to create an MSI installer`);
options.msi = !options.noMsi;
}
const msi = options.msi;
if (msi != null && typeof msi !== "boolean") {
throw new builder_util_1.InvalidConfigurationError(`msi expected to be boolean value, but string '"${msi}"' was specified`);
}
}
//# sourceMappingURL=SquirrelWindowsTarget.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,28 @@
{
"name": "electron-builder-squirrel-windows",
"version": "26.15.3",
"main": "out/SquirrelWindowsTarget.js",
"author": "Vladimir Krivosheev",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/electron-userland/electron-builder.git",
"directory": "packages/electron-builder-squirrel-windows"
},
"bugs": "https://github.com/electron-userland/electron-builder/issues",
"homepage": "https://github.com/electron-userland/electron-builder",
"files": [
"out",
"template.nuspectemplate"
],
"dependencies": {
"electron-winstaller": "5.4.0",
"app-builder-lib": "26.15.3",
"builder-util": "26.15.3"
},
"devDependencies": {
"@types/archiver": "5.3.1",
"@types/fs-extra": "9.0.13"
},
"types": "./out/SquirrelWindowsTarget.d.ts"
}

View file

@ -0,0 +1,3 @@
# electron-builder-squirrel-windows
Plugin for [electron-builder](https://github.com/electron-userland/electron-builder) to build Squirrel.Windows installer.

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id><%- name %></id>
<title><%- title %></title>
<version><%- version %></version>
<authors><%- authors %></authors>
<owners><%- owners %></owners>
<iconUrl><%- iconUrl %></iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description><%- description %></description>
<copyright><%- copyright %></copyright>
</metadata>
<files>
<file src="locales\**" target="lib\net45\locales" />
<file src="resources\**" target="lib\net45\resources" />
<file src="*.bin" target="lib\net45" />
<file src="*.dll" target="lib\net45" />
<file src="*.pak" target="lib\net45" />
<file src="*.exe.config" target="lib\net45" />
<file src="*.exe.sig" target="lib\net45" />
<file src="*_ExecutionStub.exe" target="lib\net45" />
<file src="icudtl.dat" target="lib\net45\icudtl.dat" />
<file src="Squirrel.exe" target="lib\net45\squirrel.exe" />
<file src="LICENSE.electron.txt" target="lib\net45\LICENSE.electron.txt" />
<file src="LICENSES.chromium.html" target="lib\net45\LICENSES.chromium.html" />
<file src="<%- exe %>" target="lib\net45\<%- exe %>" />
<% additionalFiles.forEach(function(f) { %>
<file src="<%- f.src %>" target="<%- f.target %>" />
<% }); %>
</files>
</package>