update electron to v43
This commit is contained in:
parent
68ac0beedf
commit
fb6c8b6ee9
5385 changed files with 513060 additions and 123058 deletions
223
electron/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
generated
vendored
223
electron/node_modules/app-builder-lib/out/targets/LinuxTargetHelper.js
generated
vendored
|
|
@ -2,9 +2,77 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.LinuxTargetHelper = exports.installPrefix = void 0;
|
||||
const builder_util_1 = require("builder-util");
|
||||
const builder_util_runtime_1 = require("builder-util-runtime");
|
||||
const fs_extra_1 = require("fs-extra");
|
||||
const lazy_val_1 = require("lazy-val");
|
||||
const path_1 = require("path");
|
||||
const semver = require("semver");
|
||||
const core24_1 = require("./snap/core24");
|
||||
const coreCustom_1 = require("./snap/coreCustom");
|
||||
const coreLegacy_1 = require("./snap/coreLegacy");
|
||||
/**
|
||||
* Escape a string value for use in a freedesktop .desktop file string field
|
||||
* (Name, Comment, StartupWMClass, etc.).
|
||||
*
|
||||
* The freedesktop Desktop Entry Specification requires that the following
|
||||
* characters be escaped in string / localestring values:
|
||||
* \n → \\n (newline — would inject new key=value lines otherwise)
|
||||
* \r → \\r
|
||||
* \t → \\t
|
||||
* \\ → \\\\
|
||||
*
|
||||
* Without escaping, a productName or description containing a literal newline
|
||||
* can inject arbitrary key=value pairs into the generated .desktop file,
|
||||
* potentially overriding the Exec key.
|
||||
*
|
||||
* @see https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#value-types
|
||||
*/
|
||||
function desktopStringEscape(value) {
|
||||
return value.replace(/\\/g, "\\\\").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
||||
}
|
||||
/**
|
||||
* Characters that require an Exec argument to be double-quoted per the
|
||||
* freedesktop Desktop Entry Specification. Plain alphanumeric args and
|
||||
* field codes must NOT be wrapped in quotes.
|
||||
*
|
||||
* @see https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables
|
||||
*/
|
||||
const EXEC_RESERVED_RE = /[\s"'`\\<>~|&;$*?#()]/;
|
||||
/**
|
||||
* Quote a single argument for use in a .desktop file Exec key.
|
||||
*
|
||||
* Field codes (`%f`, `%u`, `%F`, `%U`, etc.) MUST be left unquoted — the
|
||||
* desktop launcher only expands them in unquoted token positions. Wrapping
|
||||
* them in `"…"` causes the launcher to treat them as literal strings, which
|
||||
* breaks file-association / drag-and-drop functionality.
|
||||
*
|
||||
* For all other arguments, double-quoting is used when the argument contains
|
||||
* any character that would be misinterpreted by the launcher without quoting
|
||||
* (spaces, shell metacharacters, etc.). Safe plain-word args are passed
|
||||
* through unchanged to keep the Exec line readable.
|
||||
*
|
||||
* @see https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables
|
||||
*/
|
||||
function desktopExecArgEscape(arg) {
|
||||
// Field codes (%f, %u, %F, %U, %i, %c, %k, …) must never be quoted.
|
||||
if (/^%[a-zA-Z]$/.test(arg)) {
|
||||
return arg;
|
||||
}
|
||||
// Only quote when the arg actually contains characters that need it.
|
||||
if (EXEC_RESERVED_RE.test(arg)) {
|
||||
return `"${arg.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
function mapLinuxCompressionToSnap(level) {
|
||||
if (level === "store") {
|
||||
return "lzo";
|
||||
}
|
||||
if (level === "maximum") {
|
||||
return "xz";
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
exports.installPrefix = "/opt";
|
||||
class LinuxTargetHelper {
|
||||
constructor(packager) {
|
||||
|
|
@ -19,6 +87,60 @@ class LinuxTargetHelper {
|
|||
get mimeTypeFiles() {
|
||||
return this.mimeTypeFilesPromise.value;
|
||||
}
|
||||
getSnapCore() {
|
||||
const { snapcraft, snap: legacySnap } = this.packager.config;
|
||||
if (snapcraft != null && legacySnap != null) {
|
||||
builder_util_1.log.warn("Both `snapcraft` and `snap` configurations are present. `snapcraft` takes precedence; please remove the `snap` key to silence this warning.");
|
||||
}
|
||||
// Merge linux-level options (category, description, mimeTypes, etc.) as the base so they
|
||||
// propagate into the generated snapcraft.yaml and .desktop file without requiring users to
|
||||
// duplicate them under core24/core18/etc. Per-core options always win for conflicts.
|
||||
// linux.compression is a CompressionLevel ("store"/"normal"/"maximum"); snap compression is an
|
||||
// algorithm ("xz"/"lzo"). Map the level to the nearest algorithm; per-core options override.
|
||||
const { compression: linuxCompression, ...linuxOptions } = this.packager.platformSpecificBuildOptions;
|
||||
const snapLinuxOptions = { ...linuxOptions, compression: mapLinuxCompressionToSnap(linuxCompression) };
|
||||
if (snapcraft != null) {
|
||||
const core = snapcraft.base;
|
||||
const options = snapcraft[core] || {};
|
||||
switch (core) {
|
||||
case "core18":
|
||||
case "core20":
|
||||
case "core22":
|
||||
if (!this.isElectronVersionGreaterOrEqualThan("4.0.0")) {
|
||||
if (!this.isElectronVersionGreaterOrEqualThan("2.0.0-beta.1")) {
|
||||
throw new builder_util_1.InvalidConfigurationError("Electron 2 and higher is required to build Snap with core18/core20/core22");
|
||||
}
|
||||
builder_util_1.log.warn(null, "electron 4 and higher is highly recommended for Snap with core18/core20/core22");
|
||||
}
|
||||
return new coreLegacy_1.SnapCoreLegacy(this.packager, this, (0, builder_util_runtime_1.deepAssign)({}, snapLinuxOptions, { base: core, ...options }));
|
||||
case "core24":
|
||||
if (!this.isElectronVersionGreaterOrEqualThan("28.0.0")) {
|
||||
if (!this.isElectronVersionGreaterOrEqualThan("25.0.0")) {
|
||||
throw new builder_util_1.InvalidConfigurationError("Electron 25 and higher is required to build Snap with core24");
|
||||
}
|
||||
builder_util_1.log.warn(null, "electron 28 and higher is highly recommended for Snap with core24");
|
||||
}
|
||||
return new core24_1.SnapCore24(this.packager, this, (0, builder_util_runtime_1.deepAssign)({}, snapLinuxOptions, options));
|
||||
case "custom":
|
||||
// Pass-through: do not inject linux options into user-supplied yaml
|
||||
return new coreCustom_1.SnapCoreCustom(this.packager, this, snapcraft.custom || {});
|
||||
}
|
||||
}
|
||||
if (legacySnap != null) {
|
||||
builder_util_1.log.warn({
|
||||
reason: "`snap` configuration is deprecated",
|
||||
docs: "https://www.electron.build/snapcraft",
|
||||
}, "please consider migrating `snap` configuration to `snapcraft.<core>` and remove `snap` configuration");
|
||||
}
|
||||
return new coreLegacy_1.SnapCoreLegacy(this.packager, this, (0, builder_util_runtime_1.deepAssign)({}, snapLinuxOptions, legacySnap !== null && legacySnap !== void 0 ? legacySnap : {}));
|
||||
}
|
||||
isElectronVersionGreaterOrEqualThan(version, fallback) {
|
||||
const electronVersion = this.packager.config.electronVersion;
|
||||
if (!electronVersion) {
|
||||
return fallback ? semver.gte(fallback, version) : true;
|
||||
}
|
||||
return semver.gte(electronVersion, version);
|
||||
}
|
||||
async computeMimeTypeFiles() {
|
||||
const items = [];
|
||||
for (const fileAssociation of this.packager.fileAssociations) {
|
||||
|
|
@ -36,7 +158,7 @@ class LinuxTargetHelper {
|
|||
return null;
|
||||
}
|
||||
const file = await this.packager.getTempFile(".xml");
|
||||
await fs_extra_1.outputFile(file, '<?xml version="1.0" encoding="utf-8"?>\n<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">\n' + items.join("\n") + "\n</mime-info>");
|
||||
await (0, fs_extra_1.outputFile)(file, '<?xml version="1.0" encoding="utf-8"?>\n<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">\n' + items.join("\n") + "\n</mime-info>");
|
||||
return file;
|
||||
}
|
||||
// must be name without spaces and other special characters, but not product name used
|
||||
|
|
@ -46,31 +168,62 @@ class LinuxTargetHelper {
|
|||
const { platformSpecificBuildOptions, config } = packager;
|
||||
const sources = [platformSpecificBuildOptions.icon, (_b = (_a = config.mac) === null || _a === void 0 ? void 0 : _a.icon) !== null && _b !== void 0 ? _b : config.icon].filter(str => !!str);
|
||||
// If no explicit sources are defined, fallback to buildResources directory, then default framework icon
|
||||
let fallbackSources = [...builder_util_1.asArray(packager.getDefaultFrameworkIcon())];
|
||||
let fallbackSources = [...(0, builder_util_1.asArray)(packager.getDefaultFrameworkIcon())];
|
||||
const buildResources = (_c = config.directories) === null || _c === void 0 ? void 0 : _c.buildResources;
|
||||
if (buildResources && (await builder_util_1.exists(path_1.join(buildResources, "icons")))) {
|
||||
if (buildResources && (await (0, builder_util_1.exists)((0, path_1.join)(buildResources, "icons")))) {
|
||||
fallbackSources = [buildResources, ...fallbackSources];
|
||||
}
|
||||
// need to put here and not as default because need to resolve image size
|
||||
const result = await packager.resolveIcon(sources, fallbackSources, "set");
|
||||
this.maxIconPath = result[result.length - 1].file;
|
||||
return result;
|
||||
// Ignore .icon files for linux (they are exclusive for macOS)
|
||||
return result.filter(icon => !icon.file.endsWith(".icon"));
|
||||
}
|
||||
getDescription(options) {
|
||||
return options.description || this.packager.appInfo.description;
|
||||
}
|
||||
getSanitizedVersion(target) {
|
||||
const { appInfo: { version }, } = this.packager;
|
||||
switch (target) {
|
||||
case "pacman":
|
||||
return version.replace(/-/g, "_");
|
||||
case "rpm":
|
||||
case "deb":
|
||||
return version.replace(/-/g, "~");
|
||||
default:
|
||||
return version;
|
||||
}
|
||||
}
|
||||
async writeDesktopEntry(targetSpecificOptions, exec, destination, extra) {
|
||||
const data = await this.computeDesktopEntry(targetSpecificOptions, exec, extra);
|
||||
const file = destination || (await this.packager.getTempFile(`${this.packager.appInfo.productFilename}.desktop`));
|
||||
await fs_extra_1.outputFile(file, data);
|
||||
await (0, fs_extra_1.outputFile)(file, data);
|
||||
return file;
|
||||
}
|
||||
getDesktopFileName(fallback = this.packager.executableName) {
|
||||
var _a;
|
||||
if (!this.packager.platformSpecificBuildOptions.syncDesktopName) {
|
||||
return fallback;
|
||||
}
|
||||
const trimmedDesktopName = (_a = this.packager.info.metadata.desktopName) === null || _a === void 0 ? void 0 : _a.trim();
|
||||
if ((0, builder_util_1.isEmptyOrSpaces)(trimmedDesktopName)) {
|
||||
return fallback;
|
||||
}
|
||||
const basename = trimmedDesktopName.replace(/\.desktop$/, "");
|
||||
// Guard against path traversal: desktopName flows into filesystem paths
|
||||
// (snap/gui/<name>.desktop, /usr/share/applications/<name>.desktop, etc.).
|
||||
if (/[/\\]/.test(basename) || [...basename].some(c => c.charCodeAt(0) === 0)) {
|
||||
throw new builder_util_1.InvalidConfigurationError(`desktopName "${trimmedDesktopName}" produces an invalid .desktop filename — remove any path separators or NUL characters`);
|
||||
}
|
||||
return basename;
|
||||
}
|
||||
computeDesktopEntry(targetSpecificOptions, exec, extra) {
|
||||
var _a, _b, _c, _d, _e, _f, _g;
|
||||
if (exec != null && exec.length === 0) {
|
||||
throw new Error("Specified exec is empty");
|
||||
}
|
||||
// https://github.com/electron-userland/electron-builder/issues/3418
|
||||
if (targetSpecificOptions.desktop != null && targetSpecificOptions.desktop.Exec != null) {
|
||||
if ((_b = (_a = targetSpecificOptions.desktop) === null || _a === void 0 ? void 0 : _a.entry) === null || _b === void 0 ? void 0 : _b.Exec) {
|
||||
throw new Error("Please specify executable name as linux.executableName instead of linux.desktop.Exec");
|
||||
}
|
||||
const packager = this.packager;
|
||||
|
|
@ -83,7 +236,9 @@ class LinuxTargetHelper {
|
|||
}
|
||||
if (executableArgs) {
|
||||
exec += " ";
|
||||
exec += executableArgs.join(" ");
|
||||
// Each arg is double-quoted per the freedesktop Exec key spec so that
|
||||
// spaces, $, ;, & and other reserved characters are not misinterpreted.
|
||||
exec += executableArgs.map(desktopExecArgEscape).join(" ");
|
||||
}
|
||||
// https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#exec-variables
|
||||
const execCodes = ["%f", "%u", "%F", "%U"];
|
||||
|
|
@ -91,33 +246,47 @@ class LinuxTargetHelper {
|
|||
exec += " %U";
|
||||
}
|
||||
}
|
||||
const desktopMeta = {
|
||||
Name: appInfo.productName,
|
||||
// https://github.com/electron-userland/electron-builder/issues/9103
|
||||
// Electron derives app_id from desktopName in package.json; StartupWMClass must match.
|
||||
// https://github.com/electron/electron/blob/9a7b73b5334f1d72c08e2d5e94106706ed751186/lib/browser/init.ts#L128-L133
|
||||
const trimmedDesktopName = (_c = packager.info.metadata.desktopName) === null || _c === void 0 ? void 0 : _c.trim();
|
||||
if ((0, builder_util_1.isEmptyOrSpaces)(trimmedDesktopName)) {
|
||||
builder_util_1.log.warn({
|
||||
reason: "desktopName is not set in package.json",
|
||||
docs: "https://www.electron.build/linux#window-association-desktopname--syncdesktopname",
|
||||
}, "electron uses desktopName as app_id / WM_CLASS for window association. Without it desktop environments may not link running windows to this .desktop entry. Set desktopName in package.json and linux.syncDesktopName: true to fix.");
|
||||
}
|
||||
const wmClass = !(0, builder_util_1.isEmptyOrSpaces)(trimmedDesktopName) ? trimmedDesktopName.replace(/\.desktop$/, "") : appInfo.productName;
|
||||
const desktopMeta = (0, builder_util_runtime_1.deepAssign)({
|
||||
// String values are escaped per the freedesktop spec (\\, \n, \r, \t)
|
||||
// so that a product name containing a newline cannot inject new key=value
|
||||
// pairs into the .desktop file (e.g. overriding the Exec key).
|
||||
Name: desktopStringEscape(appInfo.productName),
|
||||
Exec: exec,
|
||||
Terminal: "false",
|
||||
Type: "Application",
|
||||
Icon: packager.executableName,
|
||||
// https://askubuntu.com/questions/367396/what-represent-the-startupwmclass-field-of-a-desktop-file
|
||||
// must be set to package.json name (because it is Electron set WM_CLASS)
|
||||
// Set to desktopName (minus .desktop suffix) when provided, so it matches Electron's
|
||||
// app_id and desktop environments can associate running windows with this entry.
|
||||
// Falls back to productName for apps that don't set desktopName.
|
||||
// to get WM_CLASS of running window: xprop WM_CLASS
|
||||
// StartupWMClass doesn't work for unicode
|
||||
// https://github.com/electron/electron/blob/2-0-x/atom/browser/native_window_views.cc#L226
|
||||
StartupWMClass: appInfo.productName,
|
||||
...extra,
|
||||
...targetSpecificOptions.desktop,
|
||||
};
|
||||
StartupWMClass: desktopStringEscape(wmClass),
|
||||
}, extra, (_e = (_d = targetSpecificOptions.desktop) === null || _d === void 0 ? void 0 : _d.entry) !== null && _e !== void 0 ? _e : {});
|
||||
const description = this.getDescription(targetSpecificOptions);
|
||||
if (!builder_util_1.isEmptyOrSpaces(description)) {
|
||||
desktopMeta.Comment = description;
|
||||
if (!(0, builder_util_1.isEmptyOrSpaces)(description)) {
|
||||
desktopMeta.Comment = desktopStringEscape(description);
|
||||
}
|
||||
const mimeTypes = builder_util_1.asArray(targetSpecificOptions.mimeTypes);
|
||||
const mimeTypes = (0, builder_util_1.asArray)(targetSpecificOptions.mimeTypes);
|
||||
for (const fileAssociation of packager.fileAssociations) {
|
||||
if (fileAssociation.mimeType != null) {
|
||||
mimeTypes.push(fileAssociation.mimeType);
|
||||
}
|
||||
}
|
||||
for (const protocol of builder_util_1.asArray(packager.config.protocols).concat(builder_util_1.asArray(packager.platformSpecificBuildOptions.protocols))) {
|
||||
for (const scheme of builder_util_1.asArray(protocol.schemes)) {
|
||||
for (const protocol of (0, builder_util_1.asArray)(packager.config.protocols).concat((0, builder_util_1.asArray)(packager.platformSpecificBuildOptions.protocols))) {
|
||||
for (const scheme of (0, builder_util_1.asArray)(protocol.schemes)) {
|
||||
mimeTypes.push(`x-scheme-handler/${scheme}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -125,7 +294,7 @@ class LinuxTargetHelper {
|
|||
desktopMeta.MimeType = mimeTypes.join(";") + ";";
|
||||
}
|
||||
let category = targetSpecificOptions.category;
|
||||
if (builder_util_1.isEmptyOrSpaces(category)) {
|
||||
if ((0, builder_util_1.isEmptyOrSpaces)(category)) {
|
||||
const macCategory = (packager.config.mac || {}).category;
|
||||
if (macCategory != null) {
|
||||
category = macToLinuxCategory[macCategory];
|
||||
|
|
@ -137,7 +306,7 @@ class LinuxTargetHelper {
|
|||
}
|
||||
builder_util_1.log.warn({
|
||||
reason: "linux.category is not set and cannot map from macOS",
|
||||
docs: "https://www.electron.build/configuration/linux",
|
||||
docs: "https://www.electron.build/linux",
|
||||
}, 'application Linux category is set to default "Utility"');
|
||||
category = "Utility";
|
||||
}
|
||||
|
|
@ -148,6 +317,17 @@ class LinuxTargetHelper {
|
|||
data += `\n${name}=${desktopMeta[name]}`;
|
||||
}
|
||||
data += "\n";
|
||||
const desktopActions = (_g = (_f = targetSpecificOptions.desktop) === null || _f === void 0 ? void 0 : _f.desktopActions) !== null && _g !== void 0 ? _g : {};
|
||||
for (const [actionName, config] of Object.entries(desktopActions)) {
|
||||
if (!Object.keys(config !== null && config !== void 0 ? config : {}).length) {
|
||||
continue;
|
||||
}
|
||||
data += `\n[Desktop Action ${actionName}]`;
|
||||
for (const [key, value] of Object.entries(config !== null && config !== void 0 ? config : {})) {
|
||||
data += `\n${key}=${value}`;
|
||||
}
|
||||
data += "\n";
|
||||
}
|
||||
return Promise.resolve(data);
|
||||
}
|
||||
}
|
||||
|
|
@ -161,5 +341,6 @@ const macToLinuxCategory = {
|
|||
"public.app-category.utilities": "Utility",
|
||||
"public.app-category.social-networking": "Network;Chat",
|
||||
"public.app-category.finance": "Office;Finance",
|
||||
"public.app-category.music": "Audio;AudioVideo",
|
||||
};
|
||||
//# sourceMappingURL=LinuxTargetHelper.js.map
|
||||
Loading…
Add table
Add a link
Reference in a new issue