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,5 +1,4 @@
/// <reference types="node" />
import { Filter } from "builder-util/out/fs";
import { Filter } from "builder-util";
import { Stats } from "fs-extra";
import { FileMatcher } from "../fileMatcher";
import { Packager } from "../packager";

View file

@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.AppFileWalker = exports.FileCopyHelper = void 0;
const fs_extra_1 = require("fs-extra");
const path = require("path");
const nodeModulesSystemDependentSuffix = `${path.sep}node_modules`;
function addAllPatternIfNeed(matcher) {
if (!matcher.isSpecifiedAsEmptyArray && (matcher.isEmpty() || matcher.containsOnlyIgnore())) {
matcher.prependPattern("**/*");
@ -21,7 +20,7 @@ class FileCopyHelper {
if (!fileStat.isSymbolicLink()) {
return null;
}
return fs_extra_1.readlink(file).then((linkTarget) => {
return (0, fs_extra_1.readlink)(file).then((linkTarget) => {
// http://unix.stackexchange.com/questions/105637/is-symlinks-target-relative-to-the-destinations-parent-directory-and-if-so-wh
return this.handleSymlink(fileStat, file, parent, linkTarget);
});
@ -31,7 +30,7 @@ class FileCopyHelper {
const link = path.relative(this.matcher.from, resolvedLinkTarget);
if (link.startsWith("..")) {
// outside of project, linked module (https://github.com/electron-userland/electron-builder/issues/675)
return fs_extra_1.stat(resolvedLinkTarget).then(targetFileStat => {
return (0, fs_extra_1.stat)(resolvedLinkTarget).then(targetFileStat => {
this.metadata.set(file, targetFileStat);
return targetFileStat;
});
@ -49,19 +48,7 @@ function createAppFilter(matcher, packager) {
if (packager.areNodeModulesHandledExternally) {
return matcher.isEmpty() ? null : matcher.createFilter();
}
const nodeModulesFilter = (file, fileStat) => {
return !(fileStat.isDirectory() && file.endsWith(nodeModulesSystemDependentSuffix));
};
if (matcher.isEmpty()) {
return nodeModulesFilter;
}
const filter = matcher.createFilter();
return (file, fileStat) => {
if (!nodeModulesFilter(file, fileStat)) {
return !!packager.config.includeSubNodeModules;
}
return filter(file, fileStat);
};
return matcher.createFilter();
}
/** @internal */
class AppFileWalker extends FileCopyHelper {
@ -73,18 +60,8 @@ class AppFileWalker extends FileCopyHelper {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
consume(file, fileStat, parent, siblingNames) {
if (fileStat.isDirectory()) {
// https://github.com/electron-userland/electron-builder/issues/1539
// but do not filter if we inside node_modules dir
// update: solution disabled, node module resolver should support such setup
if (file.endsWith(nodeModulesSystemDependentSuffix)) {
if (!this.packager.config.includeSubNodeModules) {
const matchesFilter = this.matcherFilter(file, fileStat);
if (!matchesFilter) {
// Skip the file
return false;
}
}
}
const matchesFilter = this.matcherFilter(file, fileStat);
return !matchesFilter;
}
else {
// save memory - no need to store stat for directory

File diff suppressed because one or more lines are too long

View file

@ -1,16 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeModuleCopyHelper = void 0;
const bluebird_lst_1 = require("bluebird-lst");
const fs_1 = require("builder-util/out/fs");
const builder_util_1 = require("builder-util");
const fs_1 = require("fs");
const fs_extra_1 = require("fs-extra");
const path = require("path");
const tiny_async_pool_1 = require("tiny-async-pool");
const fileMatcher_1 = require("../fileMatcher");
const platformPackager_1 = require("../platformPackager");
const AppFileWalker_1 = require("./AppFileWalker");
const excludedFiles = new Set([".DS_Store", "node_modules" /* already in the queue */, "CHANGELOG.md", "ChangeLog", "changelog.md", "Changelog.md", "Changelog", "binding.gyp", ".npmignore"].concat(fileMatcher_1.excludedNames.split(",")));
const resolve_1 = require("./resolve");
const excludedFiles = new Set([
".DS_Store",
"node_modules" /* already in the queue */,
"CHANGELOG.md",
"ChangeLog",
"changelog.md",
"Changelog.md",
"Changelog",
"binding.gyp",
".npmignore",
"node_gyp_bins",
].concat(fileMatcher_1.excludedNames.split(",")));
const topLevelExcludedFiles = new Set([
"test.js",
"karma.conf.js",
".coveralls.yml",
"README.md",
@ -21,8 +32,8 @@ const topLevelExcludedFiles = new Set([
"Readme",
"readme",
"test",
"__tests__",
"tests",
"__tests__",
"powered-test",
"example",
"examples",
@ -33,32 +44,37 @@ class NodeModuleCopyHelper extends AppFileWalker_1.FileCopyHelper {
constructor(matcher, packager) {
super(matcher, matcher.isEmpty() ? null : matcher.createFilter(), packager);
}
async collectNodeModules(baseDir, moduleNames, nodeModuleExcludedExts) {
async collectNodeModules(moduleInfo, nodeModuleExcludedExts, destination) {
var _a;
const filter = this.filter;
const metadata = this.metadata;
const onNodeModuleFile = platformPackager_1.resolveFunction(this.packager.config.onNodeModuleFile, "onNodeModuleFile");
const onNodeModuleFile = await (0, resolve_1.resolveFunction)(this.packager.appInfo.type, this.packager.config.onNodeModuleFile, "onNodeModuleFile", await this.packager.getWorkspaceRoot());
const result = [];
const queue = [];
for (const moduleName of moduleNames) {
const tmpPath = baseDir + path.sep + moduleName;
queue.length = 1;
// The path should be corrected in Windows that when the moduleName is Scoped packages named.
const depPath = path.normalize(tmpPath);
queue[0] = depPath;
while (queue.length > 0) {
const dirPath = queue.pop();
const childNames = await fs_extra_1.readdir(dirPath);
childNames.sort();
const isTopLevel = dirPath === depPath;
const dirs = [];
// our handler is async, but we should add sorted files, so, we add file to result not in the mapper, but after map
const sortedFilePaths = await bluebird_lst_1.default.map(childNames, name => {
if (onNodeModuleFile != null) {
onNodeModuleFile(dirPath + path.sep + name);
}
if (excludedFiles.has(name) || name.startsWith("._")) {
return null;
}
const emptyDirs = new Set();
const symlinkFiles = new Map();
const tmpPath = moduleInfo.dir;
const moduleName = moduleInfo.name;
queue.length = 1;
// The path should be corrected in Windows that when the moduleName is Scoped packages named.
const depPath = path.normalize(tmpPath);
queue[0] = depPath;
while (queue.length > 0) {
const dirPath = queue.pop();
const childNames = await (0, fs_extra_1.readdir)(dirPath);
childNames.sort();
const isTopLevel = dirPath === depPath;
const dirs = [];
// our handler is async, but we should add sorted files, so, we add file to result not in the mapper, but after map
const sortedFilePaths = await (0, tiny_async_pool_1.default)(builder_util_1.MAX_FILE_REQUESTS, childNames, async (name) => {
const filePath = path.join(dirPath, name);
const forceIncluded = onNodeModuleFile != null && !!onNodeModuleFile(filePath);
if (excludedFiles.has(name) || name.startsWith("._")) {
return null;
}
// check if filematcher matches the files array as more important than the default excluded files.
const fileMatched = filter != null && filter(dirPath, (0, fs_extra_1.lstatSync)(dirPath));
if (!fileMatched || !forceIncluded || !!this.packager.config.disableDefaultIgnoredFiles) {
for (const ext of nodeModuleExcludedExts) {
if (name.endsWith(ext)) {
return null;
@ -82,50 +98,67 @@ class NodeModuleCopyHelper extends AppFileWalker_1.FileCopyHelper {
else if (dirPath.endsWith("lzma-native") && (name === "build" || name === "deps")) {
return null;
}
const filePath = dirPath + path.sep + name;
return fs_extra_1.lstat(filePath).then(stat => {
if (filter != null && !filter(filePath, stat)) {
}
return (0, fs_extra_1.lstat)(filePath).then((stat) => {
stat.moduleName = moduleName;
stat.moduleRootPath = destination;
stat.moduleFullFilePath = path.join(destination, path.relative(depPath, filePath));
if (filter != null && !filter(filePath, stat)) {
return null;
}
if (!stat.isDirectory()) {
metadata.set(filePath, stat);
}
const consumerResult = this.handleFile(filePath, dirPath, stat);
if (consumerResult == null) {
if (stat.isDirectory()) {
dirs.push(name);
return null;
}
if (!stat.isDirectory()) {
metadata.set(filePath, stat);
else {
return filePath;
}
const consumerResult = this.handleFile(filePath, dirPath, stat);
if (consumerResult == null) {
if (stat.isDirectory()) {
}
else {
return consumerResult.then(it => {
// asarUtil can return modified stat (symlink handling)
if ((it == null ? stat : it).isDirectory()) {
dirs.push(name);
return null;
}
else {
return filePath;
}
}
else {
return consumerResult.then(it => {
// asarUtil can return modified stat (symlink handling)
if ((it == null ? stat : it).isDirectory()) {
dirs.push(name);
return null;
}
else {
return filePath;
}
});
}
});
}, fs_1.CONCURRENCY);
for (const child of sortedFilePaths) {
if (child != null) {
result.push(child);
});
}
}
dirs.sort();
for (const child of dirs) {
queue.push(dirPath + path.sep + child);
});
});
let isEmpty = true;
for (const child of sortedFilePaths) {
if (child != null) {
result.push(child);
if ((_a = this.metadata.get(child)) === null || _a === void 0 ? void 0 : _a.isSymbolicLink()) {
symlinkFiles.set(child, result.length - 1);
}
isEmpty = false;
}
}
if (isEmpty) {
emptyDirs.add(dirPath);
}
dirs.sort();
for (const child of dirs) {
queue.push(dirPath + path.sep + child);
}
}
return result;
for (const [file, index] of symlinkFiles) {
const resolvedPath = (0, fs_1.realpathSync)(file);
if (emptyDirs.has(resolvedPath)) {
// delete symlink file if target is a empty dir
result[index] = undefined;
}
}
return result.filter((it) => it !== undefined);
}
}
exports.NodeModuleCopyHelper = NodeModuleCopyHelper;

File diff suppressed because one or more lines are too long

View file

@ -1,7 +0,0 @@
/// <reference types="node" />
import { SpawnOptions } from "child_process";
export declare function executeAppBuilderAsJson<T>(args: Array<string>): Promise<T>;
export declare function executeAppBuilderAndWriteJson(args: Array<string>, data: any, extraOptions?: SpawnOptions): Promise<string>;
export declare function objectToArgs(to: Array<string>, argNameToValue: {
[key: string]: string | null;
}): void;

View file

@ -1,37 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.objectToArgs = exports.executeAppBuilderAndWriteJson = exports.executeAppBuilderAsJson = void 0;
const builder_util_1 = require("builder-util");
function executeAppBuilderAsJson(args) {
return builder_util_1.executeAppBuilder(args).then(rawResult => {
if (rawResult === "") {
return Object.create(null);
}
try {
return JSON.parse(rawResult);
}
catch (e) {
throw new Error(`Cannot parse result: ${e.message}: "${rawResult}"`);
}
});
}
exports.executeAppBuilderAsJson = executeAppBuilderAsJson;
function executeAppBuilderAndWriteJson(args, data, extraOptions = {}) {
return builder_util_1.executeAppBuilder(args, childProcess => {
childProcess.stdin.end(JSON.stringify(data));
}, {
...extraOptions,
stdio: ["pipe", "pipe", process.stdout],
});
}
exports.executeAppBuilderAndWriteJson = executeAppBuilderAndWriteJson;
function objectToArgs(to, argNameToValue) {
for (const name of Object.keys(argNameToValue)) {
const value = argNameToValue[name];
if (value != null) {
to.push(`--${name}`, value);
}
}
}
exports.objectToArgs = objectToArgs;
//# sourceMappingURL=appBuilder.js.map

View file

@ -1 +0,0 @@
{"version":3,"file":"appBuilder.js","sourceRoot":"","sources":["../../src/util/appBuilder.ts"],"names":[],"mappings":";;;AAAA,+CAAgD;AAGhD,SAAgB,uBAAuB,CAAI,IAAmB;IAC5D,OAAO,gCAAiB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE;QAC9C,IAAI,SAAS,KAAK,EAAE,EAAE;YACpB,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAM,CAAA;SAChC;QAED,IAAI;YACF,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,CAAM,CAAA;SAClC;QAAC,OAAO,CAAC,EAAE;YACV,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC,OAAO,MAAM,SAAS,GAAG,CAAC,CAAA;SACrE;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAZD,0DAYC;AAED,SAAgB,6BAA6B,CAAC,IAAmB,EAAE,IAAS,EAAE,eAA6B,EAAE;IAC3G,OAAO,gCAAiB,CACtB,IAAI,EACJ,YAAY,CAAC,EAAE;QACb,YAAY,CAAC,KAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAA;IAC/C,CAAC,EACD;QACE,GAAG,YAAY;QACf,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC;KACxC,CACF,CAAA;AACH,CAAC;AAXD,sEAWC;AAED,SAAgB,YAAY,CAAC,EAAiB,EAAE,cAAgD;IAC9F,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE;QAC9C,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;QAClC,IAAI,KAAK,IAAI,IAAI,EAAE;YACjB,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,KAAK,CAAC,CAAA;SAC5B;KACF;AACH,CAAC;AAPD,oCAOC","sourcesContent":["import { executeAppBuilder } from \"builder-util\"\nimport { SpawnOptions } from \"child_process\"\n\nexport function executeAppBuilderAsJson<T>(args: Array<string>): Promise<T> {\n return executeAppBuilder(args).then(rawResult => {\n if (rawResult === \"\") {\n return Object.create(null) as T\n }\n\n try {\n return JSON.parse(rawResult) as T\n } catch (e) {\n throw new Error(`Cannot parse result: ${e.message}: \"${rawResult}\"`)\n }\n })\n}\n\nexport function executeAppBuilderAndWriteJson(args: Array<string>, data: any, extraOptions: SpawnOptions = {}): Promise<string> {\n return executeAppBuilder(\n args,\n childProcess => {\n childProcess.stdin!.end(JSON.stringify(data))\n },\n {\n ...extraOptions,\n stdio: [\"pipe\", \"pipe\", process.stdout],\n }\n )\n}\n\nexport function objectToArgs(to: Array<string>, argNameToValue: { [key: string]: string | null }): void {\n for (const name of Object.keys(argNameToValue)) {\n const value = argNameToValue[name]\n if (value != null) {\n to.push(`--${name}`, value)\n }\n }\n}\n"]}

View file

@ -1,5 +1,4 @@
/// <reference types="node" />
import { FileTransformer } from "builder-util/out/fs";
import { FileTransformer } from "builder-util";
import { Stats } from "fs";
import { FileMatcher } from "../fileMatcher";
import { Packager } from "../packager";

View file

@ -1,15 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeNodeModuleFileSets = exports.computeFileSets = exports.transformFiles = exports.copyAppFiles = exports.getDestinationPath = exports.ELECTRON_COMPILE_SHIM_FILENAME = void 0;
const bluebird_lst_1 = require("bluebird-lst");
exports.ELECTRON_COMPILE_SHIM_FILENAME = void 0;
exports.getDestinationPath = getDestinationPath;
exports.copyAppFiles = copyAppFiles;
exports.transformFiles = transformFiles;
exports.computeFileSets = computeFileSets;
exports.computeNodeModuleFileSets = computeNodeModuleFileSets;
const builder_util_1 = require("builder-util");
const fs_1 = require("builder-util/out/fs");
const fs_extra_1 = require("fs-extra");
const promises_1 = require("fs/promises");
const path = require("path");
const tiny_async_pool_1 = require("tiny-async-pool");
const unpackDetector_1 = require("../asar/unpackDetector");
const core_1 = require("../core");
const fileMatcher_1 = require("../fileMatcher");
const fileTransformer_1 = require("../fileTransformer");
const node_module_collector_1 = require("../node-module-collector");
const moduleManager_1 = require("../node-module-collector/moduleManager");
const AppFileWalker_1 = require("./AppFileWalker");
const NodeModuleCopyHelper_1 = require("./NodeModuleCopyHelper");
const BOWER_COMPONENTS_PATTERN = `${path.sep}bower_components${path.sep}`;
@ -19,36 +26,21 @@ function getDestinationPath(file, fileSet) {
if (file === fileSet.src) {
return fileSet.destination;
}
else {
const src = fileSet.src;
const dest = fileSet.destination;
if (file.length > src.length && file.startsWith(src) && file[src.length] === path.sep) {
return dest + file.substring(src.length);
}
else {
// hoisted node_modules
// not lastIndexOf, to ensure that nested module (top-level module depends on) copied to parent node_modules, not to top-level directory
// project https://github.com/angexis/punchcontrol/commit/cf929aba55c40d0d8901c54df7945e1d001ce022
let index = file.indexOf(fileTransformer_1.NODE_MODULES_PATTERN);
if (index < 0 && file.endsWith(`${path.sep}node_modules`)) {
index = file.length - 13;
}
if (index < 0) {
throw new Error(`File "${file}" not under the source directory "${fileSet.src}"`);
}
return dest + file.substring(index);
}
const src = fileSet.src;
const dest = fileSet.destination;
// get node_modules path relative to src and then append to dest
if (file.startsWith(src)) {
return path.join(dest, path.relative(src, file));
}
return dest;
}
exports.getDestinationPath = getDestinationPath;
async function copyAppFiles(fileSet, packager, transformer) {
const metadata = fileSet.metadata;
// search auto unpacked dir
const taskManager = new builder_util_1.AsyncTaskManager(packager.cancellationToken);
const createdParentDirs = new Set();
const fileCopier = new fs_1.FileCopier(file => {
// https://github.com/electron-userland/electron-builder/issues/3038
return !(unpackDetector_1.isLibOrExe(file) || file.endsWith(".node"));
const fileCopier = new builder_util_1.FileCopier(file => {
return !(0, unpackDetector_1.isLibOrExe)(file);
}, transformer);
const links = [];
for (let i = 0, n = fileSet.files.length; i < n; i++) {
@ -60,27 +52,24 @@ async function copyAppFiles(fileSet, packager, transformer) {
}
const destinationFile = getDestinationPath(sourceFile, fileSet);
if (stat.isSymbolicLink()) {
links.push({ file: destinationFile, link: await promises_1.readlink(sourceFile) });
links.push({ file: destinationFile, link: await (0, promises_1.readlink)(sourceFile) });
continue;
}
const fileParent = path.dirname(destinationFile);
if (!createdParentDirs.has(fileParent)) {
createdParentDirs.add(fileParent);
await promises_1.mkdir(fileParent, { recursive: true });
await (0, promises_1.mkdir)(fileParent, { recursive: true });
}
taskManager.addTask(fileCopier.copy(sourceFile, destinationFile, stat));
if (taskManager.tasks.length > fs_1.MAX_FILE_REQUESTS) {
if (taskManager.tasks.length > builder_util_1.MAX_FILE_REQUESTS) {
await taskManager.awaitTasks();
}
}
if (taskManager.tasks.length > 0) {
await taskManager.awaitTasks();
}
if (links.length > 0) {
await bluebird_lst_1.default.map(links, it => promises_1.symlink(it.link, it.file), fs_1.CONCURRENCY);
}
await (0, tiny_async_pool_1.default)(builder_util_1.MAX_FILE_REQUESTS, links, it => (0, fs_extra_1.ensureSymlink)(it.link, it.file));
}
exports.copyAppFiles = copyAppFiles;
// used only for ASAR, if no asar, file transformed on the fly
async function transformFiles(transformer, fileSet) {
if (transformer == null) {
@ -92,39 +81,40 @@ async function transformFiles(transformer, fileSet) {
fileSet.transformedFiles = transformedFiles;
}
const metadata = fileSet.metadata;
await bluebird_lst_1.default.filter(fileSet.files, (it, index) => {
const filesPromise = fileSet.files.map(async (it, index) => {
const fileStat = metadata.get(it);
if (fileStat == null || !fileStat.isFile()) {
return false;
return;
}
const transformedValue = transformer(it);
if (transformedValue == null) {
return false;
return;
}
if (typeof transformedValue === "object" && "then" in transformedValue) {
return transformedValue.then(it => {
if (it != null) {
transformedFiles.set(index, it);
}
return false;
return;
});
}
transformedFiles.set(index, transformedValue);
return false;
}, fs_1.CONCURRENCY);
return;
});
// `asyncPool` doesn't provide `index` in it's handler, so we `map` first before using it
await (0, tiny_async_pool_1.default)(builder_util_1.MAX_FILE_REQUESTS, filesPromise, promise => promise);
}
exports.transformFiles = transformFiles;
async function computeFileSets(matchers, transformer, platformPackager, isElectronCompile) {
const fileSets = [];
const packager = platformPackager.info;
for (const matcher of matchers) {
const fileWalker = new AppFileWalker_1.AppFileWalker(matcher, packager);
const fromStat = await fs_1.statOrNull(matcher.from);
const fromStat = await (0, builder_util_1.statOrNull)(matcher.from);
if (fromStat == null) {
builder_util_1.log.debug({ directory: matcher.from, reason: "doesn't exist" }, `skipped copying`);
continue;
}
const files = await fs_1.walk(matcher.from, fileWalker.filter, fileWalker);
const files = await (0, builder_util_1.walk)(matcher.from, fileWalker.filter, fileWalker);
const metadata = fileWalker.metadata;
fileSets.push(validateFileSet({ src: matcher.from, files, metadata, destination: matcher.to }));
}
@ -134,7 +124,6 @@ async function computeFileSets(matchers, transformer, platformPackager, isElectr
}
return fileSets;
}
exports.computeFileSets = computeFileSets;
function getNodeModuleExcludedExts(platformPackager) {
// do not exclude *.h files (https://github.com/electron-userland/electron-builder/issues/2852)
const result = [".o", ".obj"].concat(fileMatcher_1.excludedExts.split(",").map(it => `.${it}`));
@ -156,45 +145,89 @@ function validateFileSet(fileSet) {
}
/** @internal */
async function computeNodeModuleFileSets(platformPackager, mainMatcher) {
const deps = await platformPackager.info.getNodeDependencyInfo(platformPackager.platform).value;
const deps = await collectNodeModulesWithLogging(platformPackager);
const nodeModuleExcludedExts = getNodeModuleExcludedExts(platformPackager);
// serial execution because copyNodeModules is concurrent and so, no need to increase queue/pressure
const result = new Array();
let index = 0;
for (const info of deps) {
const source = info.dir;
const destination = getDestinationPath(source, { src: mainMatcher.from, destination: mainMatcher.to, files: [], metadata: null });
// use main matcher patterns, so, user can exclude some files in such hoisted node modules
// source here includes node_modules, but pattern base should be without because users expect that pattern "!node_modules/loot-core/src{,/**/*}" will work
const matcher = new fileMatcher_1.FileMatcher(path.dirname(source), destination, mainMatcher.macroExpander, mainMatcher.patterns);
const NODE_MODULES = "node_modules";
const collectNodeModules = async (dep, destination) => {
const source = dep.dir;
const matcher = new fileMatcher_1.FileMatcher(source, destination, mainMatcher.macroExpander, mainMatcher.patterns);
const copier = new NodeModuleCopyHelper_1.NodeModuleCopyHelper(matcher, platformPackager.info);
const files = await copier.collectNodeModules(source, info.deps.map(it => it.name), nodeModuleExcludedExts);
const files = await copier.collectNodeModules(dep, nodeModuleExcludedExts, path.relative(mainMatcher.to, destination));
result[index++] = validateFileSet({ src: source, destination, files, metadata: copier.metadata });
builder_util_1.log.debug({ dep: dep.name, from: builder_util_1.log.filePath(source), to: builder_util_1.log.filePath(destination), filesCount: files.length }, "identified module");
if (dep.dependencies) {
for (const c of dep.dependencies) {
await collectNodeModules(c, path.join(destination, NODE_MODULES, c.name));
}
}
};
for (const dep of deps) {
const destination = path.join(mainMatcher.to, NODE_MODULES, dep.name);
await collectNodeModules(dep, destination);
}
return result;
}
exports.computeNodeModuleFileSets = computeNodeModuleFileSets;
async function collectNodeModulesWithLogging(platformPackager) {
var _a, _b, _c;
const packager = platformPackager.info;
const { tempDirManager, appDir, projectDir } = packager;
let deps = undefined;
const searchDirectories = Array.from(new Set([appDir, projectDir, await packager.getWorkspaceRoot()])).filter((it) => (0, builder_util_1.isEmptyOrSpaces)(it) === false);
const pmApproaches = [await packager.getPackageManager(), node_module_collector_1.PM.TRAVERSAL];
for (const pm of pmApproaches) {
for (const dir of searchDirectories) {
builder_util_1.log.info({ pm, searchDir: dir }, "searching for node modules");
const collector = (0, node_module_collector_1.getCollectorByPackageManager)(pm, dir, tempDirManager);
deps = await collector.getNodeModules({ packageName: packager.nodePackageName });
if (deps.nodeModules.length > 0) {
break;
}
const attempt = searchDirectories.indexOf(dir);
if (attempt < searchDirectories.length - 1) {
builder_util_1.log.info({ searchDir: dir, attempt }, "no node modules found in collection, trying next search directory");
}
}
if ((_a = deps === null || deps === void 0 ? void 0 : deps.nodeModules) === null || _a === void 0 ? void 0 : _a.length) {
builder_util_1.log.debug({ pm, nodeModules: deps.nodeModules }, "collected node modules");
break;
}
}
if (!((_b = deps === null || deps === void 0 ? void 0 : deps.nodeModules) === null || _b === void 0 ? void 0 : _b.length)) {
builder_util_1.log.warn({ searchDirectories: searchDirectories.map(it => builder_util_1.log.filePath(it)) }, "no node modules returned while searching directories");
return [];
}
const summary = Object.entries((_c = deps.logSummary) !== null && _c !== void 0 ? _c : {}).filter(([, dependencies]) => Array.isArray(dependencies) && dependencies.length > 0);
for (const [errorMessage, dependencies] of summary) {
const logLevel = moduleManager_1.logMessageLevelByKey[errorMessage] || "debug";
builder_util_1.log[logLevel]({ dependencies }, errorMessage);
}
return deps.nodeModules;
}
async function compileUsingElectronCompile(mainFileSet, packager) {
builder_util_1.log.info("compiling using electron-compile");
const electronCompileCache = await packager.tempDirManager.getTempDir({ prefix: "electron-compile-cache" });
const cacheDir = path.join(electronCompileCache, ".cache");
// clear and create cache dir
await promises_1.mkdir(cacheDir, { recursive: true });
const compilerHost = await fileTransformer_1.createElectronCompilerHost(mainFileSet.src, cacheDir);
await (0, promises_1.mkdir)(cacheDir, { recursive: true });
const compilerHost = await (0, fileTransformer_1.createElectronCompilerHost)(mainFileSet.src, cacheDir);
const nextSlashIndex = mainFileSet.src.length + 1;
// pre-compute electron-compile to cache dir - we need to process only subdirectories, not direct files of app dir
await bluebird_lst_1.default.map(mainFileSet.files, file => {
const filesPromise = mainFileSet.files.map(file => {
if (file.includes(fileTransformer_1.NODE_MODULES_PATTERN) ||
file.includes(BOWER_COMPONENTS_PATTERN) ||
!file.includes(path.sep, nextSlashIndex) || // ignore not root files
!mainFileSet.metadata.get(file).isFile()) {
return null;
return;
}
return compilerHost.compile(file).then(() => null);
}, fs_1.CONCURRENCY);
return compilerHost.compile(file);
});
await (0, tiny_async_pool_1.default)(builder_util_1.MAX_FILE_REQUESTS, filesPromise, promise => promise);
await compilerHost.saveConfiguration();
const metadata = new Map();
const cacheFiles = await fs_1.walk(cacheDir, file => !file.startsWith("."), {
const cacheFiles = await (0, builder_util_1.walk)(cacheDir, file => !file.startsWith("."), {
consume: (file, fileStat) => {
if (fileStat.isFile()) {
metadata.set(file, fileStat);

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,33 @@
import { Nullish } from "builder-util-runtime";
type Handler = (...args: any[]) => Promise<void> | void;
export type HandlerType = "system" | "user";
type Handle = {
handler: Handler;
type: HandlerType;
};
export type EventMap = {
[key: string]: Handler;
};
interface TypedEventEmitter<Events extends EventMap> {
on<E extends keyof Events>(event: E, listener: Events[E] | Nullish, type: HandlerType): this;
off<E extends keyof Events>(event: E, listener: Events[E] | Nullish): this;
emit<E extends keyof Events>(event: E, ...args: Parameters<Events[E]>): Promise<{
emittedSystem: boolean;
emittedUser: boolean;
}>;
filterListeners<E extends keyof Events>(event: E, type: HandlerType): Handle[];
clear(): void;
}
export declare class AsyncEventEmitter<T extends EventMap> implements TypedEventEmitter<T> {
private readonly listeners;
private readonly cancellationToken;
on<E extends keyof T>(event: E, listener: T[E] | Nullish, type?: HandlerType): this;
off<E extends keyof T>(event: E, listener: T[E] | Nullish): this;
emit<E extends keyof T>(event: E, ...args: Parameters<T[E]>): Promise<{
emittedSystem: boolean;
emittedUser: boolean;
}>;
filterListeners<E extends keyof T>(event: E, type: HandlerType | undefined): Handle[];
clear(): void;
}
export {};

View file

@ -0,0 +1,63 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AsyncEventEmitter = void 0;
const builder_util_1 = require("builder-util");
const builder_util_runtime_1 = require("builder-util-runtime");
class AsyncEventEmitter {
constructor() {
this.listeners = new Map();
this.cancellationToken = new builder_util_runtime_1.CancellationToken();
}
on(event, listener, type = "system") {
var _a;
if (!listener) {
return this;
}
const listeners = (_a = this.listeners.get(event)) !== null && _a !== void 0 ? _a : [];
listeners.push({ handler: listener, type });
this.listeners.set(event, listeners);
return this;
}
off(event, listener) {
var _a;
const listeners = (_a = this.listeners.get(event)) === null || _a === void 0 ? void 0 : _a.filter(l => l.handler !== listener);
if (!(listeners === null || listeners === void 0 ? void 0 : listeners.length)) {
this.listeners.delete(event);
return this;
}
this.listeners.set(event, listeners);
return this;
}
async emit(event, ...args) {
const result = { emittedSystem: false, emittedUser: false };
const eventListeners = this.listeners.get(event) || [];
if (!eventListeners.length) {
builder_util_1.log.debug({ event }, "no event listeners found");
return result;
}
const emitInternal = async (listeners) => {
for (const listener of listeners) {
if (this.cancellationToken.cancelled) {
return false;
}
const handler = await Promise.resolve(listener.handler);
await Promise.resolve(handler === null || handler === void 0 ? void 0 : handler(...args));
}
return true;
};
result.emittedSystem = await emitInternal(eventListeners.filter(l => l.type === "system"));
// user handlers are always last
result.emittedUser = await emitInternal(eventListeners.filter(l => l.type === "user"));
return result;
}
filterListeners(event, type) {
var _a;
const listeners = (_a = this.listeners.get(event)) !== null && _a !== void 0 ? _a : [];
return type ? listeners.filter(l => l.type === type) : listeners;
}
clear() {
this.listeners.clear();
}
}
exports.AsyncEventEmitter = AsyncEventEmitter;
//# sourceMappingURL=asyncEventEmitter.js.map

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
import { Nullish } from "builder-util-runtime";
export interface ToolInfo {
path: string;
env?: any;
}
export declare function computeEnv(oldValue: string | null | undefined, newValues: Array<string>): string;
export declare function computeEnv(oldValue: string | Nullish, newValues: Array<string>): string;
export declare function computeToolEnv(libPath: Array<string>): any;

View file

@ -1,6 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeToolEnv = exports.computeEnv = void 0;
exports.computeEnv = computeEnv;
exports.computeToolEnv = computeToolEnv;
const builder_util_1 = require("builder-util");
function computeEnv(oldValue, newValues) {
const parsedOldValue = oldValue ? oldValue.split(":") : [];
return newValues
@ -8,13 +10,11 @@ function computeEnv(oldValue, newValues) {
.filter(it => it.length > 0)
.join(":");
}
exports.computeEnv = computeEnv;
function computeToolEnv(libPath) {
// noinspection SpellCheckingInspection
return {
...process.env,
...(0, builder_util_1.stripSensitiveEnvVars)(process.env),
DYLD_LIBRARY_PATH: computeEnv(process.env.DYLD_LIBRARY_PATH, libPath),
};
}
exports.computeToolEnv = computeToolEnv;
//# sourceMappingURL=bundledTool.js.map

View file

@ -1 +1 @@
{"version":3,"file":"bundledTool.js","sourceRoot":"","sources":["../../src/util/bundledTool.ts"],"names":[],"mappings":";;;AAKA,SAAgB,UAAU,CAAC,QAAmC,EAAE,SAAwB;IACtF,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAC1D,OAAO,SAAS;SACb,MAAM,CAAC,cAAc,CAAC;SACtB,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC;AAND,gCAMC;AAED,SAAgB,cAAc,CAAC,OAAsB;IACnD,uCAAuC;IACvC,OAAO;QACL,GAAG,OAAO,CAAC,GAAG;QACd,iBAAiB,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC;KACtE,CAAA;AACH,CAAC;AAND,wCAMC","sourcesContent":["export interface ToolInfo {\n path: string\n env?: any\n}\n\nexport function computeEnv(oldValue: string | null | undefined, newValues: Array<string>): string {\n const parsedOldValue = oldValue ? oldValue.split(\":\") : []\n return newValues\n .concat(parsedOldValue)\n .filter(it => it.length > 0)\n .join(\":\")\n}\n\nexport function computeToolEnv(libPath: Array<string>): any {\n // noinspection SpellCheckingInspection\n return {\n ...process.env,\n DYLD_LIBRARY_PATH: computeEnv(process.env.DYLD_LIBRARY_PATH, libPath),\n }\n}\n"]}
{"version":3,"file":"bundledTool.js","sourceRoot":"","sources":["../../src/util/bundledTool.ts"],"names":[],"mappings":";;AAQA,gCAMC;AAED,wCAMC;AAtBD,+CAAoD;AAQpD,SAAgB,UAAU,CAAC,QAA0B,EAAE,SAAwB;IAC7E,MAAM,cAAc,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAC1D,OAAO,SAAS;SACb,MAAM,CAAC,cAAc,CAAC;SACtB,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;SAC3B,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC;AAED,SAAgB,cAAc,CAAC,OAAsB;IACnD,uCAAuC;IACvC,OAAO;QACL,GAAG,IAAA,oCAAqB,EAAC,OAAO,CAAC,GAAG,CAAC;QACrC,iBAAiB,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,OAAO,CAAC;KACtE,CAAA;AACH,CAAC","sourcesContent":["import { stripSensitiveEnvVars } from \"builder-util\"\nimport { Nullish } from \"builder-util-runtime\"\n\nexport interface ToolInfo {\n path: string\n env?: any\n}\n\nexport function computeEnv(oldValue: string | Nullish, newValues: Array<string>): string {\n const parsedOldValue = oldValue ? oldValue.split(\":\") : []\n return newValues\n .concat(parsedOldValue)\n .filter(it => it.length > 0)\n .join(\":\")\n}\n\nexport function computeToolEnv(libPath: Array<string>): any {\n // noinspection SpellCheckingInspection\n return {\n ...stripSensitiveEnvVars(process.env),\n DYLD_LIBRARY_PATH: computeEnv(process.env.DYLD_LIBRARY_PATH, libPath),\n }\n}\n"]}

View file

@ -1,4 +1,3 @@
/// <reference types="node" />
import { Arch } from "builder-util";
import { Hash } from "crypto";
export interface BuildCacheInfo {

View file

@ -1,10 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.digest = exports.BuildCacheManager = void 0;
const bluebird_lst_1 = require("bluebird-lst");
exports.BuildCacheManager = void 0;
exports.digest = digest;
const builder_util_1 = require("builder-util");
const fs_1 = require("builder-util/out/fs");
const promise_1 = require("builder-util/out/promise");
const fs_extra_1 = require("fs-extra");
const promises_1 = require("fs/promises");
const path = require("path");
@ -19,7 +17,7 @@ class BuildCacheManager {
}
async copyIfValid(digest) {
this.newDigest = digest;
this.cacheInfo = await promise_1.orNullIfFileNotExist(fs_extra_1.readJson(this.cacheInfoFile));
this.cacheInfo = await (0, builder_util_1.orNullIfFileNotExist)((0, fs_extra_1.readJson)(this.cacheInfoFile));
const oldDigest = this.cacheInfo == null ? null : this.cacheInfo.executableDigest;
if (oldDigest !== digest) {
builder_util_1.log.debug({ oldDigest, newDigest: digest }, "no valid cached executable found");
@ -27,7 +25,7 @@ class BuildCacheManager {
}
builder_util_1.log.debug({ cacheFile: this.cacheFile, file: this.executableFile }, `copying cached executable`);
try {
await fs_1.copyFile(this.cacheFile, this.executableFile, false);
await (0, builder_util_1.copyFile)(this.cacheFile, this.executableFile, false);
return true;
}
catch (e) {
@ -51,8 +49,8 @@ class BuildCacheManager {
this.cacheInfo.executableDigest = this.newDigest;
}
try {
await promises_1.mkdir(this.cacheDir, { recursive: true });
await Promise.all([fs_extra_1.writeJson(this.cacheInfoFile, this.cacheInfo), fs_1.copyFile(this.executableFile, this.cacheFile, false)]);
await (0, promises_1.mkdir)(this.cacheDir, { recursive: true });
await Promise.all([(0, fs_extra_1.writeJson)(this.cacheInfoFile, this.cacheInfo), (0, builder_util_1.copyFile)(this.executableFile, this.cacheFile, false)]);
}
catch (e) {
builder_util_1.log.warn({ error: e.stack || e }, `cannot save build cache`);
@ -63,11 +61,10 @@ exports.BuildCacheManager = BuildCacheManager;
BuildCacheManager.VERSION = "0";
async function digest(hash, files) {
// do not use pipe - better do bulk file read (https://github.com/yarnpkg/yarn/commit/7a63e0d23c46a4564bc06645caf8a59690f04d01)
for (const content of await bluebird_lst_1.default.map(files, it => promises_1.readFile(it))) {
for (const content of await Promise.all(files.map(it => (0, promises_1.readFile)(it)))) {
hash.update(content);
}
hash.update(BuildCacheManager.VERSION);
return hash.digest("base64");
}
exports.digest = digest;
//# sourceMappingURL=cacheManager.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,28 @@
export declare enum CacheState {
pending = "pending",
downloaded = "downloaded",
extracting = "extracting",
extracted = "extracted",
complete = "complete",
corrupted = "corrupted"
}
export interface CacheStateFile {
version: number;
state: CacheState;
timestamp: number;
fileCount: number;
extractedSize: number;
}
export declare function readCacheStateFile(extractDir: string): Promise<CacheStateFile | null>;
export declare function writeCacheState(extractDir: string, state: CacheState, metadata?: {
fileCount?: number;
extractedSize?: number;
}, throwOnError?: boolean): Promise<void>;
export declare function computeCacheMetadata(dir: string): Promise<{
fileCount: number;
extractedSize: number;
}>;
export declare function validateCacheDirectory(extractDir: string, expectedFileCount?: number): Promise<boolean>;
export declare function cleanupCacheDirectory(extractDir: string, { skipLockFiles }?: {
skipLockFiles?: boolean | undefined;
}): Promise<void>;

View file

@ -0,0 +1,143 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CacheState = void 0;
exports.readCacheStateFile = readCacheStateFile;
exports.writeCacheState = writeCacheState;
exports.computeCacheMetadata = computeCacheMetadata;
exports.validateCacheDirectory = validateCacheDirectory;
exports.cleanupCacheDirectory = cleanupCacheDirectory;
const builder_util_1 = require("builder-util");
const fs = require("fs/promises");
const path = require("path");
var CacheState;
(function (CacheState) {
CacheState["pending"] = "pending";
CacheState["downloaded"] = "downloaded";
CacheState["extracting"] = "extracting";
CacheState["extracted"] = "extracted";
CacheState["complete"] = "complete";
CacheState["corrupted"] = "corrupted";
})(CacheState || (exports.CacheState = CacheState = {}));
const STATE_FILE_VERSION = 1;
const STALE_EXTRACTING_TIMEOUT_MS = 120000; // 120 seconds
function getStateFilePath(extractDir) {
return `${extractDir}.state`;
}
async function readCacheStateFile(extractDir) {
const stateFile = getStateFilePath(extractDir);
let content;
try {
content = await fs.readFile(stateFile, "utf-8");
}
catch (e) {
if (e.code !== "ENOENT") {
builder_util_1.log.warn({ stateFile, error: e.message }, "Failed to read cache state file");
}
return null;
}
try {
const data = JSON.parse(content);
if (data.version !== STATE_FILE_VERSION) {
builder_util_1.log.warn({ stateFile, version: data.version, expected: STATE_FILE_VERSION }, "Cache state file version mismatch, ignoring");
return null;
}
if (data.state === CacheState.extracting) {
const age = Date.now() - data.timestamp;
if (age > STALE_EXTRACTING_TIMEOUT_MS) {
builder_util_1.log.warn({ stateFile, age }, "Detected stale extracting state, marking as corrupted");
return { ...data, state: CacheState.corrupted };
}
}
return data;
}
catch (e) {
builder_util_1.log.warn({ stateFile, error: e.message }, "Failed to parse cache state file");
return null;
}
}
async function writeCacheState(extractDir, state, metadata, throwOnError = false) {
var _a, _b;
const stateFile = getStateFilePath(extractDir);
const stateData = {
version: STATE_FILE_VERSION,
state,
timestamp: Date.now(),
fileCount: (_a = metadata === null || metadata === void 0 ? void 0 : metadata.fileCount) !== null && _a !== void 0 ? _a : 0,
extractedSize: (_b = metadata === null || metadata === void 0 ? void 0 : metadata.extractedSize) !== null && _b !== void 0 ? _b : 0,
};
try {
await fs.writeFile(stateFile, JSON.stringify(stateData, null, 2), "utf-8");
}
catch (e) {
builder_util_1.log.warn({ stateFile, error: e.message }, "Failed to write cache state file");
if (throwOnError) {
throw e;
}
}
}
async function computeCacheMetadata(dir) {
let fileCount = 0;
let extractedSize = 0;
const stack = [dir];
while (stack.length > 0) {
const current = stack.pop();
let entries;
try {
entries = await fs.readdir(current, { withFileTypes: true });
}
catch {
continue;
}
for (const entry of entries) {
const fullPath = path.join(current, entry.name);
if (entry.isDirectory()) {
stack.push(fullPath);
}
else {
fileCount++;
if (entry.isFile()) {
try {
const stat = await fs.stat(fullPath);
extractedSize += stat.size;
}
catch {
// ignore stat errors for individual files
}
}
}
}
}
return { fileCount, extractedSize };
}
async function validateCacheDirectory(extractDir, expectedFileCount) {
try {
const topLevel = await fs.readdir(extractDir);
if (topLevel.length === 0) {
return false;
}
if (expectedFileCount != null && expectedFileCount > 0) {
const { fileCount: actual } = await computeCacheMetadata(extractDir);
if (actual < expectedFileCount) {
builder_util_1.log.warn({ extractDir, expected: expectedFileCount, actual }, "Cache file count mismatch (fewer files than expected), treating as invalid");
return false;
}
}
return true;
}
catch (e) {
builder_util_1.log.warn({ extractDir, error: e.message }, "Failed to validate cache directory");
return false;
}
}
async function cleanupCacheDirectory(extractDir, { skipLockFiles = false } = {}) {
const filesToClean = [extractDir, `${extractDir}.state`, `${extractDir}.tmp`, ...(!skipLockFiles ? [`${extractDir}.lock`, `${extractDir}.tmp.lock`] : [])];
for (const file of filesToClean) {
try {
await fs.rm(file, { recursive: true, force: true });
}
catch (e) {
builder_util_1.log.warn({ file, error: e.message }, "Failed to clean up cache file");
}
}
}
//# sourceMappingURL=cacheState.js.map

File diff suppressed because one or more lines are too long

View file

@ -1,13 +0,0 @@
import { DebugLogger } from "builder-util";
import { Lazy } from "lazy-val";
import { Configuration } from "../configuration";
export declare function getConfig(projectDir: string, configPath: string | null, configFromOptions: Configuration | null | undefined, packageMetadata?: Lazy<{
[key: string]: any;
} | null>): Promise<Configuration>;
/**
* `doMergeConfigs` takes configs in the order you would pass them to
* Object.assign as sources.
*/
export declare function doMergeConfigs(configs: Configuration[]): Configuration;
export declare function validateConfig(config: Configuration, debugLogger: DebugLogger): Promise<void>;
export declare function computeDefaultAppDirectory(projectDir: string, userAppDir: string | null | undefined): Promise<string>;

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,12 @@
import { DebugLogger } from "builder-util";
import { Nullish } from "builder-util-runtime";
import { Lazy } from "lazy-val";
import { Configuration } from "../../configuration";
export declare function getConfig(projectDir: string, configPath: string | null, configFromOptions: Configuration | Nullish, packageMetadata?: Lazy<Record<string, any> | null>): Promise<Configuration>;
/**
* `doMergeConfigs` takes configs in the order you would pass them to
* Object.assign as sources.
*/
export declare function doMergeConfigs(configs: Configuration[]): Configuration;
export declare function validateConfiguration(config: Configuration, debugLogger: DebugLogger): Promise<void>;
export declare function computeDefaultAppDirectory(projectDir: string, userAppDir: string | Nullish): Promise<string>;

View file

@ -1,16 +1,18 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeDefaultAppDirectory = exports.validateConfig = exports.doMergeConfigs = exports.getConfig = void 0;
exports.getConfig = getConfig;
exports.doMergeConfigs = doMergeConfigs;
exports.validateConfiguration = validateConfiguration;
exports.computeDefaultAppDirectory = computeDefaultAppDirectory;
const builder_util_1 = require("builder-util");
const fs_1 = require("builder-util/out/fs");
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 = require("path");
const read_config_file_1 = require("read-config-file");
const rectCra_1 = require("../presets/rectCra");
const version_1 = require("../version");
// eslint-disable-next-line @typescript-eslint/no-var-requires
const validateSchema = require("@develar/schema-utils");
const rectCra_1 = require("../../presets/rectCra");
const version_1 = require("../../version");
const load_1 = require("./load");
const schemaValidator_1 = require("./schemaValidator");
// https://github.com/electron-userland/electron-builder/issues/1847
function mergePublish(config, configFromOptions) {
// if config from disk doesn't have publish (or object), no need to handle, it will be simply merged by deepAssign
@ -18,7 +20,7 @@ function mergePublish(config, configFromOptions) {
if (publish != null) {
delete configFromOptions.publish;
}
builder_util_1.deepAssign(config, configFromOptions);
(0, builder_util_runtime_1.deepAssign)(config, configFromOptions);
if (publish == null) {
return;
}
@ -28,12 +30,12 @@ function mergePublish(config, configFromOptions) {
}
else {
// apply to first
Object.assign(listOnDisk[0], publish);
(0, builder_util_runtime_1.deepAssign)(listOnDisk[0], publish);
}
}
async function getConfig(projectDir, configPath, configFromOptions, packageMetadata = new lazy_val_1.Lazy(() => read_config_file_1.orNullIfFileNotExist(fs_extra_1.readJson(path.join(projectDir, "package.json"))))) {
async function getConfig(projectDir, configPath, configFromOptions, packageMetadata = new lazy_val_1.Lazy(() => (0, load_1.orNullIfFileNotExist)((0, fs_extra_1.readJson)(path.join(projectDir, "package.json"))))) {
const configRequest = { packageKey: "build", configFilename: "electron-builder", projectDir, packageMetadata };
const configAndEffectiveFile = await read_config_file_1.getConfig(configRequest, configPath);
const configAndEffectiveFile = await (0, load_1.getConfig)(configRequest, configPath);
const config = configAndEffectiveFile == null ? {} : configAndEffectiveFile.result;
if (configFromOptions != null) {
mergePublish(config, configFromOptions);
@ -53,7 +55,7 @@ async function getConfig(projectDir, configPath, configFromOptions, packageMetad
try {
file = require.resolve(file);
}
catch (ignore) {
catch (_ignore) {
file = require.resolve("electron-webpack/electron-builder.yml");
}
config.extends = `file:${file}`;
@ -61,19 +63,18 @@ async function getConfig(projectDir, configPath, configFromOptions, packageMetad
}
const parentConfigs = await loadParentConfigsRecursively(config.extends, async (configExtend) => {
if (configExtend === "react-cra") {
const result = await rectCra_1.reactCra(projectDir);
const result = await (0, rectCra_1.reactCra)(projectDir);
builder_util_1.log.info({ preset: configExtend }, "loaded parent configuration");
return result;
}
else {
const { configFile, result } = await read_config_file_1.loadParentConfig(configRequest, configExtend);
const { configFile, result } = await (0, load_1.loadParentConfig)(configRequest, configExtend);
builder_util_1.log.info({ file: configFile }, "loaded parent configuration");
return result;
}
});
return doMergeConfigs([...parentConfigs, config]);
}
exports.getConfig = getConfig;
function asArray(value) {
return Array.isArray(value) ? value : typeof value === "string" ? [value] : [];
}
@ -169,7 +170,7 @@ function doMergeConfigs(configs) {
normalizeFiles(config, "extraFiles");
normalizeFiles(config, "extraResources");
}
const result = builder_util_1.deepAssign(getDefaultConfig(), ...configs);
const result = (0, builder_util_runtime_1.deepAssign)(getDefaultConfig(), ...configs);
// `deepAssign` prioritises latter configs, while `mergeFilesSets` prioritises
// former configs, so we have to reverse the order, because latter configs
// must have higher priority.
@ -177,7 +178,6 @@ function doMergeConfigs(configs) {
result.files = mergeFileSets(configs.map(config => { var _a; return ((_a = config.files) !== null && _a !== void 0 ? _a : []); }));
return result;
}
exports.doMergeConfigs = doMergeConfigs;
function getDefaultConfig() {
return {
directories: {
@ -186,8 +186,8 @@ function getDefaultConfig() {
},
};
}
const schemeDataPromise = new lazy_val_1.Lazy(() => fs_extra_1.readJson(path.join(__dirname, "..", "..", "scheme.json")));
async function validateConfig(config, debugLogger) {
const schemeDataPromise = new lazy_val_1.Lazy(() => (0, fs_extra_1.readJson)(path.join(__dirname, "..", "..", "..", "scheme.json")));
async function validateConfiguration(config, debugLogger) {
const extraMetadata = config.extraMetadata;
if (extraMetadata != null) {
if (extraMetadata.build != null) {
@ -204,20 +204,19 @@ async function validateConfig(config, debugLogger) {
if (oldConfig.appImage != null && oldConfig.appImage.systemIntegration != null) {
throw new builder_util_1.InvalidConfigurationError(`appImage.systemIntegration is deprecated, https://github.com/TheAssassin/AppImageLauncher is used for desktop integration"`);
}
// noinspection JSUnusedGlobalSymbols
validateSchema(await schemeDataPromise.value, config, {
(0, schemaValidator_1.validateSchema)(await schemeDataPromise.value, config, {
name: `electron-builder ${version_1.PACKAGE_VERSION}`,
postFormatter: (formattedError, error) => {
var _a, _b;
if (debugLogger.isEnabled) {
debugLogger.add("invalidConfig", builder_util_1.safeStringifyJson(error));
debugLogger.add("invalidConfig", (0, builder_util_1.safeStringifyJson)(error));
}
const site = "https://www.electron.build";
let url = `${site}/configuration/configuration`;
let url = `${site}/configuration`;
const targets = new Set(["mac", "dmg", "pkg", "mas", "win", "nsis", "appx", "linux", "appimage", "snap"]);
const dataPath = error.dataPath == null ? null : error.dataPath;
const targetPath = dataPath.startsWith(".") ? dataPath.substr(1).toLowerCase() : null;
if (targetPath != null && targets.has(targetPath)) {
url = `${site}/configuration/${targetPath}`;
const firstSegment = (_b = ((_a = error.instancePath) !== null && _a !== void 0 ? _a : "").split("/").filter(Boolean)[0]) === null || _b === void 0 ? void 0 : _b.toLowerCase();
if (firstSegment != null && targets.has(firstSegment)) {
url = `${site}/${firstSegment}`;
}
return `${formattedError}\n How to fix:
1. Open ${url}
@ -228,12 +227,11 @@ async function validateConfig(config, debugLogger) {
},
});
}
exports.validateConfig = validateConfig;
const DEFAULT_APP_DIR_NAMES = ["app", "www"];
async function computeDefaultAppDirectory(projectDir, userAppDir) {
if (userAppDir != null) {
const absolutePath = path.resolve(projectDir, userAppDir);
const stat = await fs_1.statOrNull(absolutePath);
const stat = await (0, builder_util_1.statOrNull)(absolutePath);
if (stat == null) {
throw new builder_util_1.InvalidConfigurationError(`Application directory ${userAppDir} doesn't exist`);
}
@ -248,12 +246,11 @@ async function computeDefaultAppDirectory(projectDir, userAppDir) {
for (const dir of DEFAULT_APP_DIR_NAMES) {
const absolutePath = path.join(projectDir, dir);
const packageJson = path.join(absolutePath, "package.json");
const stat = await fs_1.statOrNull(packageJson);
const stat = await (0, builder_util_1.statOrNull)(packageJson);
if (stat != null && stat.isFile()) {
return absolutePath;
}
}
return projectDir;
}
exports.computeDefaultAppDirectory = computeDefaultAppDirectory;
//# sourceMappingURL=config.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,19 @@
import { DotenvParseInput } from "dotenv-expand";
import { Lazy } from "lazy-val";
export interface ReadConfigResult<T> {
readonly result: T;
readonly configFile: string | null;
}
export declare function findAndReadConfig<T>(request: ReadConfigRequest): Promise<ReadConfigResult<T> | null>;
export declare function orNullIfFileNotExist<T>(promise: Promise<T>): Promise<T | null>;
export declare function orIfFileNotExist<T>(promise: Promise<T>, fallbackValue: T): Promise<T>;
export interface ReadConfigRequest {
packageKey: string;
configFilename: string;
projectDir: string;
packageMetadata: Lazy<Record<string, any> | null> | null;
}
export declare function loadConfig<T>(request: ReadConfigRequest): Promise<ReadConfigResult<T> | null>;
export declare function getConfig<T>(request: ReadConfigRequest, configPath?: string | null): Promise<ReadConfigResult<T> | null>;
export declare function loadParentConfig<T>(request: ReadConfigRequest, spec: string): Promise<ReadConfigResult<T>>;
export declare function loadEnv(envFile: string): Promise<DotenvParseInput | null>;

View file

@ -0,0 +1,129 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findAndReadConfig = findAndReadConfig;
exports.orNullIfFileNotExist = orNullIfFileNotExist;
exports.orIfFileNotExist = orIfFileNotExist;
exports.loadConfig = loadConfig;
exports.getConfig = getConfig;
exports.loadParentConfig = loadParentConfig;
exports.loadEnv = loadEnv;
const builder_util_1 = require("builder-util");
const dotenv_1 = require("dotenv");
const dotenv_expand_1 = require("dotenv-expand");
const fs_1 = require("fs");
const jiti_1 = require("jiti");
const js_yaml_1 = require("js-yaml");
const path = require("path");
const resolve_1 = require("../resolve");
const jiti = (0, jiti_1.createJiti)(__filename);
async function readConfig(configFile, request) {
const data = await fs_1.promises.readFile(configFile, "utf8");
let result;
if (configFile.endsWith(".json5") || configFile.endsWith(".json")) {
result = require("json5").parse(data);
}
else if (configFile.endsWith(".js") || configFile.endsWith(".cjs") || configFile.endsWith(".mjs")) {
const json = await orNullIfFileNotExist(fs_1.promises.readFile(path.join(process.cwd(), "package.json"), "utf8"));
const moduleType = json === null ? null : JSON.parse(json).type;
result = await (0, resolve_1.resolveModule)(moduleType, configFile);
if (result.default != null) {
result = result.default;
}
if (typeof result === "function") {
result = result(request);
}
result = await Promise.resolve(result);
}
else if (configFile.endsWith(".ts")) {
result = await jiti.import(configFile, { default: true });
if (typeof result === "function") {
result = result(request);
}
result = await Promise.resolve(result);
}
else if (configFile.endsWith(".toml")) {
result = require("toml").parse(data);
}
else {
result = (0, js_yaml_1.load)(data);
}
return { result, configFile };
}
async function findAndReadConfig(request) {
const prefix = request.configFilename;
for (const configFile of [`${prefix}.yml`, `${prefix}.yaml`, `${prefix}.json`, `${prefix}.json5`, `${prefix}.toml`, `${prefix}.js`, `${prefix}.cjs`, `${prefix}.ts`]) {
const data = await orNullIfFileNotExist(readConfig(path.join(request.projectDir, configFile), request));
if (data != null) {
return data;
}
}
return null;
}
function orNullIfFileNotExist(promise) {
return orIfFileNotExist(promise, null);
}
function orIfFileNotExist(promise, fallbackValue) {
return promise.catch(e => {
if (e.code === "ENOENT" || e.code === "ENOTDIR") {
return fallbackValue;
}
throw e;
});
}
async function loadConfig(request) {
let packageMetadata = request.packageMetadata == null ? null : await request.packageMetadata.value;
if (packageMetadata == null) {
const json = await orNullIfFileNotExist(fs_1.promises.readFile(path.join(request.projectDir, "package.json"), "utf8"));
packageMetadata = json == null ? null : JSON.parse(json);
}
const data = packageMetadata == null ? null : packageMetadata[request.packageKey];
return data == null ? findAndReadConfig(request) : { result: data, configFile: null };
}
function getConfig(request, configPath) {
if (configPath == null) {
return loadConfig(request);
}
else {
return readConfig(path.resolve(request.projectDir, configPath), request);
}
}
async function loadParentConfig(request, spec) {
let isFileSpec;
if (spec.startsWith("file:")) {
spec = spec.substring("file:".length);
isFileSpec = true;
}
let parentConfig = await orNullIfFileNotExist(readConfig(path.resolve(request.projectDir, spec), request));
if (parentConfig == null && isFileSpec !== true) {
let resolved = null;
try {
resolved = require.resolve(spec);
}
catch (_e) {
// ignore
}
if (resolved != null) {
parentConfig = await readConfig(resolved, request);
}
}
if (parentConfig == null) {
throw new Error(`Cannot find parent config file: ${spec}`);
}
return parentConfig;
}
async function loadEnv(envFile) {
const data = await orNullIfFileNotExist(fs_1.promises.readFile(envFile, "utf8"));
if (data == null) {
return null;
}
const parsed = (0, dotenv_1.parse)(data);
builder_util_1.log.info({ envFile }, "injecting environment");
Object.entries(parsed).forEach(([key, value]) => {
if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
process.env[key] = value;
}
});
(0, dotenv_expand_1.expand)({ parsed });
return parsed;
}
//# sourceMappingURL=load.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,7 @@
import { ErrorObject } from "ajv";
export type PostFormatter = (formattedError: string, error: ErrorObject) => string;
export interface ValidationConfig {
name?: string;
postFormatter?: PostFormatter;
}
export declare function validateSchema(schema: unknown, data: unknown, config?: ValidationConfig): void;

View file

@ -0,0 +1,154 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateSchema = validateSchema;
const ajv_1 = require("ajv");
const ajv = new ajv_1.default({
allErrors: true,
verbose: true,
coerceTypes: true,
strict: false,
});
// Cache the compiled validator for the canonical scheme.json so it is only
// compiled once per process lifetime.
let _cachedValidate;
function validateSchema(schema, data, config = {}) {
var _a, _b;
if (_cachedValidate == null || _cachedValidate.schema !== schema) {
_cachedValidate = ajv.compile(schema);
}
const validate = _cachedValidate;
if (validate(data)) {
return;
}
const errors = (_a = validate.errors) !== null && _a !== void 0 ? _a : [];
const baseDataPath = "configuration";
const name = (_b = config.name) !== null && _b !== void 0 ? _b : "Object";
const relevant = filterRelevantErrors(errors);
const formatted = relevant.map(error => {
let msg = formatError(error, baseDataPath);
if (config.postFormatter != null) {
msg = config.postFormatter(msg, error);
}
return ` - ${indentNewlines(msg, " ")}`;
});
const header = `Invalid configuration object. ${name} has been initialized using a configuration object that does not match the API schema.`;
throw new Error(`${header}\n${formatted.join("\n")}`);
}
/**
* Filters the flat list of ajv errors to the most actionable subset.
* Composite keywords (anyOf/oneOf/if) are suppressed when more specific
* errors exist at the same or deeper paths. When all errors share the
* same instancePath and a composite parent for that path exists, the
* parent is kept instead so the user sees a single "should be one of"
* message rather than every failed branch listed separately.
*/
function filterRelevantErrors(errors) {
const compositeKeywords = new Set(["anyOf", "oneOf", "if"]);
const specific = errors.filter(e => !compositeKeywords.has(e.keyword));
if (specific.length === 0) {
return errors.filter(e => compositeKeywords.has(e.keyword));
}
// Group specific errors by instancePath
const byPath = new Map();
for (const e of specific) {
const list = byPath.get(e.instancePath);
if (list != null) {
list.push(e);
}
else {
byPath.set(e.instancePath, [e]);
}
}
const result = [];
for (const [path, group] of byPath) {
// When multiple branch-failures share the same path, prefer the anyOf
// parent error (one concise "should be one of these" message).
if (group.length > 1) {
const parent = errors.find(e => e.instancePath === path && compositeKeywords.has(e.keyword));
if (parent != null) {
result.push(parent);
continue;
}
}
result.push(...group);
}
return result;
}
/** Decodes a single RFC 6901 JSON Pointer segment (`~1` → `/`, `~0` → `~`). */
function decodePointerSegment(segment) {
return segment.replace(/~1/g, "/").replace(/~0/g, "~");
}
function instancePathToLabel(instancePath, baseDataPath) {
if (!instancePath) {
return baseDataPath;
}
const segments = instancePath.split("/").filter(Boolean).map(decodePointerSegment);
return [baseDataPath, ...segments].join(".");
}
function formatError(error, baseDataPath) {
var _a;
const label = instancePathToLabel(error.instancePath, baseDataPath);
const params = error.params;
const parentSchema = error.parentSchema;
switch (error.keyword) {
case "additionalProperties":
return `${label} has an unknown property '${params.additionalProperty}'`;
case "required": {
const missingProp = String(params.missingProperty).replace(/^\./, "");
return `${label} misses the property '${missingProp}'`;
}
case "type": {
const type = params.type;
if (Array.isArray(type)) {
const typeList = type.join(" | ");
const desc = descriptionSuffix(parentSchema);
return `${label} should be:\n${typeList}${desc}`;
}
return `${label} should be a ${type}`;
}
case "enum": {
const enumVals = (_a = parentSchema === null || parentSchema === void 0 ? void 0 : parentSchema.enum) !== null && _a !== void 0 ? _a : [];
if (enumVals.length === 1) {
return `${label} should be ${JSON.stringify(enumVals[0])}`;
}
return `${label} should be one of these:\n${enumVals.map(v => JSON.stringify(v)).join(" | ")}`;
}
case "anyOf":
case "oneOf": {
const schemaText = formatSchemaType(parentSchema);
return `${label} should be one of these:\n${schemaText}`;
}
default:
return `${label} ${error.message}`;
}
}
function descriptionSuffix(schema) {
return typeof (schema === null || schema === void 0 ? void 0 : schema.description) === "string" ? `\n-> ${schema.description}` : "";
}
function formatSchemaType(schema) {
if (schema == null) {
return "";
}
if (Array.isArray(schema.type)) {
return schema.type.join(" | ");
}
if (typeof schema.type === "string") {
return schema.type;
}
if (Array.isArray(schema.anyOf)) {
return schema.anyOf
.map(s => {
if (Array.isArray(s.type)) {
return s.type.join(" | ");
}
return typeof s.type === "string" ? s.type : "";
})
.filter(Boolean)
.join(" | ");
}
return JSON.stringify(schema);
}
function indentNewlines(str, prefix) {
return str.replace(/\n(?!$)/g, `\n${prefix}`);
}
//# sourceMappingURL=schemaValidator.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
export declare function dynamicImport<T = any>(modulePath: string): Promise<T>;

View file

@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.dynamicImport = dynamicImport;
// TypeScript's "module": "CommonJS" compiles `await import(x)` to
// `await Promise.resolve().then(() => require(x))`, which fails for ESM-only
// packages. helpers/dynamic-import.js is plain JS so TypeScript never
// transforms its native import() call — route through it instead.
const _helper = require("../../helpers/dynamic-import");
function dynamicImport(modulePath) {
return _helper.dynamicImport(modulePath);
}
//# sourceMappingURL=dynamicImport.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"dynamicImport.js","sourceRoot":"","sources":["../../src/util/dynamicImport.ts"],"names":[],"mappings":";;AAMA,sCAEC;AARD,kEAAkE;AAClE,6EAA6E;AAC7E,sEAAsE;AACtE,kEAAkE;AAClE,MAAM,OAAO,GAAG,OAAO,CAAC,8BAA8B,CAAkD,CAAA;AAExG,SAAgB,aAAa,CAAU,UAAkB;IACvD,OAAO,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAA;AAC1C,CAAC","sourcesContent":["// TypeScript's \"module\": \"CommonJS\" compiles `await import(x)` to\n// `await Promise.resolve().then(() => require(x))`, which fails for ESM-only\n// packages. helpers/dynamic-import.js is plain JS so TypeScript never\n// transforms its native import() call — route through it instead.\nconst _helper = require(\"../../helpers/dynamic-import\") as { dynamicImport(path: string): Promise<any> }\n\nexport function dynamicImport<T = any>(modulePath: string): Promise<T> {\n return _helper.dynamicImport(modulePath)\n}\n"]}

View file

@ -0,0 +1,61 @@
import { ElectronPlatformArtifactDetails, MirrorOptions } from "@electron/get";
import { ElectronPlatformName } from "../electron/ElectronFramework";
export type ElectronGetOptions = Omit<ElectronPlatformArtifactDetails, "platform" | "arch" | "version" | "artifactName" | "artifactSuffix" | "customFilename" | "tempDirectory" | "downloader" | "cacheMode" | "cacheRoot" | "downloadOptions" | "isGeneric" | "mirrorOptions"> & {
mirrorOptions?: Omit<MirrorOptions, "customDir" | "customFilename" | "customVersion">;
};
export type ArtifactDownloadOptions = {
electronDownload?: ElectronGetOptions | ElectronDownloadOptions | null;
artifactName: string;
platformName: string;
arch: string;
version: string;
cacheDir?: string;
};
export interface ElectronDownloadOptions {
version?: string;
/**
* The [cache location](https://github.com/electron-userland/electron-download#cache-location).
*/
cache?: string | null;
/**
* The mirror.
*/
mirror?: string | null;
/** @private */
customDir?: string | null;
/** @private */
customFilename?: string | null;
/** @private */
strictSSL?: boolean;
/** @private */
isVerifyChecksum?: boolean;
platform?: ElectronPlatformName;
arch?: string;
}
export declare function getCacheDirectory(options: {
isAvoidSystemOnWindows?: boolean;
allowEnvVarOverride: boolean;
}): string;
export declare function extractArchive(file: string, dir: string): Promise<void>;
/**
* Downloads a generic artifact (.tar.gz or .zip) from a GitHub release.
* Used for electron-builder-binaries tools (appimage, etc.).
*/
export declare function downloadBuilderToolset(options: {
releaseName: string;
filenameWithExt: string;
checksums?: Record<string, string>;
githubOrgRepo?: string;
overrideUrl?: string;
}): Promise<string>;
/**
* Downloads the electron artifact zip via @electron/get (with caching) and returns the zip file path.
* Use when you need to extract the zip yourself (e.g. directly to appOutDir to preserve empty dirs and symlinks).
*/
export declare function downloadElectronArtifactZip(options: ArtifactDownloadOptions): Promise<string>;
export declare function downloadElectronArtifact(options: ArtifactDownloadOptions): Promise<string>;
/**
* Get the binaries mirror URL from environment variables.
* Supports various npm config formats and falls back to GitHub.
*/
export declare function getBinariesMirrorUrl(githubOrgRepo: string): string;

View file

@ -0,0 +1,524 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCacheDirectory = getCacheDirectory;
exports.extractArchive = extractArchive;
exports.downloadBuilderToolset = downloadBuilderToolset;
exports.downloadElectronArtifactZip = downloadElectronArtifactZip;
exports.downloadElectronArtifact = downloadElectronArtifact;
exports.getBinariesMirrorUrl = getBinariesMirrorUrl;
const get = require("@electron/get");
const get_1 = require("@electron/get");
const builder_util_1 = require("builder-util");
const _7zip_1 = require("../toolsets/7zip");
const multiProgress_1 = require("electron-publish/out/multiProgress");
const fs_1 = require("fs");
const fs = require("fs/promises");
const crypto = require("crypto");
const os = require("os");
const path = require("path");
const lockfile = require("proper-lockfile");
const promises_1 = require("stream/promises");
const tar = require("tar");
const unzipper = require("unzipper");
const builder_util_runtime_1 = require("builder-util-runtime");
const cacheState_1 = require("./cacheState");
function hashUrlSafe(input, length = 6) {
let hash = 5381;
for (let i = 0; i < input.length; i++) {
hash = ((hash << 5) + hash) ^ input.charCodeAt(i);
}
hash >>>= 0;
const out = hash.toString(36);
return out.length >= length ? out.slice(0, length) : out.padStart(length, "0");
}
function getCacheDirectory(options) {
var _a, _b, _c, _d, _e;
const { isAvoidSystemOnWindows = true, allowEnvVarOverride } = options;
const env = (_a = process.env.ELECTRON_BUILDER_CACHE) === null || _a === void 0 ? void 0 : _a.trim();
if (allowEnvVarOverride && env && path.parse(env).root) {
return env;
}
const appName = "electron-builder";
const platform = os.platform();
const homeDir = os.homedir();
if (platform === "darwin") {
return path.join(homeDir, "Library", "Caches", appName);
}
if (platform === "win32") {
const localAppData = (_b = process.env.LOCALAPPDATA) === null || _b === void 0 ? void 0 : _b.trim();
const username = (_d = (_c = process.env.USERNAME) === null || _c === void 0 ? void 0 : _c.trim()) === null || _d === void 0 ? void 0 : _d.toLowerCase();
// https://github.com/electron-userland/electron-builder/issues/1164
const isSystemUser = isAvoidSystemOnWindows && (((_e = localAppData === null || localAppData === void 0 ? void 0 : localAppData.toLowerCase()) === null || _e === void 0 ? void 0 : _e.includes("\\windows\\system32\\")) || username === "system");
if (!localAppData || isSystemUser) {
return path.join(os.tmpdir(), `${appName}-cache`);
}
return path.join(localAppData, appName, "Cache");
}
const xdgCache = process.env.XDG_CACHE_HOME;
return xdgCache && path.parse(xdgCache).root ? path.join(xdgCache, appName) : path.join(homeDir, ".cache", appName);
}
function resolveCacheMode() {
var _a;
const varName = "ELECTRON_DOWNLOAD_CACHE_MODE";
const cacheOverride = (_a = process.env[varName]) === null || _a === void 0 ? void 0 : _a.trim();
if (cacheOverride && Number(cacheOverride) in get_1.ElectronDownloadCacheMode) {
const mode = Number(cacheOverride);
builder_util_1.log.debug({ mode }, `cache mode overridden via env var ${varName}`);
return mode;
}
return get_1.ElectronDownloadCacheMode.ReadWrite;
}
async function extractZipStreaming(file, dir) {
var _a;
// Pass 1: read central directory once to collect Unix modes (one seek to EOF)
const zipDir = await unzipper.Open.file(file);
const entryModes = new Map();
for (const entry of zipDir.files) {
const mode = (entry.externalFileAttributes >> 16) & 0xffff;
if (mode > 0) {
entryModes.set(entry.path, mode);
}
}
const isSymlink = (mode) => (mode & 0o170000) === 0o120000;
// Pass 2: stream from byte 0 — no per-entry seeks, no Docker hang
const entries = (0, fs_1.createReadStream)(file).pipe(unzipper.Parse({ forceStream: true }));
for await (const entry of entries) {
const destPath = path.resolve(dir, entry.path);
if (!destPath.startsWith(dir + path.sep) && destPath !== dir) {
throw new Error(`Path traversal blocked: ${entry.path}`);
}
const mode = (_a = entryModes.get(entry.path)) !== null && _a !== void 0 ? _a : 0;
if (mode > 0 && isSymlink(mode)) {
const target = (await entry.buffer()).toString();
if (path.isAbsolute(target)) {
throw new Error(`Absolute symlink target blocked: ${target}`);
}
const resolvedTarget = path.resolve(path.dirname(destPath), target);
if (!resolvedTarget.startsWith(dir + path.sep) && resolvedTarget !== dir) {
throw new Error(`Symlink target escapes extraction dir: ${target}`);
}
await fs.mkdir(path.dirname(destPath), { recursive: true });
await fs.symlink(target, destPath);
}
else if (entry.type === "Directory") {
await fs.mkdir(destPath, { recursive: true });
entry.autodrain();
}
else {
await fs.mkdir(path.dirname(destPath), { recursive: true });
await (0, promises_1.pipeline)(entry, (0, fs_1.createWriteStream)(destPath));
if (mode > 0) {
await fs.chmod(destPath, mode & 0o7777);
}
}
}
}
async function extractArchive(file, dir) {
const tmpDir = `${dir}.tmp`;
await fs.mkdir(tmpDir, { recursive: true });
const release = await lockfile.lock(tmpDir, {
// 100 retries (not 15) so concurrent callers wait out a slow first extraction instead of failing
// with ELOCKED; the update heartbeat keeps an in-progress holder's lock fresh against `stale`.
retries: { retries: 100, minTimeout: 1000, maxTimeout: 5000 },
stale: 120000, // Increased from 60s to allow long-running extractions
});
try {
// rm + mkdir happen AFTER acquiring the lock so no concurrent caller can clear our tmpDir mid-extraction
await fs.rm(tmpDir, { recursive: true, force: true });
await fs.mkdir(tmpDir, { recursive: true });
// Guard against the transient window in @electron/get's non-atomic putFileInCache (remove → move).
// A concurrent worker may have deleted and not yet replaced the source archive; wait briefly for it.
for (let i = 0; !(await (0, builder_util_1.exists)(file)); i++) {
if (i >= 4) {
throw Object.assign(new Error(`Source archive not found after retries: ${file}`), { code: "ENOENT", path: file });
}
builder_util_1.log.warn({ file, attempt: i + 1 }, "source archive transiently missing, retrying");
await new Promise(r => setTimeout(r, 300 * (i + 1)));
}
if (file.endsWith(".tar.gz") || file.endsWith(".tgz")) {
await tar.extract({ file, cwd: tmpDir, strip: 1 });
}
else if (file.endsWith(".tar.xz") || file.endsWith(".txz")) {
// node-tar cannot decompress xz, so use 7za to turn the .tar.xz into a .tar, then extract that tar.
const cmd7za = await (0, _7zip_1.getPath7za)();
const xzOutDir = `${tmpDir}.xz`;
await fs.rm(xzOutDir, { recursive: true, force: true });
await fs.mkdir(xzOutDir, { recursive: true });
try {
await (0, builder_util_1.exec)(cmd7za, ["x", "-bd", file, (0, builder_util_1.to7zaOutputSwitch)((0, builder_util_1.sanitizeDirPath)(xzOutDir)), "-y"]);
const innerTar = (await fs.readdir(xzOutDir)).find(f => f.endsWith(".tar"));
if (innerTar == null) {
throw new Error(`xz decompression of ${path.basename(file)} produced no .tar archive`);
}
await tar.extract({ file: path.join(xzOutDir, innerTar), cwd: tmpDir, strip: 1 });
}
finally {
await fs.rm(xzOutDir, { recursive: true, force: true });
}
}
else if (file.endsWith(".zip")) {
await extractZipStreaming(file, tmpDir);
}
else if (file.endsWith(".7z")) {
const cmd7za = await (0, _7zip_1.getPath7za)();
try {
await (0, builder_util_1.exec)(cmd7za, ["x", "-bd", file, (0, builder_util_1.to7zaOutputSwitch)((0, builder_util_1.sanitizeDirPath)(tmpDir)), "-y"]);
}
catch (e) {
// Check if extraction actually failed or just had benign warnings
const files = await fs.readdir(tmpDir);
if (files.length === 0) {
builder_util_1.log.warn({ file, tmpDir, error: e.message }, "7z extraction produced no output");
throw new Error(`7z extraction failed for ${file}: ${e.message}`);
}
// If files were extracted despite the error, log and continue
builder_util_1.log.warn({ error: e.message, filesExtracted: files.length }, "7z reported error but extracted files");
}
}
else {
throw new Error(`Unsupported archive format: ${path.basename(file)}`);
}
// Verify extraction produced files
const extractedFiles = await fs.readdir(tmpDir);
if (extractedFiles.length === 0) {
throw new Error(`Extraction of ${path.basename(file)} produced no files`);
}
await fs.rm(dir, { recursive: true, force: true });
await fs.rename(tmpDir, dir);
}
finally {
await release().catch(err => builder_util_1.log.warn({ err }, "failed to release lockfile"));
}
}
async function downloadArtifactToFile(config, label) {
var _a, _b, _c, _d;
// Serialize concurrent downloads of the same artifact across vitest workers to prevent @electron/get's
// non-atomic putFileInCache (remove + move) from racing with a concurrent reader.
const artifactLockKey = crypto
.createHash("sha256")
.update(JSON.stringify({ v: config.version, p: config.platform, a: config.arch, n: config.artifactName }))
.digest("hex")
.slice(0, 20);
const artifactLockPath = path.join(os.tmpdir(), `eb-dl-${artifactLockKey}.lock`);
// This lock is taken when the artifact is not yet in @electron/get's download cache. 100 retries
// matches the other toolset locks; stale (10min) + proper-lockfile's update heartbeat keep a live
// downloader's lock fresh so the longer wait never falsely steals an in-progress download.
const releaseArtifactLock = await lockfile.lock(artifactLockPath, {
retries: { retries: 100, minTimeout: 500, maxTimeout: 5000 },
stale: 600000,
realpath: false,
});
let lastLoggedMilestone = -1;
const state = { bar: undefined };
const downloadOptions = {
timeout: { request: 10 * 60 * 1000 }, // prevent indefinite hang on stalled connections
...config.downloadOptions,
agent: (_b = (_a = config.downloadOptions) === null || _a === void 0 ? void 0 : _a.agent) !== null && _b !== void 0 ? _b : (0, builder_util_1.buildGotProxyAgent)(),
getProgressCallback: info => {
// @electron/get passes downloadOptions (including this callback) to its internal
// SHASUMS256.txt validation download. That file is tiny (<1 MB) and fires at 100%
// immediately, producing a spurious bar even when the artifact itself is cached.
// Skip progress display for any download whose total size is known and small.
if (info.total && info.total < 1000000) {
return Promise.resolve();
}
if (!state.bar && process.stdout.isTTY) {
builder_util_1.log.info({ label }, "downloading");
state.bar = new multiProgress_1.MultiProgress().createBar(`${" ".repeat(builder_util_1.PADDING + 2)}[:bar] :percent | ${label}`, { total: 100 });
}
const pct = info.percent != null ? Math.floor(info.percent * 100) : 0;
if (state.bar) {
state.bar.update(pct);
}
else {
// log every 25% milestone for non-TTY environments (e.g. CI logs) to provide some visibility into download progress without overwhelming logs with too many updates
const percentCompleted = info.transferred && info.total ? Math.floor((info.transferred / info.total) * 100) : Math.floor(pct / 25) * 25;
if (percentCompleted > lastLoggedMilestone && percentCompleted > 0) {
lastLoggedMilestone = percentCompleted;
builder_util_1.log.info({ label, progress: `${percentCompleted}%` }, percentCompleted !== 100 ? "downloading" : "downloaded");
}
}
return Promise.resolve();
},
};
const configWithProgress = { ...config, downloadOptions };
try {
let filePath;
try {
filePath = await (0, builder_util_runtime_1.retry)(() => get.downloadArtifact(configWithProgress), {
retries: 3,
interval: 2000,
backoff: 2000,
shouldRetry: (e) => {
var _a;
if (e instanceof builder_util_runtime_1.HttpError) {
return e.isServerError();
}
if (typeof ((_a = e === null || e === void 0 ? void 0 : e.response) === null || _a === void 0 ? void 0 : _a.statusCode) === "number") {
return e.response.statusCode >= 500;
}
return typeof (e === null || e === void 0 ? void 0 : e.code) === "string" && ["ENOTFOUND", "ETIMEDOUT", "ECONNRESET", "EPIPE", "ENOENT"].includes(e.code);
},
});
}
catch (err) {
if (typeof (err === null || err === void 0 ? void 0 : err.message) === "string" && err.message.includes("dest already exists")) {
filePath = await get.downloadArtifact(configWithProgress);
}
else {
throw err;
}
}
if (!(await (0, builder_util_1.exists)(filePath))) {
builder_util_1.log.warn({ filePath, label }, "cached artifact missing from disk; retrying with cache write");
filePath = await get.downloadArtifact({ ...configWithProgress, cacheMode: get_1.ElectronDownloadCacheMode.WriteOnly });
}
if (!state.bar && lastLoggedMilestone === -1) {
builder_util_1.log.info({ label }, "using cached artifact");
}
return filePath;
}
finally {
(_c = state.bar) === null || _c === void 0 ? void 0 : _c.update(100);
(_d = state.bar) === null || _d === void 0 ? void 0 : _d.terminate();
await releaseArtifactLock().catch(err => builder_util_1.log.warn({ err }, "failed to release artifact download lock"));
}
}
/**
* Checks electron-builder's own archive cache for a previously downloaded archive.
* Validates the SHA-256 checksum when one is known. Returns the cached path on hit,
* null on miss or checksum mismatch (mismatch also deletes the stale file).
*/
async function resolveFromArchiveCache(archiveCachePath, label, expectedSha256) {
if (!(await (0, builder_util_1.exists)(archiveCachePath))) {
return null;
}
if (expectedSha256) {
const hash = await new Promise((resolve, reject) => {
const h = crypto.createHash("sha256");
const s = (0, fs_1.createReadStream)(archiveCachePath);
s.on("error", reject);
s.on("data", (chunk) => h.update(chunk));
s.on("end", () => resolve(h.digest("hex")));
});
if (hash !== expectedSha256) {
builder_util_1.log.warn({ file: label, archiveCachePath }, "cached archive checksum mismatch — removing and re-downloading");
await fs.rm(archiveCachePath).catch(() => { });
return null;
}
}
builder_util_1.log.debug({ file: label, archiveCachePath }, "using cached archive — skipping download");
return archiveCachePath;
}
/**
* Copies a freshly downloaded archive into electron-builder's own archive cache so that
* future builds (including offline environments) can skip the network request entirely.
*/
async function persistToArchiveCache(sourcePath, archiveCachePath) {
try {
await fs.mkdir(path.dirname(archiveCachePath), { recursive: true });
await fs.copyFile(sourcePath, archiveCachePath);
}
catch (err) {
builder_util_1.log.warn({ err, archiveCachePath }, "failed to persist archive to cache — will re-download next time");
}
}
/**
* Core download + extract engine. Handles lockfile, cache-hit short-circuit,
* progress bar, extraction (.zip or .tar.gz), and completion marker.
* Both public download functions delegate here after building their respective configs.
*/
async function downloadAndExtract(config, extractDir, label, archiveCachePath) {
var _a;
await fs.mkdir(extractDir, { recursive: true });
// Pre-lock fast path: only short-circuit for a definitively complete and valid cache.
// Do NOT clean up here — concurrent processes could race to delete under each other.
const stateData = await (0, cacheState_1.readCacheStateFile)(extractDir);
if ((stateData === null || stateData === void 0 ? void 0 : stateData.state) === cacheState_1.CacheState.complete) {
const isValid = await (0, cacheState_1.validateCacheDirectory)(extractDir, stateData.fileCount);
if (isValid) {
builder_util_1.log.debug({ file: label, path: extractDir }, "using cached artifact - cache valid");
return extractDir;
}
}
// Be patient: when many targets/builds contend on the same toolset cache concurrently, all but the
// first wait here while the winner downloads+extracts (a large bundle can take >1min). 15 retries
// (~67s) is too few and waiters fail with ELOCKED before the winner finishes; 100 matches the
// patience of withToolsetLock. proper-lockfile's update heartbeat keeps a live holder's lock fresh,
// so increasing waiter retries never falsely steals an in-progress extraction.
const release = await lockfile.lock(extractDir, {
retries: { retries: 100, minTimeout: 1000, maxTimeout: 5000 },
stale: 120000,
});
let downloadedFile = null;
try {
// Re-check after acquiring lock: another worker may have completed while we waited.
const stateDataAfterLock = await (0, cacheState_1.readCacheStateFile)(extractDir);
if ((stateDataAfterLock === null || stateDataAfterLock === void 0 ? void 0 : stateDataAfterLock.state) === cacheState_1.CacheState.complete) {
const isValid = await (0, cacheState_1.validateCacheDirectory)(extractDir, stateDataAfterLock.fileCount);
if (isValid) {
builder_util_1.log.debug({ file: label, path: extractDir }, "using cached artifact - skipping download/extract");
return extractDir;
}
builder_util_1.log.warn({ extractDir }, "Cache marked complete but files invalid, clearing");
}
else if ((stateDataAfterLock === null || stateDataAfterLock === void 0 ? void 0 : stateDataAfterLock.state) === cacheState_1.CacheState.corrupted) {
builder_util_1.log.warn({ extractDir }, "Corrupted cache detected, cleaning up and re-extracting");
}
// Cleanup inside the lock — skip lock files since we currently hold them
await (0, cacheState_1.cleanupCacheDirectory)(extractDir, { skipLockFiles: true });
await fs.mkdir(extractDir, { recursive: true });
// Check electron-builder's own archive cache before touching @electron/get.
// The cache lives alongside the extract dir: <cacheDir>/<releaseName>/<filename>.
// This lets repeated builds (or offline environments) skip the download entirely once
// the archive has been fetched at least once.
if (archiveCachePath) {
downloadedFile = await resolveFromArchiveCache(archiveCachePath, label, (_a = config.checksums) === null || _a === void 0 ? void 0 : _a[label]);
}
if (!downloadedFile) {
builder_util_1.log.debug({ file: label }, "downloading");
downloadedFile = await downloadArtifactToFile(config, label);
if (!downloadedFile) {
throw new Error(`Failed to download artifact: ${label}`);
}
// Persist the downloaded archive so future builds (and offline environments) can
// skip the network request entirely.
if (archiveCachePath) {
await persistToArchiveCache(downloadedFile, archiveCachePath);
}
}
await (0, cacheState_1.writeCacheState)(extractDir, cacheState_1.CacheState.downloaded);
// Mark extracting so stale-lock detection can recover a crashed mid-extraction process
await (0, cacheState_1.writeCacheState)(extractDir, cacheState_1.CacheState.extracting);
// Extract while holding the lock to prevent concurrent interference
await extractArchive(downloadedFile, extractDir);
// Compute metadata with a full recursive walk now that tmpDir has been renamed to extractDir
const { fileCount, extractedSize } = await (0, cacheState_1.computeCacheMetadata)(extractDir);
// Write complete state with metadata BEFORE releasing the lock; throwOnError=true so a
// failed write (disk full, permissions) propagates instead of silently producing a no-op cache
await (0, cacheState_1.writeCacheState)(extractDir, cacheState_1.CacheState.complete, { fileCount, extractedSize }, true);
}
finally {
await release().catch(err => builder_util_1.log.warn({ err }, "failed to release lockfile"));
}
return extractDir;
}
// ─── Public API ───────────────────────────────────────────────────────────────
/**
* Downloads a generic artifact (.tar.gz or .zip) from a GitHub release.
* Used for electron-builder-binaries tools (appimage, etc.).
*/
async function downloadBuilderToolset(options) {
const { releaseName, filenameWithExt, checksums, githubOrgRepo = "electron-userland/electron-builder-binaries", overrideUrl } = options;
if (/[/\\]|\.\./.test(filenameWithExt)) {
throw new Error(`downloadBuilderToolset: unsafe filenameWithExt "${filenameWithExt}" — must be a plain filename with no path separators or traversal sequences`);
}
const baseUrl = getBinariesMirrorUrl(githubOrgRepo);
const fullUrl = overrideUrl ? `${overrideUrl}/${filenameWithExt}` : `${baseUrl}${releaseName}/${filenameWithExt}`;
const suffix = hashUrlSafe(fullUrl, 5);
const folderName = `${filenameWithExt.replace(/\.(tar\.gz|tgz|tar\.xz|txz|zip|7z)$/, "")}-${suffix}`;
const extractDir = path.join(getCacheDirectory({ allowEnvVarOverride: true }), releaseName, folderName);
// Use resolveAssetURL so @electron/get's ELECTRON_MIRROR env var check cannot override
// the builder-binaries URL we've already resolved (see getArtifactRemoteURL in @electron/get).
const mirrorOptions = {
resolveAssetURL: async () => Promise.resolve(fullUrl),
};
// Predictable archive cache: <cacheDir>/<releaseName>/<filename>, next to the extract dir.
// downloadAndExtract checks here before touching @electron/get and persists the archive here
// after every successful download, so subsequent builds never need a network round-trip.
const archiveCachePath = path.join(getCacheDirectory({ allowEnvVarOverride: true }), releaseName, filenameWithExt);
const config = {
version: "9.9.9", // must be >1.3.2 to bypass @electron/get validation shortcut
artifactName: filenameWithExt,
cacheRoot: path.resolve(getCacheDirectory({ allowEnvVarOverride: true }), "downloads"),
cacheMode: resolveCacheMode(),
...(checksums != null ? { checksums } : { unsafelyDisableChecksums: true }),
mirrorOptions,
isGeneric: true,
};
return downloadAndExtract(config, extractDir, filenameWithExt, archiveCachePath);
}
// Keys present in ElectronGetOptions but absent from ElectronDownloadOptions.
// Used to discriminate between the two config shapes at runtime.
const ELECTRON_GET_EXCLUSIVE_KEYS = ["mirrorOptions", "force", "unsafelyDisableChecksums"];
function isElectronGetOptions(dl) {
return ELECTRON_GET_EXCLUSIVE_KEYS.some(k => Object.hasOwnProperty.call(dl, k));
}
/**
* Downloads and extracts an electron platform artifact (e.g. ffmpeg) using @electron/get.
* Deduplicates concurrent calls for the same artifact within the same process.
*/
function buildElectronArtifactConfig(options) {
const { electronDownload, arch, version, platformName: platform, artifactName, cacheDir: cacheRoot } = options;
let artifactConfig = { cacheRoot, platform, arch, version, artifactName };
if (electronDownload != null) {
if (isElectronGetOptions(electronDownload)) {
const { mirrorOptions, ...rest } = electronDownload;
artifactConfig = { ...artifactConfig, ...rest, cacheRoot, mirrorOptions };
}
else {
const { mirror, customDir, cache, customFilename, isVerifyChecksum, strictSSL, platform: overridePlatform, arch: overrideArch } = electronDownload;
// strictSSL: false disables TLS certificate validation for all
// electron/tool downloads. This option exists only for air-gapped or
// self-signed-cert environments; ensure your build network is fully trusted.
if (strictSSL === false) {
builder_util_1.log.warn({ option: "electronDownload.strictSSL" }, "strictSSL is false — TLS certificate validation is DISABLED for Electron downloads. Only use this option in a trusted, isolated build environment.");
}
artifactConfig = {
...artifactConfig,
unsafelyDisableChecksums: isVerifyChecksum === false,
cacheRoot: cache !== null && cache !== void 0 ? cache : cacheRoot,
mirrorOptions: {
mirror: mirror || undefined,
customDir: customDir || undefined,
customFilename: customFilename || undefined,
},
...(strictSSL === false ? { downloadOptions: { https: { rejectUnauthorized: false } } } : {}),
};
if (overridePlatform != null) {
artifactConfig.platform = overridePlatform;
}
if (overrideArch != null) {
artifactConfig.arch = overrideArch;
}
}
}
artifactConfig.cacheMode = resolveCacheMode();
return artifactConfig;
}
/**
* Downloads the electron artifact zip via @electron/get (with caching) and returns the zip file path.
* Use when you need to extract the zip yourself (e.g. directly to appOutDir to preserve empty dirs and symlinks).
*/
function downloadElectronArtifactZip(options) {
const config = buildElectronArtifactConfig(options);
return downloadArtifactToFile(config, config.artifactName);
}
async function downloadElectronArtifact(options) {
const { arch, version, platformName: platform, artifactName } = options;
const artifactConfig = buildElectronArtifactConfig(options);
const suffix = hashUrlSafe(JSON.stringify(artifactConfig), 5);
const folderName = `${artifactName}-v${version}-${platform}-${arch}-${suffix}`;
const extractDir = path.join(getCacheDirectory({ allowEnvVarOverride: true }), `${artifactName}-v${version}`, folderName);
return downloadAndExtract(artifactConfig, extractDir, artifactName);
}
/**
* Get the binaries mirror URL from environment variables.
* Supports various npm config formats and falls back to GitHub.
*/
function getBinariesMirrorUrl(githubOrgRepo) {
const allowHttp = process.env["ELECTRON_BUILDER_BINARIES_ALLOW_HTTP"] === "true";
for (const envVar of [
"NPM_CONFIG_ELECTRON_BUILDER_BINARIES_MIRROR",
"npm_config_electron_builder_binaries_mirror",
"npm_package_config_electron_builder_binaries_mirror",
"ELECTRON_BUILDER_BINARIES_MIRROR",
]) {
const url = (0, builder_util_1.parseValidEnvVarUrl)(envVar, allowHttp);
if (url) {
return url.endsWith("/") ? url : `${url}/`;
}
}
return `https://github.com/${githubOrgRepo}/releases/download/`;
}
//# sourceMappingURL=electronGet.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
export declare function validateEnvValue(envVarName: string): string | null;
export declare function resolveEnvToolsetPath(envVarKey: string): string | null;

View file

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateEnvValue = validateEnvValue;
exports.resolveEnvToolsetPath = resolveEnvToolsetPath;
const builder_util_1 = require("builder-util");
const path = require("path");
function validateEnvValue(envVarName) {
const rawValue = process.env[envVarName];
if ((0, builder_util_1.isEmptyOrSpaces)(rawValue)) {
return null;
}
const trimmed = rawValue.trim();
// On Windows, backslash is the native path separator and must not be rejected
const shellUnsafeChars = process.platform === "win32" ? /[;&|`$<>"']/ : /[;&|`$<>"'\\]/;
if (shellUnsafeChars.test(trimmed)) {
throw new Error(`${envVarName} contains shell-unsafe characters: ${trimmed}`);
}
return trimmed;
}
function resolveEnvToolsetPath(envVarKey) {
const value = validateEnvValue(envVarKey);
if (value == null) {
return null;
}
builder_util_1.log.info({ envVarKey, value }, `resolved value from environment variable`);
return path.resolve(value);
}
//# sourceMappingURL=envPath.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"envPath.js","sourceRoot":"","sources":["../../src/util/envPath.ts"],"names":[],"mappings":";;AAGA,4CAYC;AAED,sDAOC;AAxBD,+CAAmD;AACnD,6BAA4B;AAE5B,SAAgB,gBAAgB,CAAC,UAAkB;IACjD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IACxC,IAAI,IAAA,8BAAe,EAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAA;IACb,CAAC;IACD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAA;IAC/B,8EAA8E;IAC9E,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,eAAe,CAAA;IACvF,IAAI,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,GAAG,UAAU,sCAAsC,OAAO,EAAE,CAAC,CAAA;IAC/E,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,SAAgB,qBAAqB,CAAC,SAAiB;IACrD,MAAM,KAAK,GAAG,gBAAgB,CAAC,SAAS,CAAC,CAAA;IACzC,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAClB,OAAO,IAAI,CAAA;IACb,CAAC;IACD,kBAAG,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,0CAA0C,CAAC,CAAA;IAC1E,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;AAC5B,CAAC","sourcesContent":["import { isEmptyOrSpaces, log } from \"builder-util\"\nimport * as path from \"path\"\n\nexport function validateEnvValue(envVarName: string): string | null {\n const rawValue = process.env[envVarName]\n if (isEmptyOrSpaces(rawValue)) {\n return null\n }\n const trimmed = rawValue.trim()\n // On Windows, backslash is the native path separator and must not be rejected\n const shellUnsafeChars = process.platform === \"win32\" ? /[;&|`$<>\"']/ : /[;&|`$<>\"'\\\\]/\n if (shellUnsafeChars.test(trimmed)) {\n throw new Error(`${envVarName} contains shell-unsafe characters: ${trimmed}`)\n }\n return trimmed\n}\n\nexport function resolveEnvToolsetPath(envVarKey: string): string | null {\n const value = validateEnvValue(envVarKey)\n if (value == null) {\n return null\n }\n log.info({ envVarKey, value }, `resolved value from environment variable`)\n return path.resolve(value)\n}\n"]}

View file

@ -1,2 +0,0 @@
export declare function sanitizeFileName(s: string): string;
export declare function getCompleteExtname(filename: string): string;

View file

@ -1,39 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCompleteExtname = exports.sanitizeFileName = void 0;
// @ts-ignore
const _sanitizeFileName = require("sanitize-filename");
const path = require("path");
function sanitizeFileName(s) {
return _sanitizeFileName(s);
}
exports.sanitizeFileName = sanitizeFileName;
// Get the filetype from a filename. Returns a string of one or more file extensions,
// e.g. .zip, .dmg, .tar.gz, .tar.bz2, .exe.blockmap. We'd normally use `path.extname()`,
// but it doesn't support multiple extensions, e.g. Foo-1.0.0.dmg.blockmap should be
// .dmg.blockmap, not .blockmap.
function getCompleteExtname(filename) {
let extname = path.extname(filename);
switch (extname) {
// Append leading extension for blockmap filetype
case ".blockmap": {
extname = path.extname(filename.replace(extname, "")) + extname;
break;
}
// Append leading extension for known compressed tar formats
case ".bz2":
case ".gz":
case ".lz":
case ".xz":
case ".7z": {
const ext = path.extname(filename.replace(extname, ""));
if (ext === ".tar") {
extname = ext + extname;
}
break;
}
}
return extname;
}
exports.getCompleteExtname = getCompleteExtname;
//# sourceMappingURL=filename.js.map

View file

@ -1 +0,0 @@
{"version":3,"file":"filename.js","sourceRoot":"","sources":["../../src/util/filename.ts"],"names":[],"mappings":";;;AAAA,aAAa;AACb,uDAAsD;AACtD,6BAA4B;AAE5B,SAAgB,gBAAgB,CAAC,CAAS;IACxC,OAAO,iBAAiB,CAAC,CAAC,CAAC,CAAA;AAC7B,CAAC;AAFD,4CAEC;AAED,qFAAqF;AACrF,yFAAyF;AACzF,oFAAoF;AACpF,gCAAgC;AAChC,SAAgB,kBAAkB,CAAC,QAAgB;IACjD,IAAI,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAEpC,QAAQ,OAAO,EAAE;QACf,iDAAiD;QACjD,KAAK,WAAW,CAAC,CAAC;YAChB,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,GAAG,OAAO,CAAA;YAE/D,MAAK;SACN;QACD,4DAA4D;QAC5D,KAAK,MAAM,CAAC;QACZ,KAAK,KAAK,CAAC;QACX,KAAK,KAAK,CAAC;QACX,KAAK,KAAK,CAAC;QACX,KAAK,KAAK,CAAC,CAAC;YACV,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;YACvD,IAAI,GAAG,KAAK,MAAM,EAAE;gBAClB,OAAO,GAAG,GAAG,GAAG,OAAO,CAAA;aACxB;YAED,MAAK;SACN;KACF;IAED,OAAO,OAAO,CAAA;AAChB,CAAC;AA1BD,gDA0BC","sourcesContent":["// @ts-ignore\nimport * as _sanitizeFileName from \"sanitize-filename\"\nimport * as path from \"path\"\n\nexport function sanitizeFileName(s: string): string {\n return _sanitizeFileName(s)\n}\n\n// Get the filetype from a filename. Returns a string of one or more file extensions,\n// e.g. .zip, .dmg, .tar.gz, .tar.bz2, .exe.blockmap. We'd normally use `path.extname()`,\n// but it doesn't support multiple extensions, e.g. Foo-1.0.0.dmg.blockmap should be\n// .dmg.blockmap, not .blockmap.\nexport function getCompleteExtname(filename: string): string {\n let extname = path.extname(filename)\n\n switch (extname) {\n // Append leading extension for blockmap filetype\n case \".blockmap\": {\n extname = path.extname(filename.replace(extname, \"\")) + extname\n\n break\n }\n // Append leading extension for known compressed tar formats\n case \".bz2\":\n case \".gz\":\n case \".lz\":\n case \".xz\":\n case \".7z\": {\n const ext = path.extname(filename.replace(extname, \"\"))\n if (ext === \".tar\") {\n extname = ext + extname\n }\n\n break\n }\n }\n\n return extname\n}\n"]}

View file

@ -1,8 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createFilter = exports.hasMagic = void 0;
exports.hasMagic = hasMagic;
exports.createFilter = createFilter;
const path = require("path");
const fileTransformer_1 = require("../fileTransformer");
/** @internal */
function hasMagic(pattern) {
const set = pattern.set;
@ -16,22 +16,12 @@ function hasMagic(pattern) {
}
return false;
}
exports.hasMagic = hasMagic;
// sometimes, destination may not contain path separator in the end (path to folder), but the src does. So let's ensure paths have path separators in the end
function ensureEndSlash(s) {
return s.length === 0 || s.endsWith(path.sep) ? s : s + path.sep;
}
function getRelativePath(file, srcWithEndSlash) {
if (!file.startsWith(srcWithEndSlash)) {
const index = file.indexOf(fileTransformer_1.NODE_MODULES_PATTERN);
if (index < 0) {
throw new Error(`${file} must be under ${srcWithEndSlash}`);
}
else {
return file.substring(index + 1 /* leading slash */);
}
}
let relative = file.substring(srcWithEndSlash.length);
function getRelativePath(file, srcWithEndSlash, stat) {
let relative = stat.moduleFullFilePath || file.substring(srcWithEndSlash.length);
if (path.sep === "\\") {
if (relative.startsWith("\\")) {
// windows problem: double backslash, the above substring call removes root path with a single slash, so here can me some leftovers
@ -48,12 +38,18 @@ function createFilter(src, patterns, excludePatterns) {
if (src === file) {
return true;
}
const relative = getRelativePath(file, srcWithEndSlash);
let relative = getRelativePath(file, srcWithEndSlash, stat);
// filter the root node_modules, but not a subnode_modules (like /appDir/others/foo/node_modules/blah)
if (relative === "node_modules") {
return false;
}
else if (relative.endsWith("/node_modules")) {
relative += "/";
}
// https://github.com/electron-userland/electron-builder/issues/867
return minimatchAll(relative, patterns, stat) && (excludePatterns == null || stat.isDirectory() || !minimatchAll(relative, excludePatterns, stat));
};
}
exports.createFilter = createFilter;
// https://github.com/joshwnj/minimatch-all/blob/master/index.js
function minimatchAll(path, patterns, stat) {
let match = false;

View file

@ -1 +1 @@
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/util/filter.ts"],"names":[],"mappings":";;;AAGA,6BAA4B;AAC5B,wDAAyD;AAEzD,gBAAgB;AAChB,SAAgB,QAAQ,CAAC,OAAkB;IACzC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAA;IACvB,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE;QAClB,OAAO,IAAI,CAAA;KACZ;IAED,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE;QACtB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE;YACzB,OAAO,IAAI,CAAA;SACZ;KACF;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAbD,4BAaC;AAED,6JAA6J;AAC7J,SAAS,cAAc,CAAC,CAAS;IAC/B,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAA;AAClE,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,eAAuB;IAC5D,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,sCAAoB,CAAC,CAAA;QAChD,IAAI,KAAK,GAAG,CAAC,EAAE;YACb,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,kBAAkB,eAAe,EAAE,CAAC,CAAA;SAC5D;aAAM;YACL,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,GAAG,CAAC,CAAC,mBAAmB,CAAC,CAAA;SACrD;KACF;IAED,IAAI,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;IACrD,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,EAAE;QACrB,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE;YAC7B,mIAAmI;YACnI,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;SACjC;QACD,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;KACxC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,gBAAgB;AAChB,SAAgB,YAAY,CAAC,GAAW,EAAE,QAA0B,EAAE,eAAyC;IAC7G,MAAM,eAAe,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;IAC3C,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QACpB,IAAI,GAAG,KAAK,IAAI,EAAE;YAChB,OAAO,IAAI,CAAA;SACZ;QAED,MAAM,QAAQ,GAAG,eAAe,CAAC,IAAI,EAAE,eAAe,CAAC,CAAA;QACvD,mEAAmE;QACnE,OAAO,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC,CAAA;IACpJ,CAAC,CAAA;AACH,CAAC;AAXD,oCAWC;AAED,gEAAgE;AAChE,SAAS,YAAY,CAAC,IAAY,EAAE,QAA0B,EAAE,IAAW;IACzE,IAAI,KAAK,GAAG,KAAK,CAAA;IACjB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE;QAC9B,qDAAqD;QACrD,yDAAyD;QACzD,IAAI,KAAK,KAAK,OAAO,CAAC,MAAM,EAAE;YAC5B,SAAQ;SACT;QAED,qEAAqE;QACrE,oMAAoM;QACpM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;KACnE;IACD,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["import { Filter } from \"builder-util/out/fs\"\nimport { Stats } from \"fs-extra\"\nimport { Minimatch } from \"minimatch\"\nimport * as path from \"path\"\nimport { NODE_MODULES_PATTERN } from \"../fileTransformer\"\n\n/** @internal */\nexport function hasMagic(pattern: Minimatch) {\n const set = pattern.set\n if (set.length > 1) {\n return true\n }\n\n for (const i of set[0]) {\n if (typeof i !== \"string\") {\n return true\n }\n }\n\n return false\n}\n\n// sometimes, destination may not contain path separator in the end (path to folder), but the src does. So let's ensure paths have path separators in the end\nfunction ensureEndSlash(s: string) {\n return s.length === 0 || s.endsWith(path.sep) ? s : s + path.sep\n}\n\nfunction getRelativePath(file: string, srcWithEndSlash: string) {\n if (!file.startsWith(srcWithEndSlash)) {\n const index = file.indexOf(NODE_MODULES_PATTERN)\n if (index < 0) {\n throw new Error(`${file} must be under ${srcWithEndSlash}`)\n } else {\n return file.substring(index + 1 /* leading slash */)\n }\n }\n\n let relative = file.substring(srcWithEndSlash.length)\n if (path.sep === \"\\\\\") {\n if (relative.startsWith(\"\\\\\")) {\n // windows problem: double backslash, the above substring call removes root path with a single slash, so here can me some leftovers\n relative = relative.substring(1)\n }\n relative = relative.replace(/\\\\/g, \"/\")\n }\n return relative\n}\n\n/** @internal */\nexport function createFilter(src: string, patterns: Array<Minimatch>, excludePatterns?: Array<Minimatch> | null): Filter {\n const srcWithEndSlash = ensureEndSlash(src)\n return (file, stat) => {\n if (src === file) {\n return true\n }\n\n const relative = getRelativePath(file, srcWithEndSlash)\n // https://github.com/electron-userland/electron-builder/issues/867\n return minimatchAll(relative, patterns, stat) && (excludePatterns == null || stat.isDirectory() || !minimatchAll(relative, excludePatterns, stat))\n }\n}\n\n// https://github.com/joshwnj/minimatch-all/blob/master/index.js\nfunction minimatchAll(path: string, patterns: Array<Minimatch>, stat: Stats): boolean {\n let match = false\n for (const pattern of patterns) {\n // If we've got a match, only re-test for exclusions.\n // if we don't have a match, only re-test for inclusions.\n if (match !== pattern.negate) {\n continue\n }\n\n // partial match — pattern: foo/bar.txt path: foo — we must allow foo\n // use it only for non-negate patterns: const m = new Minimatch(\"!node_modules/@(electron-download|electron)/**/*\", {dot: true }); m.match(\"node_modules\", true) will return false, but must be true\n match = pattern.match(path, stat.isDirectory() && !pattern.negate)\n }\n return match\n}\n"]}
{"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/util/filter.ts"],"names":[],"mappings":";;AAKA,4BAaC;AAoBD,oCAmBC;AAvDD,6BAA4B;AAE5B,gBAAgB;AAChB,SAAgB,QAAQ,CAAC,OAAkB;IACzC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAA;IACvB,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnB,OAAO,IAAI,CAAA;IACb,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QACvB,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC1B,OAAO,IAAI,CAAA;QACb,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAA;AACd,CAAC;AAED,6JAA6J;AAC7J,SAAS,cAAc,CAAC,CAAS;IAC/B,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAA;AAClE,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,eAAuB,EAAE,IAAiB;IAC/E,IAAI,QAAQ,GAAG,IAAI,CAAC,kBAAkB,IAAI,IAAI,CAAC,SAAS,CAAC,eAAe,CAAC,MAAM,CAAC,CAAA;IAChF,IAAI,IAAI,CAAC,GAAG,KAAK,IAAI,EAAE,CAAC;QACtB,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,mIAAmI;YACnI,QAAQ,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;QAClC,CAAC;QACD,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;IACzC,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,gBAAgB;AAChB,SAAgB,YAAY,CAAC,GAAW,EAAE,QAA0B,EAAE,eAAyC;IAC7G,MAAM,eAAe,GAAG,cAAc,CAAC,GAAG,CAAC,CAAA;IAC3C,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;QACpB,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YACjB,OAAO,IAAI,CAAA;QACb,CAAC;QAED,IAAI,QAAQ,GAAG,eAAe,CAAC,IAAI,EAAE,eAAe,EAAE,IAAI,CAAC,CAAA;QAE3D,sGAAsG;QACtG,IAAI,QAAQ,KAAK,cAAc,EAAE,CAAC;YAChC,OAAO,KAAK,CAAA;QACd,CAAC;aAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC;YAC9C,QAAQ,IAAI,GAAG,CAAA;QACjB,CAAC;QAED,mEAAmE;QACnE,OAAO,YAAY,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,IAAI,IAAI,IAAI,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,eAAe,EAAE,IAAI,CAAC,CAAC,CAAA;IACpJ,CAAC,CAAA;AACH,CAAC;AAED,gEAAgE;AAChE,SAAS,YAAY,CAAC,IAAY,EAAE,QAA0B,EAAE,IAAiB;IAC/E,IAAI,KAAK,GAAG,KAAK,CAAA;IACjB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,qDAAqD;QACrD,yDAAyD;QACzD,IAAI,KAAK,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;YAC7B,SAAQ;QACV,CAAC;QAED,qEAAqE;QACrE,oMAAoM;QACpM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IACpE,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC","sourcesContent":["import { Filter, FilterStats } from \"builder-util\"\nimport { Minimatch } from \"minimatch\"\nimport * as path from \"path\"\n\n/** @internal */\nexport function hasMagic(pattern: Minimatch) {\n const set = pattern.set\n if (set.length > 1) {\n return true\n }\n\n for (const i of set[0]) {\n if (typeof i !== \"string\") {\n return true\n }\n }\n\n return false\n}\n\n// sometimes, destination may not contain path separator in the end (path to folder), but the src does. So let's ensure paths have path separators in the end\nfunction ensureEndSlash(s: string) {\n return s.length === 0 || s.endsWith(path.sep) ? s : s + path.sep\n}\n\nfunction getRelativePath(file: string, srcWithEndSlash: string, stat: FilterStats) {\n let relative = stat.moduleFullFilePath || file.substring(srcWithEndSlash.length)\n if (path.sep === \"\\\\\") {\n if (relative.startsWith(\"\\\\\")) {\n // windows problem: double backslash, the above substring call removes root path with a single slash, so here can me some leftovers\n relative = relative.substring(1)\n }\n relative = relative.replace(/\\\\/g, \"/\")\n }\n return relative\n}\n\n/** @internal */\nexport function createFilter(src: string, patterns: Array<Minimatch>, excludePatterns?: Array<Minimatch> | null): Filter {\n const srcWithEndSlash = ensureEndSlash(src)\n return (file, stat) => {\n if (src === file) {\n return true\n }\n\n let relative = getRelativePath(file, srcWithEndSlash, stat)\n\n // filter the root node_modules, but not a subnode_modules (like /appDir/others/foo/node_modules/blah)\n if (relative === \"node_modules\") {\n return false\n } else if (relative.endsWith(\"/node_modules\")) {\n relative += \"/\"\n }\n\n // https://github.com/electron-userland/electron-builder/issues/867\n return minimatchAll(relative, patterns, stat) && (excludePatterns == null || stat.isDirectory() || !minimatchAll(relative, excludePatterns, stat))\n }\n}\n\n// https://github.com/joshwnj/minimatch-all/blob/master/index.js\nfunction minimatchAll(path: string, patterns: Array<Minimatch>, stat: FilterStats): boolean {\n let match = false\n for (const pattern of patterns) {\n // If we've got a match, only re-test for exclusions.\n // if we don't have a match, only re-test for inclusions.\n if (match !== pattern.negate) {\n continue\n }\n\n // partial match — pattern: foo/bar.txt path: foo — we must allow foo\n // use it only for non-negate patterns: const m = new Minimatch(\"!node_modules/@(electron-download|electron)/**/*\", {dot: true }); m.match(\"node_modules\", true) will return false, but must be true\n match = pattern.match(path, stat.isDirectory() && !pattern.negate)\n }\n return match\n}\n"]}

View file

@ -1,17 +1,16 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isAutoDiscoveryCodeSignIdentity = exports.isBuildCacheEnabled = exports.isUseSystemSigncode = void 0;
exports.isUseSystemSigncode = isUseSystemSigncode;
exports.isBuildCacheEnabled = isBuildCacheEnabled;
exports.isAutoDiscoveryCodeSignIdentity = isAutoDiscoveryCodeSignIdentity;
const builder_util_1 = require("builder-util");
function isUseSystemSigncode() {
return builder_util_1.isEnvTrue(process.env.USE_SYSTEM_SIGNCODE);
return (0, builder_util_1.isEnvTrue)(process.env.USE_SYSTEM_SIGNCODE);
}
exports.isUseSystemSigncode = isUseSystemSigncode;
function isBuildCacheEnabled() {
return !builder_util_1.isEnvTrue(process.env.ELECTRON_BUILDER_DISABLE_BUILD_CACHE);
return !(0, builder_util_1.isEnvTrue)(process.env.ELECTRON_BUILDER_DISABLE_BUILD_CACHE);
}
exports.isBuildCacheEnabled = isBuildCacheEnabled;
function isAutoDiscoveryCodeSignIdentity() {
return process.env.CSC_IDENTITY_AUTO_DISCOVERY !== "false";
}
exports.isAutoDiscoveryCodeSignIdentity = isAutoDiscoveryCodeSignIdentity;
//# sourceMappingURL=flags.js.map

View file

@ -1 +1 @@
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../../src/util/flags.ts"],"names":[],"mappings":";;;AAAA,+CAAwC;AAExC,SAAgB,mBAAmB;IACjC,OAAO,wBAAS,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;AACnD,CAAC;AAFD,kDAEC;AAED,SAAgB,mBAAmB;IACjC,OAAO,CAAC,wBAAS,CAAC,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAA;AACrE,CAAC;AAFD,kDAEC;AAED,SAAgB,+BAA+B;IAC7C,OAAO,OAAO,CAAC,GAAG,CAAC,2BAA2B,KAAK,OAAO,CAAA;AAC5D,CAAC;AAFD,0EAEC","sourcesContent":["import { isEnvTrue } from \"builder-util\"\n\nexport function isUseSystemSigncode() {\n return isEnvTrue(process.env.USE_SYSTEM_SIGNCODE)\n}\n\nexport function isBuildCacheEnabled() {\n return !isEnvTrue(process.env.ELECTRON_BUILDER_DISABLE_BUILD_CACHE)\n}\n\nexport function isAutoDiscoveryCodeSignIdentity() {\n return process.env.CSC_IDENTITY_AUTO_DISCOVERY !== \"false\"\n}\n"]}
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../../src/util/flags.ts"],"names":[],"mappings":";;AAEA,kDAEC;AAED,kDAEC;AAED,0EAEC;AAZD,+CAAwC;AAExC,SAAgB,mBAAmB;IACjC,OAAO,IAAA,wBAAS,EAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAA;AACnD,CAAC;AAED,SAAgB,mBAAmB;IACjC,OAAO,CAAC,IAAA,wBAAS,EAAC,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAA;AACrE,CAAC;AAED,SAAgB,+BAA+B;IAC7C,OAAO,OAAO,CAAC,GAAG,CAAC,2BAA2B,KAAK,OAAO,CAAA;AAC5D,CAAC","sourcesContent":["import { isEnvTrue } from \"builder-util\"\n\nexport function isUseSystemSigncode() {\n return isEnvTrue(process.env.USE_SYSTEM_SIGNCODE)\n}\n\nexport function isBuildCacheEnabled() {\n return !isEnvTrue(process.env.ELECTRON_BUILDER_DISABLE_BUILD_CACHE)\n}\n\nexport function isAutoDiscoveryCodeSignIdentity() {\n return process.env.CSC_IDENTITY_AUTO_DISCOVERY !== \"false\"\n}\n"]}

View file

@ -1,13 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hashFile = void 0;
exports.hashFile = hashFile;
const crypto_1 = require("crypto");
const fs_1 = require("fs");
function hashFile(file, algorithm = "sha512", encoding = "base64", options) {
return new Promise((resolve, reject) => {
const hash = crypto_1.createHash(algorithm);
const hash = (0, crypto_1.createHash)(algorithm);
hash.on("error", reject).setEncoding(encoding);
fs_1.createReadStream(file, { ...options, highWaterMark: 1024 * 1024 /* better to use more memory but hash faster */ })
(0, fs_1.createReadStream)(file, { ...options, highWaterMark: 1024 * 1024 /* better to use more memory but hash faster */ })
.on("error", reject)
.on("end", () => {
hash.end();
@ -16,5 +16,4 @@ function hashFile(file, algorithm = "sha512", encoding = "base64", options) {
.pipe(hash, { end: false });
});
}
exports.hashFile = hashFile;
//# sourceMappingURL=hash.js.map

View file

@ -1 +1 @@
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/util/hash.ts"],"names":[],"mappings":";;;AAAA,mCAAmC;AACnC,2BAAqC;AAErC,SAAgB,QAAQ,CAAC,IAAY,EAAE,SAAS,GAAG,QAAQ,EAAE,WAA6B,QAAQ,EAAE,OAAa;IAC/G,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,MAAM,IAAI,GAAG,mBAAU,CAAC,SAAS,CAAC,CAAA;QAClC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;QAE9C,qBAAgB,CAAC,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC,+CAA+C,EAAE,CAAC;aAC/G,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC;aACnB,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACd,IAAI,CAAC,GAAG,EAAE,CAAA;YACV,OAAO,CAAC,IAAI,CAAC,IAAI,EAAY,CAAC,CAAA;QAChC,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;AACJ,CAAC;AAbD,4BAaC","sourcesContent":["import { createHash } from \"crypto\"\nimport { createReadStream } from \"fs\"\n\nexport function hashFile(file: string, algorithm = \"sha512\", encoding: \"base64\" | \"hex\" = \"base64\", options?: any) {\n return new Promise<string>((resolve, reject) => {\n const hash = createHash(algorithm)\n hash.on(\"error\", reject).setEncoding(encoding)\n\n createReadStream(file, { ...options, highWaterMark: 1024 * 1024 /* better to use more memory but hash faster */ })\n .on(\"error\", reject)\n .on(\"end\", () => {\n hash.end()\n resolve(hash.read() as string)\n })\n .pipe(hash, { end: false })\n })\n}\n"]}
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/util/hash.ts"],"names":[],"mappings":";;AAGA,4BAaC;AAhBD,mCAAmC;AACnC,2BAAqC;AAErC,SAAgB,QAAQ,CAAC,IAAY,EAAE,SAAS,GAAG,QAAQ,EAAE,WAA6B,QAAQ,EAAE,OAAa;IAC/G,OAAO,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC7C,MAAM,IAAI,GAAG,IAAA,mBAAU,EAAC,SAAS,CAAC,CAAA;QAClC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;QAE9C,IAAA,qBAAgB,EAAC,IAAI,EAAE,EAAE,GAAG,OAAO,EAAE,aAAa,EAAE,IAAI,GAAG,IAAI,CAAC,+CAA+C,EAAE,CAAC;aAC/G,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC;aACnB,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACd,IAAI,CAAC,GAAG,EAAE,CAAA;YACV,OAAO,CAAC,IAAI,CAAC,IAAI,EAAY,CAAC,CAAA;QAChC,CAAC,CAAC;aACD,IAAI,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { createHash } from \"crypto\"\nimport { createReadStream } from \"fs\"\n\nexport function hashFile(file: string, algorithm = \"sha512\", encoding: \"base64\" | \"hex\" = \"base64\", options?: any) {\n return new Promise<string>((resolve, reject) => {\n const hash = createHash(algorithm)\n hash.on(\"error\", reject).setEncoding(encoding)\n\n createReadStream(file, { ...options, highWaterMark: 1024 * 1024 /* better to use more memory but hash faster */ })\n .on(\"error\", reject)\n .on(\"end\", () => {\n hash.end()\n resolve(hash.read() as string)\n })\n .pipe(hash, { end: false })\n })\n}\n"]}

View file

@ -0,0 +1,25 @@
export interface IconInfo {
file: string;
size: number;
}
export type IconFormat = "icns" | "ico" | "set";
export interface IconConvertResult {
icons: IconInfo[];
isFallback: boolean;
error?: string;
errorCode?: string;
}
type IconConversionConfig = {
sources: string[];
fallbackSources: string[];
roots: string[];
format: IconFormat;
outDir: string;
};
export declare function convertIcon({ sources, fallbackSources, roots, format, outDir }: IconConversionConfig): Promise<IconConvertResult>;
export declare function getPngSize(filePath: string): Promise<{
width: number;
height: number;
}>;
export declare function buildSourceCandidates(sources: string[], format: IconFormat): string[];
export {};

View file

@ -0,0 +1,260 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertIcon = convertIcon;
exports.getPngSize = getPngSize;
exports.buildSourceCandidates = buildSourceCandidates;
const promises_1 = require("fs/promises");
const path = require("path");
const icons_1 = require("../toolsets/icons");
class IconConversionError extends Error {
constructor(message, errorCode) {
super(message);
this.errorCode = errorCode;
this.code = errorCode;
}
}
async function convertIcon({ sources, fallbackSources, roots, format, outDir }) {
const candidates = buildSourceCandidates(sources, format);
let icons = await doConvertIcon(candidates, roots, format, outDir);
let isFallback = false;
if (icons == null) {
const fallbackCandidates = buildSourceCandidates(fallbackSources, format);
icons = await doConvertIcon(fallbackCandidates, roots, format, outDir);
isFallback = true;
}
return { icons: icons !== null && icons !== void 0 ? icons : [], isFallback };
}
// ─── PNG dimension reader ─────────────────────────────────────────────────────
// Reads width/height from the PNG IHDR chunk at a fixed offset (no dependencies).
async function getPngSize(filePath) {
const buf = await (0, promises_1.readFile)(filePath);
// PNG signature = 8 bytes, IHDR chunk header = 8 bytes → width at 16, height at 20
if (buf.length < 24) {
return { width: 0, height: 0 };
}
return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) };
}
// ─── ICO header parser ────────────────────────────────────────────────────────
async function getIcoMaxSize(filePath) {
const buf = await (0, promises_1.readFile)(filePath);
if (buf.length < 6 || buf[0] !== 0 || buf[1] !== 0 || buf[2] !== 1 || buf[3] !== 0) {
return null;
}
const count = buf.readUInt16LE(4);
let max = 0;
for (let i = 0; i < count; i++) {
const off = 6 + i * 16;
if (off + 2 > buf.length) {
break;
}
const w = buf[off] || 256;
const h = buf[off + 1] || 256;
if (w > max) {
max = w;
}
if (h > max) {
max = h;
}
}
return max;
}
// ─── Set output remapper ──────────────────────────────────────────────────────
// CLI outputs NxN.png; remap to icon_NxN.png to preserve existing naming convention.
async function remapSetOutput(outDir) {
const entries = await (0, promises_1.readdir)(outDir);
const result = [];
for (const name of entries) {
const match = name.match(/^(\d+)x\d+\.png$/);
if (!match) {
continue;
}
const size = parseInt(match[1], 10);
const oldPath = path.join(outDir, name);
const newPath = path.join(outDir, `icon_${size}x${size}.png`);
await (0, promises_1.rename)(oldPath, newPath);
result.push({ file: newPath, size });
}
return result.sort((a, b) => a.size - b.size);
}
// ─── CLI output collector ─────────────────────────────────────────────────────
async function collectCliOutput(outDir, format, sourceMaxSize = 0) {
if (format === "icns") {
return [{ file: path.join(outDir, "icon.icns"), size: sourceMaxSize }];
}
if (format === "ico") {
const icoFile = path.join(outDir, "icon.ico");
const size = await getIcoMaxSize(icoFile);
return [{ file: icoFile, size: size !== null && size !== void 0 ? size : sourceMaxSize }];
}
return remapSetOutput(outDir);
}
// ─── File resolution (matches go fileResolver.go + icon-converter.go) ────────
function imageHasExtension(name, format) {
return name.endsWith("." + format) || name.endsWith(".png") || name.endsWith(".ico") || name.endsWith(".svg") || name.endsWith(".icns");
}
function buildSourceCandidates(sources, format) {
const result = [];
for (const src of sources) {
if (imageHasExtension(src, format)) {
result.push(src);
}
else {
if (format !== "set") {
result.push(src + "." + format);
}
result.push(src);
result.push(src + ".png");
result.push(src + ".svg");
if (format !== "icns") {
result.push(src + ".icns");
if (format !== "ico") {
result.push(src + ".ico");
}
}
}
}
if (format !== "set") {
result.push("icon." + format);
}
for (const setName of ["icons", "icon"]) {
result.push(setName);
}
result.push("icon.png");
result.push("icon.svg");
if (format !== "icns") {
result.push("icon.icns");
if (format !== "ico") {
result.push("icon.ico");
}
}
// Deduplicate while preserving order so resolveSourceFile never stats the same path twice
return [...new Set(result)];
}
async function resolveSourceFile(candidates, roots) {
for (const candidate of candidates) {
const absPath = path.isAbsolute(candidate) ? path.normalize(candidate) : null;
const searchPaths = absPath ? [absPath] : roots.map(r => path.join(r, candidate));
for (const p of searchPaths) {
try {
const s = await (0, promises_1.stat)(p);
return { resolved: p, isDir: s.isDirectory() };
}
catch {
// not found, try next
}
}
}
return null;
}
// ─── Directory icon collection (go collect-icons.go) ────────────────────────
async function collectIconsFromDir(dir) {
const entries = await (0, promises_1.readdir)(dir);
const sizeMap = new Map();
let fallbackFile = null;
for (const name of entries) {
if (name === "icon.png" || name === "icon.PNG") {
fallbackFile = path.join(dir, name);
continue;
}
const match = name.match(/^(\d+)(?:x\d+)?\.png$/i);
if (!match) {
continue;
}
const size = parseInt(match[1], 10);
if (isNaN(size)) {
continue;
}
const filePath = path.join(dir, name);
const existing = sizeMap.get(size);
if (!existing || name.length < path.basename(existing.file).length) {
sizeMap.set(size, { file: filePath, size });
}
}
const icons = Array.from(sizeMap.values()).sort((a, b) => a.size - b.size);
return { icons, fallbackFile };
}
// ─── Main conversion logic ───────────────────────────────────────────────────
async function doConvertIcon(candidates, roots, format, outDir) {
const found = await resolveSourceFile(candidates, roots);
if (!found) {
return null;
}
const { resolved, isDir } = found;
// SVG source for set format: return the SVG directly — Linux targets place it in
// the freedesktop scalable/ dir. Never call getPngSize on an SVG file.
if (!isDir && resolved.endsWith(".svg") && format === "set") {
return [{ file: resolved, size: 1024 }];
}
const outExt = format === "set" ? ".png" : "." + format;
// If source already has the target extension and is not a directory, return it directly
if (!isDir && resolved.endsWith(outExt)) {
if (format === "icns") {
return [{ file: resolved, size: 0 }];
}
if (format === "ico") {
const size = await getIcoMaxSize(resolved);
if (size === null) {
throw new IconConversionError(`Icon is not a valid ICO file: ${resolved}`, "ERR_ICON_UNKNOWN_FORMAT");
}
if (size < 256) {
throw new IconConversionError(`Icon must be at least 256x256 pixels, provided: ${size}x${size}`, "ERR_ICON_TOO_SMALL");
}
return [{ file: resolved, size }];
}
// set: source is already a .png — return as-is with its dimensions
const { width, height } = await getPngSize(resolved);
return [{ file: resolved, size: Math.max(width, height) }];
}
if (isDir) {
const { icons, fallbackFile } = await collectIconsFromDir(resolved);
if (format === "set") {
if (icons.length > 0) {
return icons;
}
if (fallbackFile) {
return doConvertSingleFile(fallbackFile, format, outDir);
}
return null;
}
if (icons.length > 0) {
// Use largest available PNG from the directory as CLI input
const maxIcon = icons[icons.length - 1];
await (0, promises_1.mkdir)(outDir, { recursive: true });
await (0, icons_1.runIconsTool)({ inputFile: maxIcon.file, outputFormat: format, outDir });
return collectCliOutput(outDir, format, maxIcon.size);
}
if (fallbackFile) {
return doConvertSingleFile(fallbackFile, format, outDir);
}
return null;
}
// Single file: ICNS → ico or set — pass ICNS directly to CLI (CLI handles extraction)
if (resolved.endsWith(".icns") && format !== "icns") {
await (0, promises_1.mkdir)(outDir, { recursive: true });
await (0, icons_1.runIconsTool)({ inputFile: resolved, outputFormat: format, outDir });
return collectCliOutput(outDir, format);
}
return doConvertSingleFile(resolved, format, outDir);
}
async function doConvertSingleFile(sourceFile, format, outDir) {
const ext = path.extname(sourceFile).toLowerCase();
let maxSize;
if (ext === ".svg") {
maxSize = 1024; // CLI rasterizes SVG at 1024px
}
else {
const { width, height } = await getPngSize(sourceFile);
maxSize = Math.max(width, height);
if (maxSize === 0) {
return null;
}
const recommendedMin = format === "icns" ? 512 : 256;
if (maxSize < recommendedMin) {
throw new IconConversionError(`Icon must be at least ${recommendedMin}x${recommendedMin} pixels, provided: ${maxSize}x${maxSize}`, "ERR_ICON_TOO_SMALL");
}
}
await (0, promises_1.mkdir)(outDir, { recursive: true });
await (0, icons_1.runIconsTool)({ inputFile: sourceFile, outputFormat: format, outDir });
return collectCliOutput(outDir, format, maxSize);
}
//# sourceMappingURL=iconConverter.js.map

File diff suppressed because one or more lines are too long

View file

@ -1,6 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.langIdToName = exports.lcid = exports.toLangWithRegion = exports.bundledLanguages = void 0;
exports.langIdToName = exports.lcid = exports.bundledLanguages = void 0;
exports.toLangWithRegion = toLangWithRegion;
exports.bundledLanguages = [
"en_US",
"de_DE",
@ -42,7 +43,6 @@ function toLangWithRegion(lang) {
const result = langToLangWithRegion.get(lang);
return result == null ? `${lang}_${lang.toUpperCase()}` : result;
}
exports.toLangWithRegion = toLangWithRegion;
exports.lcid = {
af_ZA: 1078,
am_ET: 1118,

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,4 @@
import { Nullish } from "builder-util-runtime";
import { PlatformPackager } from "../platformPackager";
export declare function getLicenseAssets(fileNames: Array<string>, packager: PlatformPackager<any>): {
file: string;
@ -5,7 +6,7 @@ export declare function getLicenseAssets(fileNames: Array<string>, packager: Pla
langWithRegion: string;
langName: any;
}[];
export declare function getNotLocalizedLicenseFile(custom: string | null | undefined, packager: PlatformPackager<any>, supportedExtension?: Array<string>): Promise<string | null>;
export declare function getNotLocalizedLicenseFile(custom: string | Nullish, packager: PlatformPackager<any>, supportedExtension?: Array<string>): Promise<string | null>;
export declare function getLicenseFiles(packager: PlatformPackager<any>): Promise<Array<LicenseFile>>;
export interface LicenseFile {
file: string;

View file

@ -1,6 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLicenseFiles = exports.getNotLocalizedLicenseFile = exports.getLicenseAssets = void 0;
exports.getLicenseAssets = getLicenseAssets;
exports.getNotLocalizedLicenseFile = getNotLocalizedLicenseFile;
exports.getLicenseFiles = getLicenseFiles;
const path = require("path");
const langs_1 = require("./langs");
function getLicenseAssets(fileNames, packager) {
@ -19,12 +21,11 @@ function getLicenseAssets(fileNames, packager) {
}
else {
lang = lang.toLowerCase();
langWithRegion = langs_1.toLangWithRegion(lang);
langWithRegion = (0, langs_1.toLangWithRegion)(lang);
}
return { file: path.join(packager.buildResourcesDir, file), lang, langWithRegion, langName: langs_1.langIdToName[lang] };
});
}
exports.getLicenseAssets = getLicenseAssets;
async function getNotLocalizedLicenseFile(custom, packager, supportedExtension = ["rtf", "txt", "html"]) {
const possibleFiles = [];
for (const name of ["license", "eula"]) {
@ -37,12 +38,10 @@ async function getNotLocalizedLicenseFile(custom, packager, supportedExtension =
}
return await packager.getResource(custom, ...possibleFiles);
}
exports.getNotLocalizedLicenseFile = getNotLocalizedLicenseFile;
async function getLicenseFiles(packager) {
return getLicenseAssets((await packager.resourceList).filter(it => {
const name = it.toLowerCase();
return (name.startsWith("license_") || name.startsWith("eula_")) && (name.endsWith(".rtf") || name.endsWith(".txt"));
return (name.startsWith("license_") || name.startsWith("eula_")) && (name.endsWith(".rtf") || name.endsWith(".txt") || name.endsWith(".html"));
}), packager);
}
exports.getLicenseFiles = getLicenseFiles;
//# sourceMappingURL=license.js.map

View file

@ -1 +1 @@
{"version":3,"file":"license.js","sourceRoot":"","sources":["../../src/util/license.ts"],"names":[],"mappings":";;;AAAA,6BAA4B;AAC5B,mCAAwD;AAGxD,SAAgB,gBAAgB,CAAC,SAAwB,EAAE,QAA+B;IACxF,OAAO,SAAS;SACb,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACb,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QACtC,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QACtC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAA;IACjD,CAAC,CAAC;SACD,GAAG,CAAC,IAAI,CAAC,EAAE;QACV,IAAI,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,CAAA;QACtC,IAAI,cAAc,CAAA;QAClB,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;YACtB,cAAc,GAAG,IAAI,CAAA;YACrB,IAAI,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;SACtD;aAAM;YACL,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;YACzB,cAAc,GAAG,wBAAgB,CAAC,IAAI,CAAC,CAAA;SACxC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAG,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAA;IAC3H,CAAC,CAAC,CAAA;AACN,CAAC;AAnBD,4CAmBC;AAEM,KAAK,UAAU,0BAA0B,CAC9C,MAAiC,EACjC,QAA+B,EAC/B,qBAAoC,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC;IAE1D,MAAM,aAAa,GAAkB,EAAE,CAAA;IACvC,KAAK,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE;QACtC,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE;YACpC,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC,CAAA;YACpC,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,EAAE,CAAC,CAAA;YAClD,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;YAClD,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;SACjE;KACF;IAED,OAAO,MAAM,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,aAAa,CAAC,CAAA;AAC7D,CAAC;AAhBD,gEAgBC;AAEM,KAAK,UAAU,eAAe,CAAC,QAA+B;IACnE,OAAO,gBAAgB,CACrB,CAAC,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;QACxC,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,EAAE,CAAA;QAC7B,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAA;IACtH,CAAC,CAAC,EACF,QAAQ,CACT,CAAA;AACH,CAAC;AARD,0CAQC","sourcesContent":["import * as path from \"path\"\nimport { langIdToName, toLangWithRegion } from \"./langs\"\nimport { PlatformPackager } from \"../platformPackager\"\n\nexport function getLicenseAssets(fileNames: Array<string>, packager: PlatformPackager<any>) {\n return fileNames\n .sort((a, b) => {\n const aW = a.includes(\"_en\") ? 0 : 100\n const bW = b.includes(\"_en\") ? 0 : 100\n return aW === bW ? a.localeCompare(b) : aW - bW\n })\n .map(file => {\n let lang = /_([^.]+)\\./.exec(file)![1]\n let langWithRegion\n if (lang.includes(\"_\")) {\n langWithRegion = lang\n lang = langWithRegion.substring(0, lang.indexOf(\"_\"))\n } else {\n lang = lang.toLowerCase()\n langWithRegion = toLangWithRegion(lang)\n }\n return { file: path.join(packager.buildResourcesDir, file), lang, langWithRegion, langName: (langIdToName as any)[lang] }\n })\n}\n\nexport async function getNotLocalizedLicenseFile(\n custom: string | null | undefined,\n packager: PlatformPackager<any>,\n supportedExtension: Array<string> = [\"rtf\", \"txt\", \"html\"]\n): Promise<string | null> {\n const possibleFiles: Array<string> = []\n for (const name of [\"license\", \"eula\"]) {\n for (const ext of supportedExtension) {\n possibleFiles.push(`${name}.${ext}`)\n possibleFiles.push(`${name.toUpperCase()}.${ext}`)\n possibleFiles.push(`${name}.${ext.toUpperCase()}`)\n possibleFiles.push(`${name.toUpperCase()}.${ext.toUpperCase()}`)\n }\n }\n\n return await packager.getResource(custom, ...possibleFiles)\n}\n\nexport async function getLicenseFiles(packager: PlatformPackager<any>): Promise<Array<LicenseFile>> {\n return getLicenseAssets(\n (await packager.resourceList).filter(it => {\n const name = it.toLowerCase()\n return (name.startsWith(\"license_\") || name.startsWith(\"eula_\")) && (name.endsWith(\".rtf\") || name.endsWith(\".txt\"))\n }),\n packager\n )\n}\n\nexport interface LicenseFile {\n file: string\n lang: string\n langWithRegion: string\n langName: string\n}\n"]}
{"version":3,"file":"license.js","sourceRoot":"","sources":["../../src/util/license.ts"],"names":[],"mappings":";;AAKA,4CAmBC;AAED,gEAgBC;AAED,0CAQC;AAnDD,6BAA4B;AAE5B,mCAAwD;AAExD,SAAgB,gBAAgB,CAAC,SAAwB,EAAE,QAA+B;IACxF,OAAO,SAAS;SACb,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACb,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QACtC,MAAM,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QACtC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAA;IACjD,CAAC,CAAC;SACD,GAAG,CAAC,IAAI,CAAC,EAAE;QACV,IAAI,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAE,CAAC,CAAC,CAAC,CAAA;QACtC,IAAI,cAAc,CAAA;QAClB,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACvB,cAAc,GAAG,IAAI,CAAA;YACrB,IAAI,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;QACvD,CAAC;aAAM,CAAC;YACN,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAA;YACzB,cAAc,GAAG,IAAA,wBAAgB,EAAC,IAAI,CAAC,CAAA;QACzC,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,iBAAiB,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAG,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAA;IAC3H,CAAC,CAAC,CAAA;AACN,CAAC;AAEM,KAAK,UAAU,0BAA0B,CAC9C,MAAwB,EACxB,QAA+B,EAC/B,qBAAoC,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC;IAE1D,MAAM,aAAa,GAAkB,EAAE,CAAA;IACvC,KAAK,MAAM,IAAI,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC;QACvC,KAAK,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;YACrC,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,GAAG,EAAE,CAAC,CAAA;YACpC,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,EAAE,CAAC,CAAA;YAClD,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;YAClD,aAAa,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC,CAAA;QAClE,CAAC;IACH,CAAC;IAED,OAAO,MAAM,QAAQ,CAAC,WAAW,CAAC,MAAM,EAAE,GAAG,aAAa,CAAC,CAAA;AAC7D,CAAC;AAEM,KAAK,UAAU,eAAe,CAAC,QAA+B;IACnE,OAAO,gBAAgB,CACrB,CAAC,MAAM,QAAQ,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE;QACxC,MAAM,IAAI,GAAG,EAAE,CAAC,WAAW,EAAE,CAAA;QAC7B,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;IAChJ,CAAC,CAAC,EACF,QAAQ,CACT,CAAA;AACH,CAAC","sourcesContent":["import { Nullish } from \"builder-util-runtime\"\nimport * as path from \"path\"\nimport { PlatformPackager } from \"../platformPackager\"\nimport { langIdToName, toLangWithRegion } from \"./langs\"\n\nexport function getLicenseAssets(fileNames: Array<string>, packager: PlatformPackager<any>) {\n return fileNames\n .sort((a, b) => {\n const aW = a.includes(\"_en\") ? 0 : 100\n const bW = b.includes(\"_en\") ? 0 : 100\n return aW === bW ? a.localeCompare(b) : aW - bW\n })\n .map(file => {\n let lang = /_([^.]+)\\./.exec(file)![1]\n let langWithRegion\n if (lang.includes(\"_\")) {\n langWithRegion = lang\n lang = langWithRegion.substring(0, lang.indexOf(\"_\"))\n } else {\n lang = lang.toLowerCase()\n langWithRegion = toLangWithRegion(lang)\n }\n return { file: path.join(packager.buildResourcesDir, file), lang, langWithRegion, langName: (langIdToName as any)[lang] }\n })\n}\n\nexport async function getNotLocalizedLicenseFile(\n custom: string | Nullish,\n packager: PlatformPackager<any>,\n supportedExtension: Array<string> = [\"rtf\", \"txt\", \"html\"]\n): Promise<string | null> {\n const possibleFiles: Array<string> = []\n for (const name of [\"license\", \"eula\"]) {\n for (const ext of supportedExtension) {\n possibleFiles.push(`${name}.${ext}`)\n possibleFiles.push(`${name.toUpperCase()}.${ext}`)\n possibleFiles.push(`${name}.${ext.toUpperCase()}`)\n possibleFiles.push(`${name.toUpperCase()}.${ext.toUpperCase()}`)\n }\n }\n\n return await packager.getResource(custom, ...possibleFiles)\n}\n\nexport async function getLicenseFiles(packager: PlatformPackager<any>): Promise<Array<LicenseFile>> {\n return getLicenseAssets(\n (await packager.resourceList).filter(it => {\n const name = it.toLowerCase()\n return (name.startsWith(\"license_\") || name.startsWith(\"eula_\")) && (name.endsWith(\".rtf\") || name.endsWith(\".txt\") || name.endsWith(\".html\"))\n }),\n packager\n )\n}\n\nexport interface LicenseFile {\n file: string\n lang: string\n langWithRegion: string\n langName: string\n}\n"]}

View file

@ -0,0 +1,10 @@
export interface AssetCatalogResult {
assetCatalog: Buffer;
icnsFile: Buffer;
}
/**
* Generates an asset catalog and extra assets that are useful for packaging the app.
* @param inputPath The path to the `.icon` file
* @returns The asset catalog and extra assets
*/
export declare function generateAssetCatalogForIcon(inputPath: string): Promise<AssetCatalogResult>;

View file

@ -0,0 +1,102 @@
"use strict";
// Adapted from https://github.com/electron/packager/pull/1806
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateAssetCatalogForIcon = generateAssetCatalogForIcon;
const builder_util_1 = require("builder-util");
const fs = require("fs/promises");
const os = require("node:os");
const path = require("node:path");
const plist = require("plist");
const semver = require("semver");
const INVALID_ACTOOL_VERSION_ERROR = new Error("Failed to check actool version. Is Xcode 26 or higher installed? See output of the `actool --version` CLI command for more details.");
async function checkActoolVersion(tmpDir) {
const acToolOutputFileName = path.resolve(tmpDir, "actool.log");
let versionInfo = undefined;
let acToolOutputFile = null;
let errorQueued = null;
try {
acToolOutputFile = await fs.open(acToolOutputFileName, "w");
await (0, builder_util_1.spawn)("actool", ["--version"], { stdio: ["ignore", acToolOutputFile.fd, acToolOutputFile.fd] });
const acToolVersionOutput = await fs.readFile(acToolOutputFileName, "utf8");
versionInfo = plist.parse(acToolVersionOutput);
}
catch (e) {
errorQueued = e;
}
finally {
if (acToolOutputFile) {
await acToolOutputFile.close();
}
}
if (errorQueued || !versionInfo || !versionInfo["com.apple.actool.version"] || !versionInfo["com.apple.actool.version"]["short-bundle-version"]) {
throw INVALID_ACTOOL_VERSION_ERROR;
}
const acToolVersion = versionInfo["com.apple.actool.version"]["short-bundle-version"];
if (!semver.gte(semver.coerce(acToolVersion), "26.0.0")) {
throw new Error(`Unsupported actool version. Must be on actool 26.0.0 or higher but found ${acToolVersion}. Install Xcode 26 or higher to get a supported version of actool.`);
}
}
/**
* Generates an asset catalog and extra assets that are useful for packaging the app.
* @param inputPath The path to the `.icon` file
* @returns The asset catalog and extra assets
*/
async function generateAssetCatalogForIcon(inputPath) {
const tmpDir = await fs.mkdtemp(path.resolve(os.tmpdir(), "icon-compile-"));
const cleanup = async () => {
await fs.rm(tmpDir, {
recursive: true,
force: true,
});
};
try {
await checkActoolVersion(tmpDir);
}
catch (error) {
await cleanup();
throw error;
}
const iconPath = path.resolve(tmpDir, "Icon.icon");
const outputPath = path.resolve(tmpDir, "out");
try {
await fs.cp(inputPath, iconPath, {
recursive: true,
});
await fs.mkdir(outputPath, {
recursive: true,
});
await (0, builder_util_1.spawn)("actool", [
iconPath,
"--compile",
outputPath,
"--output-format",
"human-readable-text",
"--notices",
"--warnings",
"--output-partial-info-plist",
path.resolve(outputPath, "assetcatalog_generated_info.plist"),
"--app-icon",
"Icon",
"--include-all-app-icons",
"--accent-color",
"AccentColor",
"--enable-on-demand-resources",
"NO",
"--development-region",
"en",
"--target-device",
"mac",
"--minimum-deployment-target",
"26.0",
"--platform",
"macosx",
]);
const assetCatalog = await fs.readFile(path.resolve(outputPath, "Assets.car"));
const icnsFile = await fs.readFile(path.resolve(outputPath, "Icon.icns"));
return { assetCatalog, icnsFile };
}
finally {
await cleanup();
}
}
//# sourceMappingURL=macosIconComposer.js.map

File diff suppressed because one or more lines are too long

View file

@ -1,18 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isMacOsCatalina = exports.isMacOsSierra = exports.isMacOsHighSierra = void 0;
exports.isMacOsHighSierra = isMacOsHighSierra;
exports.isMacOsSierra = isMacOsSierra;
exports.isMacOsCatalina = isMacOsCatalina;
const builder_util_1 = require("builder-util");
const fs_extra_1 = require("fs-extra");
const lazy_val_1 = require("lazy-val");
const semver = require("semver");
const log_1 = require("builder-util/out/log");
const os_1 = require("os");
const semver = require("semver");
const macOsVersion = new lazy_val_1.Lazy(async () => {
const file = await fs_extra_1.readFile("/System/Library/CoreServices/SystemVersion.plist", "utf8");
const file = await (0, fs_extra_1.readFile)("/System/Library/CoreServices/SystemVersion.plist", "utf8");
const matches = /<key>ProductVersion<\/key>[\s\S]*<string>([\d.]+)<\/string>/.exec(file);
if (!matches) {
throw new Error("Couldn't find the macOS version");
}
log_1.log.debug({ version: matches[1] }, "macOS version");
builder_util_1.log.debug({ version: matches[1] }, "macOS version");
return clean(matches[1]);
});
function clean(version) {
@ -23,15 +25,12 @@ async function isOsVersionGreaterThanOrEqualTo(input) {
}
function isMacOsHighSierra() {
// 17.7.0 === 10.13.6
return process.platform === "darwin" && semver.gte(os_1.release(), "17.7.0");
return process.platform === "darwin" && semver.gte((0, os_1.release)(), "17.7.0");
}
exports.isMacOsHighSierra = isMacOsHighSierra;
async function isMacOsSierra() {
return process.platform === "darwin" && (await isOsVersionGreaterThanOrEqualTo("10.12.0"));
}
exports.isMacOsSierra = isMacOsSierra;
function isMacOsCatalina() {
return process.platform === "darwin" && semver.gte(os_1.release(), "19.0.0");
return process.platform === "darwin" && semver.gte((0, os_1.release)(), "19.0.0");
}
exports.isMacOsCatalina = isMacOsCatalina;
//# sourceMappingURL=macosVersion.js.map

View file

@ -1 +1 @@
{"version":3,"file":"macosVersion.js","sourceRoot":"","sources":["../../src/util/macosVersion.ts"],"names":[],"mappings":";;;AAAA,uCAAmC;AACnC,uCAA+B;AAC/B,iCAAgC;AAChC,8CAA0C;AAC1C,2BAAyC;AAEzC,MAAM,YAAY,GAAG,IAAI,eAAI,CAAS,KAAK,IAAI,EAAE;IAC/C,MAAM,IAAI,GAAG,MAAM,mBAAQ,CAAC,kDAAkD,EAAE,MAAM,CAAC,CAAA;IACvF,MAAM,OAAO,GAAG,6DAA6D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxF,IAAI,CAAC,OAAO,EAAE;QACZ,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;KACnD;IACD,SAAG,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC,CAAA;IACnD,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AAC1B,CAAC,CAAC,CAAA;AAEF,SAAS,KAAK,CAAC,OAAe;IAC5B,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO,CAAA;AACnE,CAAC;AAED,KAAK,UAAU,+BAA+B,CAAC,KAAa;IAC1D,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;AAC3D,CAAC;AAED,SAAgB,iBAAiB;IAC/B,qBAAqB;IACrB,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,YAAS,EAAE,EAAE,QAAQ,CAAC,CAAA;AAC3E,CAAC;AAHD,8CAGC;AAEM,KAAK,UAAU,aAAa;IACjC,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,+BAA+B,CAAC,SAAS,CAAC,CAAC,CAAA;AAC5F,CAAC;AAFD,sCAEC;AAED,SAAgB,eAAe;IAC7B,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,YAAS,EAAE,EAAE,QAAQ,CAAC,CAAA;AAC3E,CAAC;AAFD,0CAEC","sourcesContent":["import { readFile } from \"fs-extra\"\nimport { Lazy } from \"lazy-val\"\nimport * as semver from \"semver\"\nimport { log } from \"builder-util/out/log\"\nimport { release as osRelease } from \"os\"\n\nconst macOsVersion = new Lazy<string>(async () => {\n const file = await readFile(\"/System/Library/CoreServices/SystemVersion.plist\", \"utf8\")\n const matches = /<key>ProductVersion<\\/key>[\\s\\S]*<string>([\\d.]+)<\\/string>/.exec(file)\n if (!matches) {\n throw new Error(\"Couldn't find the macOS version\")\n }\n log.debug({ version: matches[1] }, \"macOS version\")\n return clean(matches[1])\n})\n\nfunction clean(version: string) {\n return version.split(\".\").length === 2 ? `${version}.0` : version\n}\n\nasync function isOsVersionGreaterThanOrEqualTo(input: string) {\n return semver.gte(await macOsVersion.value, clean(input))\n}\n\nexport function isMacOsHighSierra(): boolean {\n // 17.7.0 === 10.13.6\n return process.platform === \"darwin\" && semver.gte(osRelease(), \"17.7.0\")\n}\n\nexport async function isMacOsSierra() {\n return process.platform === \"darwin\" && (await isOsVersionGreaterThanOrEqualTo(\"10.12.0\"))\n}\n\nexport function isMacOsCatalina() {\n return process.platform === \"darwin\" && semver.gte(osRelease(), \"19.0.0\")\n}\n"]}
{"version":3,"file":"macosVersion.js","sourceRoot":"","sources":["../../src/util/macosVersion.ts"],"names":[],"mappings":";;AAwBA,8CAGC;AAED,sCAEC;AAED,0CAEC;AAnCD,+CAAkC;AAClC,uCAAmC;AACnC,uCAA+B;AAC/B,2BAAyC;AACzC,iCAAgC;AAEhC,MAAM,YAAY,GAAG,IAAI,eAAI,CAAS,KAAK,IAAI,EAAE;IAC/C,MAAM,IAAI,GAAG,MAAM,IAAA,mBAAQ,EAAC,kDAAkD,EAAE,MAAM,CAAC,CAAA;IACvF,MAAM,OAAO,GAAG,6DAA6D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxF,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;IACD,kBAAG,CAAC,KAAK,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC,CAAA;IACnD,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AAC1B,CAAC,CAAC,CAAA;AAEF,SAAS,KAAK,CAAC,OAAe;IAC5B,OAAO,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC,CAAC,OAAO,CAAA;AACnE,CAAC;AAED,KAAK,UAAU,+BAA+B,CAAC,KAAa;IAC1D,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAA;AAC3D,CAAC;AAED,SAAgB,iBAAiB;IAC/B,qBAAqB;IACrB,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,IAAA,YAAS,GAAE,EAAE,QAAQ,CAAC,CAAA;AAC3E,CAAC;AAEM,KAAK,UAAU,aAAa;IACjC,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,+BAA+B,CAAC,SAAS,CAAC,CAAC,CAAA;AAC5F,CAAC;AAED,SAAgB,eAAe;IAC7B,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,IAAA,YAAS,GAAE,EAAE,QAAQ,CAAC,CAAA;AAC3E,CAAC","sourcesContent":["import { log } from \"builder-util\"\nimport { readFile } from \"fs-extra\"\nimport { Lazy } from \"lazy-val\"\nimport { release as osRelease } from \"os\"\nimport * as semver from \"semver\"\n\nconst macOsVersion = new Lazy<string>(async () => {\n const file = await readFile(\"/System/Library/CoreServices/SystemVersion.plist\", \"utf8\")\n const matches = /<key>ProductVersion<\\/key>[\\s\\S]*<string>([\\d.]+)<\\/string>/.exec(file)\n if (!matches) {\n throw new Error(\"Couldn't find the macOS version\")\n }\n log.debug({ version: matches[1] }, \"macOS version\")\n return clean(matches[1])\n})\n\nfunction clean(version: string) {\n return version.split(\".\").length === 2 ? `${version}.0` : version\n}\n\nasync function isOsVersionGreaterThanOrEqualTo(input: string) {\n return semver.gte(await macOsVersion.value, clean(input))\n}\n\nexport function isMacOsHighSierra(): boolean {\n // 17.7.0 === 10.13.6\n return process.platform === \"darwin\" && semver.gte(osRelease(), \"17.7.0\")\n}\n\nexport async function isMacOsSierra() {\n return process.platform === \"darwin\" && (await isOsVersionGreaterThanOrEqualTo(\"10.12.0\"))\n}\n\nexport function isMacOsCatalina() {\n return process.platform === \"darwin\" && semver.gte(osRelease(), \"19.0.0\")\n}\n"]}

View file

@ -1,2 +1,3 @@
import { Nullish } from "builder-util-runtime";
import { AppInfo } from "../appInfo";
export declare function expandMacro(pattern: string, arch: string | null | undefined, appInfo: AppInfo, extra?: any, isProductNameSanitized?: boolean): string;
export declare function expandMacro(pattern: string, arch: string | Nullish, appInfo: AppInfo, extra?: any, isProductNameSanitized?: boolean): string;

View file

@ -1,6 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.expandMacro = void 0;
exports.expandMacro = expandMacro;
const builder_util_1 = require("builder-util");
function expandMacro(pattern, arch, appInfo, extra = {}, isProductNameSanitized = true) {
if (arch == null) {
@ -45,6 +45,9 @@ function expandMacro(pattern, arch, appInfo, extra = {}, isProductNameSanitized
if (envValue == null) {
throw new builder_util_1.InvalidConfigurationError(`cannot expand pattern "${pattern}": env ${envName} is not defined`, "ERR_ELECTRON_BUILDER_ENV_NOT_DEFINED");
}
if (/TOKEN|SECRET|KEY|PASSWORD|CREDENTIAL/i.test(envName)) {
builder_util_1.log.warn({ envName, pattern }, "macro expansion includes an env var that may contain a secret — verify this is intentional");
}
return envValue;
}
const value = extra[p1];
@ -58,5 +61,4 @@ function expandMacro(pattern, arch, appInfo, extra = {}, isProductNameSanitized
}
});
}
exports.expandMacro = expandMacro;
//# sourceMappingURL=macroExpander.js.map

View file

@ -1 +1 @@
{"version":3,"file":"macroExpander.js","sourceRoot":"","sources":["../../src/util/macroExpander.ts"],"names":[],"mappings":";;;AAAA,+CAAwD;AAGxD,SAAgB,WAAW,CAAC,OAAe,EAAE,IAA+B,EAAE,OAAgB,EAAE,QAAa,EAAE,EAAE,sBAAsB,GAAG,IAAI;IAC5I,IAAI,IAAI,IAAI,IAAI,EAAE;QAChB,OAAO,GAAG,OAAO;YACf,uDAAuD;aACtD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;YACxB,uDAAuD;aACtD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;YACxB,uDAAuD;aACtD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;YACxB,uDAAuD;aACtD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;KAC3B;IAED,OAAO,OAAO,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAAC,KAAK,EAAE,EAAE,EAAU,EAAE;QACpE,QAAQ,EAAE,EAAE;YACV,KAAK,aAAa;gBAChB,OAAO,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAA;YAEpF,KAAK,MAAM;gBACT,IAAI,IAAI,IAAI,IAAI,EAAE;oBAChB,wCAAwC;oBACxC,OAAO,EAAE,CAAA;iBACV;gBACD,OAAO,IAAI,CAAA;YAEb,KAAK,QAAQ,CAAC,CAAC;gBACb,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAA;gBACvC,IAAI,WAAW,IAAI,IAAI,EAAE;oBACvB,MAAM,IAAI,wCAAyB,CAAC,0BAA0B,OAAO,4BAA4B,EAAE,yCAAyC,CAAC,CAAA;iBAC9I;gBACD,OAAO,WAAW,CAAA;aACnB;YAED,KAAK,UAAU;gBACb,OAAO,OAAO,CAAC,QAAQ,CAAA;YAEzB,KAAK,SAAS;gBACZ,OAAO,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAA;YAEpC,OAAO,CAAC,CAAC;gBACP,IAAI,EAAE,IAAI,OAAO,EAAE;oBACjB,OAAQ,OAAe,CAAC,EAAE,CAAC,CAAA;iBAC5B;gBAED,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;oBACzB,MAAM,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;oBAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;oBACrC,IAAI,QAAQ,IAAI,IAAI,EAAE;wBACpB,MAAM,IAAI,wCAAyB,CAAC,0BAA0B,OAAO,UAAU,OAAO,iBAAiB,EAAE,sCAAsC,CAAC,CAAA;qBACjJ;oBACD,OAAO,QAAQ,CAAA;iBAChB;gBAED,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,CAAA;gBACvB,IAAI,KAAK,IAAI,IAAI,EAAE;oBACjB,MAAM,IAAI,wCAAyB,CAAC,0BAA0B,OAAO,YAAY,EAAE,iBAAiB,EAAE,wCAAwC,CAAC,CAAA;iBAChJ;qBAAM;oBACL,OAAO,KAAK,CAAA;iBACb;aACF;SACF;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AA9DD,kCA8DC","sourcesContent":["import { InvalidConfigurationError } from \"builder-util\"\nimport { AppInfo } from \"../appInfo\"\n\nexport function expandMacro(pattern: string, arch: string | null | undefined, appInfo: AppInfo, extra: any = {}, isProductNameSanitized = true): string {\n if (arch == null) {\n pattern = pattern\n // tslint:disable-next-line:no-invalid-template-strings\n .replace(\"-${arch}\", \"\")\n // tslint:disable-next-line:no-invalid-template-strings\n .replace(\" ${arch}\", \"\")\n // tslint:disable-next-line:no-invalid-template-strings\n .replace(\"_${arch}\", \"\")\n // tslint:disable-next-line:no-invalid-template-strings\n .replace(\"/${arch}\", \"\")\n }\n\n return pattern.replace(/\\${([_a-zA-Z./*+]+)}/g, (match, p1): string => {\n switch (p1) {\n case \"productName\":\n return isProductNameSanitized ? appInfo.sanitizedProductName : appInfo.productName\n\n case \"arch\":\n if (arch == null) {\n // see above, we remove macro if no arch\n return \"\"\n }\n return arch\n\n case \"author\": {\n const companyName = appInfo.companyName\n if (companyName == null) {\n throw new InvalidConfigurationError(`cannot expand pattern \"${pattern}\": author is not specified`, \"ERR_ELECTRON_BUILDER_AUTHOR_UNSPECIFIED\")\n }\n return companyName\n }\n\n case \"platform\":\n return process.platform\n\n case \"channel\":\n return appInfo.channel || \"latest\"\n\n default: {\n if (p1 in appInfo) {\n return (appInfo as any)[p1]\n }\n\n if (p1.startsWith(\"env.\")) {\n const envName = p1.substring(\"env.\".length)\n const envValue = process.env[envName]\n if (envValue == null) {\n throw new InvalidConfigurationError(`cannot expand pattern \"${pattern}\": env ${envName} is not defined`, \"ERR_ELECTRON_BUILDER_ENV_NOT_DEFINED\")\n }\n return envValue\n }\n\n const value = extra[p1]\n if (value == null) {\n throw new InvalidConfigurationError(`cannot expand pattern \"${pattern}\": macro ${p1} is not defined`, \"ERR_ELECTRON_BUILDER_MACRO_NOT_DEFINED\")\n } else {\n return value\n }\n }\n }\n })\n}\n"]}
{"version":3,"file":"macroExpander.js","sourceRoot":"","sources":["../../src/util/macroExpander.ts"],"names":[],"mappings":";;AAIA,kCAiEC;AArED,+CAA6D;AAI7D,SAAgB,WAAW,CAAC,OAAe,EAAE,IAAsB,EAAE,OAAgB,EAAE,QAAa,EAAE,EAAE,sBAAsB,GAAG,IAAI;IACnI,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;QACjB,OAAO,GAAG,OAAO;YACf,uDAAuD;aACtD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;YACxB,uDAAuD;aACtD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;YACxB,uDAAuD;aACtD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;YACxB,uDAAuD;aACtD,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;IAC5B,CAAC;IAED,OAAO,OAAO,CAAC,OAAO,CAAC,uBAAuB,EAAE,CAAC,KAAK,EAAE,EAAE,EAAU,EAAE;QACpE,QAAQ,EAAE,EAAE,CAAC;YACX,KAAK,aAAa;gBAChB,OAAO,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAA;YAEpF,KAAK,MAAM;gBACT,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;oBACjB,wCAAwC;oBACxC,OAAO,EAAE,CAAA;gBACX,CAAC;gBACD,OAAO,IAAI,CAAA;YAEb,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAA;gBACvC,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;oBACxB,MAAM,IAAI,wCAAyB,CAAC,0BAA0B,OAAO,4BAA4B,EAAE,yCAAyC,CAAC,CAAA;gBAC/I,CAAC;gBACD,OAAO,WAAW,CAAA;YACpB,CAAC;YAED,KAAK,UAAU;gBACb,OAAO,OAAO,CAAC,QAAQ,CAAA;YAEzB,KAAK,SAAS;gBACZ,OAAO,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAA;YAEpC,OAAO,CAAC,CAAC,CAAC;gBACR,IAAI,EAAE,IAAI,OAAO,EAAE,CAAC;oBAClB,OAAQ,OAAe,CAAC,EAAE,CAAC,CAAA;gBAC7B,CAAC;gBAED,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;oBAC1B,MAAM,OAAO,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;oBAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;oBACrC,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;wBACrB,MAAM,IAAI,wCAAyB,CAAC,0BAA0B,OAAO,UAAU,OAAO,iBAAiB,EAAE,sCAAsC,CAAC,CAAA;oBAClJ,CAAC;oBACD,IAAI,uCAAuC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;wBAC1D,kBAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,4FAA4F,CAAC,CAAA;oBAC9H,CAAC;oBACD,OAAO,QAAQ,CAAA;gBACjB,CAAC;gBAED,MAAM,KAAK,GAAG,KAAK,CAAC,EAAE,CAAC,CAAA;gBACvB,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;oBAClB,MAAM,IAAI,wCAAyB,CAAC,0BAA0B,OAAO,YAAY,EAAE,iBAAiB,EAAE,wCAAwC,CAAC,CAAA;gBACjJ,CAAC;qBAAM,CAAC;oBACN,OAAO,KAAK,CAAA;gBACd,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { InvalidConfigurationError, log } from \"builder-util\"\nimport { Nullish } from \"builder-util-runtime\"\nimport { AppInfo } from \"../appInfo\"\n\nexport function expandMacro(pattern: string, arch: string | Nullish, appInfo: AppInfo, extra: any = {}, isProductNameSanitized = true): string {\n if (arch == null) {\n pattern = pattern\n // tslint:disable-next-line:no-invalid-template-strings\n .replace(\"-${arch}\", \"\")\n // tslint:disable-next-line:no-invalid-template-strings\n .replace(\" ${arch}\", \"\")\n // tslint:disable-next-line:no-invalid-template-strings\n .replace(\"_${arch}\", \"\")\n // tslint:disable-next-line:no-invalid-template-strings\n .replace(\"/${arch}\", \"\")\n }\n\n return pattern.replace(/\\${([_a-zA-Z./*+]+)}/g, (match, p1): string => {\n switch (p1) {\n case \"productName\":\n return isProductNameSanitized ? appInfo.sanitizedProductName : appInfo.productName\n\n case \"arch\":\n if (arch == null) {\n // see above, we remove macro if no arch\n return \"\"\n }\n return arch\n\n case \"author\": {\n const companyName = appInfo.companyName\n if (companyName == null) {\n throw new InvalidConfigurationError(`cannot expand pattern \"${pattern}\": author is not specified`, \"ERR_ELECTRON_BUILDER_AUTHOR_UNSPECIFIED\")\n }\n return companyName\n }\n\n case \"platform\":\n return process.platform\n\n case \"channel\":\n return appInfo.channel || \"latest\"\n\n default: {\n if (p1 in appInfo) {\n return (appInfo as any)[p1]\n }\n\n if (p1.startsWith(\"env.\")) {\n const envName = p1.substring(\"env.\".length)\n const envValue = process.env[envName]\n if (envValue == null) {\n throw new InvalidConfigurationError(`cannot expand pattern \"${pattern}\": env ${envName} is not defined`, \"ERR_ELECTRON_BUILDER_ENV_NOT_DEFINED\")\n }\n if (/TOKEN|SECRET|KEY|PASSWORD|CREDENTIAL/i.test(envName)) {\n log.warn({ envName, pattern }, \"macro expansion includes an env var that may contain a secret — verify this is intentional\")\n }\n return envValue\n }\n\n const value = extra[p1]\n if (value == null) {\n throw new InvalidConfigurationError(`cannot expand pattern \"${pattern}\": macro ${p1} is not defined`, \"ERR_ELECTRON_BUILDER_MACRO_NOT_DEFINED\")\n } else {\n return value\n }\n }\n }\n })\n}\n"]}

View file

@ -1,15 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.normalizePackageData = void 0;
const semver = require("semver");
exports.normalizePackageData = normalizePackageData;
const hosted_git_info_1 = require("hosted-git-info");
const url = require("url");
const semver = require("semver");
const pathManager_1 = require("./pathManager");
function normalizePackageData(data) {
for (const it of check) {
it(data);
}
}
exports.normalizePackageData = normalizePackageData;
const depTypes = ["dependencies", "devDependencies", "optionalDependencies"];
const check = [
function (data) {
@ -23,7 +22,7 @@ const check = [
};
}
if (data.repository != null && data.repository.url) {
const hosted = hosted_git_info_1.fromUrl(data.repository.url);
const hosted = (0, hosted_git_info_1.fromUrl)(data.repository.url);
if (hosted) {
data.repository.url = hosted.getDefaultRepresentation() == "shortcut" ? hosted.https() : hosted.toString();
}
@ -81,7 +80,7 @@ const check = [
if (typeof r !== "string") {
delete data[deps][d];
}
const hosted = hosted_git_info_1.fromUrl(data[deps][d]);
const hosted = (0, hosted_git_info_1.fromUrl)(data[deps][d]);
if (hosted) {
data[deps][d] = hosted.toString();
}
@ -89,8 +88,9 @@ const check = [
}
},
function fixBugsField(data) {
var _a, _b;
if (!data.bugs && data.repository && data.repository.url) {
const hosted = hosted_git_info_1.fromUrl(data.repository.url);
const hosted = (0, hosted_git_info_1.fromUrl)(data.repository.url);
if (hosted && hosted.bugs()) {
data.bugs = { url: hosted.bugs() };
}
@ -101,7 +101,7 @@ const check = [
if (emailRe.test(data.bugs)) {
data.bugs = { email: data.bugs };
}
else if (url.parse(data.bugs).protocol) {
else if ((_a = (0, pathManager_1.parseUrl)(data.bugs)) === null || _a === void 0 ? void 0 : _a.protocol) {
data.bugs = { url: data.bugs };
}
}
@ -110,7 +110,7 @@ const check = [
const oldBugs = data.bugs;
data.bugs = {};
if (oldBugs.url) {
if (typeof oldBugs.url == "string" && url.parse(oldBugs.url).protocol) {
if (typeof oldBugs.url == "string" && ((_b = (0, pathManager_1.parseUrl)(oldBugs.url)) === null || _b === void 0 ? void 0 : _b.protocol)) {
data.bugs.url = oldBugs.url;
}
}
@ -171,8 +171,9 @@ const check = [
ensureValidName(data.name);
},
function fixHomepageField(data) {
var _a;
if (!data.homepage && data.repository && data.repository.url) {
const hosted = hosted_git_info_1.fromUrl(data.repository.url);
const hosted = (0, hosted_git_info_1.fromUrl)(data.repository.url);
if (hosted && hosted.docs()) {
data.homepage = hosted.docs();
}
@ -183,7 +184,7 @@ const check = [
if (typeof data.homepage !== "string") {
delete data.homepage;
}
if (!url.parse(data.homepage).protocol) {
if (!((_a = (0, pathManager_1.parseUrl)(data.homepage)) === null || _a === void 0 ? void 0 : _a.protocol)) {
data.homepage = `https://${data.homepage}`;
}
return;
@ -208,7 +209,7 @@ function fixBundleDependenciesField(data) {
if (!data.dependencies) {
data.dependencies = {};
}
if (!("bd" in data.dependencies)) {
if (!Object.prototype.hasOwnProperty.call(data.dependencies, bd)) {
data.dependencies[bd] = "*";
}
return true;
@ -295,9 +296,9 @@ function depObjectify(deps) {
return typeof d === "string";
})
.forEach(function (d) {
d = d.trim().split(/(:?[@\s><=])/);
const dn = d.shift();
let dv = d.join("");
const arr = d.trim().split(/(:?[@\s><=])/);
const dn = arr.shift();
let dv = arr.join("");
dv = dv.trim();
dv = dv.replace(/^@/, "");
o[dn] = dv;

File diff suppressed because one or more lines are too long

View file

@ -1,9 +1,6 @@
import { Lazy } from "lazy-val";
export declare function createLazyProductionDeps(projectDir: string, excludedDependencies: Array<string> | null): Lazy<any[]>;
export interface NodeModuleDirInfo {
readonly dir: string;
readonly deps: Array<NodeModuleInfo>;
}
export interface NodeModuleInfo {
readonly name: string;
readonly version: string;
readonly dir: string;
readonly dependencies?: Array<NodeModuleInfo>;
}

View file

@ -1,18 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createLazyProductionDeps = void 0;
const lazy_val_1 = require("lazy-val");
const appBuilder_1 = require("./appBuilder");
function createLazyProductionDeps(projectDir, excludedDependencies) {
return new lazy_val_1.Lazy(async () => {
const args = ["node-dep-tree", "--dir", projectDir];
if (excludedDependencies != null) {
for (const name of excludedDependencies) {
args.push("--exclude-dep", name);
}
}
return appBuilder_1.executeAppBuilderAsJson(args);
});
}
exports.createLazyProductionDeps = createLazyProductionDeps;
//# sourceMappingURL=packageDependencies.js.map

View file

@ -1 +1 @@
{"version":3,"file":"packageDependencies.js","sourceRoot":"","sources":["../../src/util/packageDependencies.ts"],"names":[],"mappings":";;;AAAA,uCAA+B;AAC/B,6CAAsD;AAEtD,SAAgB,wBAAwB,CAAC,UAAkB,EAAE,oBAA0C;IACrG,OAAO,IAAI,eAAI,CAAC,KAAK,IAAI,EAAE;QACzB,MAAM,IAAI,GAAG,CAAC,eAAe,EAAE,OAAO,EAAE,UAAU,CAAC,CAAA;QACnD,IAAI,oBAAoB,IAAI,IAAI,EAAE;YAChC,KAAK,MAAM,IAAI,IAAI,oBAAoB,EAAE;gBACvC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAA;aACjC;SACF;QACD,OAAO,oCAAuB,CAAa,IAAI,CAAC,CAAA;IAClD,CAAC,CAAC,CAAA;AACJ,CAAC;AAVD,4DAUC","sourcesContent":["import { Lazy } from \"lazy-val\"\nimport { executeAppBuilderAsJson } from \"./appBuilder\"\n\nexport function createLazyProductionDeps(projectDir: string, excludedDependencies: Array<string> | null) {\n return new Lazy(async () => {\n const args = [\"node-dep-tree\", \"--dir\", projectDir]\n if (excludedDependencies != null) {\n for (const name of excludedDependencies) {\n args.push(\"--exclude-dep\", name)\n }\n }\n return executeAppBuilderAsJson<Array<any>>(args)\n })\n}\n\nexport interface NodeModuleDirInfo {\n readonly dir: string\n readonly deps: Array<NodeModuleInfo>\n}\n\nexport interface NodeModuleInfo {\n readonly name: string\n}\n"]}
{"version":3,"file":"packageDependencies.js","sourceRoot":"","sources":["../../src/util/packageDependencies.ts"],"names":[],"mappings":"","sourcesContent":["export interface NodeModuleInfo {\n readonly name: string\n readonly version: string\n readonly dir: string\n readonly dependencies?: Array<NodeModuleInfo>\n}\n"]}

View file

@ -1,6 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkMetadata = exports.readPackageJson = void 0;
exports.readPackageJson = readPackageJson;
exports.checkMetadata = checkMetadata;
const builder_util_1 = require("builder-util");
const fs_extra_1 = require("fs-extra");
const path = require("path");
@ -8,24 +9,23 @@ const semver = require("semver");
const normalizePackageData_1 = require("./normalizePackageData");
/** @internal */
async function readPackageJson(file) {
const data = await fs_extra_1.readJson(file);
const data = await (0, fs_extra_1.readJson)(file);
await authors(file, data);
// remove not required fields because can be used for remote build
delete data.scripts;
delete data.readme;
normalizePackageData_1.normalizePackageData(data);
(0, normalizePackageData_1.normalizePackageData)(data);
return data;
}
exports.readPackageJson = readPackageJson;
async function authors(file, data) {
if (data.contributors != null) {
return;
}
let authorData;
try {
authorData = await fs_extra_1.readFile(path.resolve(path.dirname(file), "AUTHORS"), "utf8");
authorData = await (0, fs_extra_1.readFile)(path.resolve(path.dirname(file), "AUTHORS"), "utf8");
}
catch (ignored) {
catch (_ignored) {
return;
}
data.contributors = authorData.split(/\r?\n/g).map(it => it.replace(/^\s*#.*$/, "").trim());
@ -37,7 +37,7 @@ function checkMetadata(metadata, devMetadata, appPackageFile, devAppPackageFile)
errors.push(`Please specify '${missedFieldName}' in the package.json (${appPackageFile})`);
};
const checkNotEmpty = (name, value) => {
if (builder_util_1.isEmptyOrSpaces(value)) {
if ((0, builder_util_1.isEmptyOrSpaces)(value)) {
reportError(name);
}
};
@ -45,7 +45,7 @@ function checkMetadata(metadata, devMetadata, appPackageFile, devAppPackageFile)
errors.push(`"directories" in the root is deprecated, please specify in the "build"`);
}
checkNotEmpty("name", metadata.name);
if (builder_util_1.isEmptyOrSpaces(metadata.description)) {
if ((0, builder_util_1.isEmptyOrSpaces)(metadata.description)) {
builder_util_1.log.warn({ appPackageFile }, `description is missed in the package.json`);
}
if (metadata.author == null) {
@ -59,14 +59,13 @@ function checkMetadata(metadata, devMetadata, appPackageFile, devAppPackageFile)
}
}
const devDependencies = metadata.devDependencies;
if (devDependencies != null && "electron-rebuild" in devDependencies) {
builder_util_1.log.info('electron-rebuild not required if you use electron-builder, please consider to remove excess dependency from devDependencies\n\nTo ensure your native dependencies are always matched electron version, simply add script `"postinstall": "electron-builder install-app-deps" to your `package.json`');
if (devDependencies != null && ("electron-rebuild" in devDependencies || "@electron/rebuild" in devDependencies)) {
builder_util_1.log.info('@electron/rebuild already used by electron-builder, please consider to remove excess dependency from devDependencies\n\nTo ensure your native dependencies are always matched electron version, simply add script `"postinstall": "electron-builder install-app-deps" to your `package.json`');
}
if (errors.length > 0) {
throw new builder_util_1.InvalidConfigurationError(errors.join("\n"));
}
}
exports.checkMetadata = checkMetadata;
function versionSatisfies(version, range, loose) {
if (version == null) {
return false;
@ -81,10 +80,32 @@ function checkDependencies(dependencies, errors) {
if (dependencies == null) {
return;
}
const updaterVersion = dependencies["electron-updater"];
const requiredElectronUpdaterVersion = "4.0.0";
if (updaterVersion != null && !versionSatisfies(updaterVersion, `>=${requiredElectronUpdaterVersion}`)) {
errors.push(`At least electron-updater ${requiredElectronUpdaterVersion} is recommended by current electron-builder version. Please set electron-updater version to "^${requiredElectronUpdaterVersion}"`);
let updaterVersion = dependencies["electron-updater"];
if (updaterVersion != null) {
// Pick the version out of yarn berry patch syntax
// "patch:electron-updater@npm%3A6.4.1#~/.yarn/patches/electron-updater-npm-6.4.1-ef33e6cc39.patch"
if (updaterVersion.startsWith("patch:")) {
// codeql[js/polynomial-redos] - [^#]+ is a possessive character-class match; linear time, no catastrophic backtracking
const match = updaterVersion.match(/@npm%3A([^#]+)#/);
if (match) {
updaterVersion = match[1];
}
}
// for testing auto-update using workspace electron-updater
const prefixes = ["link:", "file:"];
for (const prefix of prefixes) {
if (updaterVersion.startsWith(prefix)) {
const normalized = path.normalize(updaterVersion.substring(prefix.length));
const packageJsonPath = path.isAbsolute(normalized) ? normalized : path.resolve(__dirname, normalized);
const json = (0, fs_extra_1.readJsonSync)(path.join(packageJsonPath, "package.json"));
updaterVersion = json.version;
break;
}
}
const requiredElectronUpdaterVersion = "4.0.0";
if (!versionSatisfies(updaterVersion, `>=${requiredElectronUpdaterVersion}`)) {
errors.push(`At least electron-updater ${requiredElectronUpdaterVersion} is recommended by current electron-builder version. Please set electron-updater version to "^${requiredElectronUpdaterVersion}". Received "${updaterVersion}"`);
}
}
const swVersion = dependencies["electron-builder-squirrel-windows"];
if (swVersion != null && !versionSatisfies(swVersion, ">=20.32.0")) {

File diff suppressed because one or more lines are too long

View file

@ -1,2 +1,3 @@
export declare function getTemplatePath(file: string): string;
export declare function getVendorPath(file?: string): string;
export declare const parseUrl: (url: string) => URL | undefined;

View file

@ -1,14 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getVendorPath = exports.getTemplatePath = void 0;
exports.parseUrl = void 0;
exports.getTemplatePath = getTemplatePath;
exports.getVendorPath = getVendorPath;
const path = require("path");
const root = path.join(__dirname, "..", "..");
function getTemplatePath(file) {
return path.join(root, "templates", file);
}
exports.getTemplatePath = getTemplatePath;
function getVendorPath(file) {
return file == null ? path.join(root, "vendor") : path.join(root, "vendor", file);
}
exports.getVendorPath = getVendorPath;
const parseUrl = (url) => {
try {
return new URL(url);
}
catch {
return undefined;
}
};
exports.parseUrl = parseUrl;
//# sourceMappingURL=pathManager.js.map

View file

@ -1 +1 @@
{"version":3,"file":"pathManager.js","sourceRoot":"","sources":["../../src/util/pathManager.ts"],"names":[],"mappings":";;;AAAA,6BAA4B;AAE5B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;AAE7C,SAAgB,eAAe,CAAC,IAAY;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,CAAA;AAC3C,CAAC;AAFD,0CAEC;AAED,SAAgB,aAAa,CAAC,IAAa;IACzC,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;AACnF,CAAC;AAFD,sCAEC","sourcesContent":["import * as path from \"path\"\n\nconst root = path.join(__dirname, \"..\", \"..\")\n\nexport function getTemplatePath(file: string) {\n return path.join(root, \"templates\", file)\n}\n\nexport function getVendorPath(file?: string) {\n return file == null ? path.join(root, \"vendor\") : path.join(root, \"vendor\", file)\n}\n"]}
{"version":3,"file":"pathManager.js","sourceRoot":"","sources":["../../src/util/pathManager.ts"],"names":[],"mappings":";;;AAIA,0CAEC;AAED,sCAEC;AAVD,6BAA4B;AAE5B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;AAE7C,SAAgB,eAAe,CAAC,IAAY;IAC1C,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,CAAC,CAAA;AAC3C,CAAC;AAED,SAAgB,aAAa,CAAC,IAAa;IACzC,OAAO,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;AACnF,CAAC;AAEM,MAAM,QAAQ,GAAG,CAAC,GAAW,EAAmB,EAAE;IACvD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;IACrB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC,CAAA;AANY,QAAA,QAAQ,YAMpB","sourcesContent":["import * as path from \"path\"\n\nconst root = path.join(__dirname, \"..\", \"..\")\n\nexport function getTemplatePath(file: string) {\n return path.join(root, \"templates\", file)\n}\n\nexport function getVendorPath(file?: string) {\n return file == null ? path.join(root, \"vendor\") : path.join(root, \"vendor\", file)\n}\n\nexport const parseUrl = (url: string): URL | undefined => {\n try {\n return new URL(url)\n } catch {\n return undefined\n }\n}\n"]}

View file

@ -0,0 +1,7 @@
type PlistValue = string | number | boolean | Date | PlistObject | PlistValue[];
interface PlistObject {
[key: string]: PlistValue;
}
export declare function savePlistFile(path: string, data: PlistValue): Promise<void>;
export declare function parsePlistFile<T>(file: string): Promise<T>;
export type { PlistValue, PlistObject };

View file

@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.savePlistFile = savePlistFile;
exports.parsePlistFile = parsePlistFile;
const plist_1 = require("plist");
const fs = require("fs/promises");
function sortObjectKeys(obj) {
if (obj === null || typeof obj !== "object") {
return obj;
}
if (Array.isArray(obj)) {
return obj.map(sortObjectKeys);
}
const result = {};
Object.keys(obj)
.sort()
.forEach(key => {
result[key] = sortObjectKeys(obj[key]);
});
return result;
}
async function savePlistFile(path, data) {
const sortedData = sortObjectKeys(data);
const plist = (0, plist_1.build)(sortedData);
await fs.writeFile(path, plist);
}
async function parsePlistFile(file) {
const data = await fs.readFile(file, "utf8");
return (0, plist_1.parse)(data);
}
//# sourceMappingURL=plist.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"plist.js","sourceRoot":"","sources":["../../src/util/plist.ts"],"names":[],"mappings":";;AA2BA,sCAIC;AAED,wCAGC;AApCD,iCAAoC;AACpC,kCAAiC;AAQjC,SAAS,cAAc,CAAC,GAAe;IACrC,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;QAC5C,OAAO,GAAG,CAAA;IACZ,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,GAAG,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;IAChC,CAAC;IAED,MAAM,MAAM,GAAgB,EAAE,CAAA;IAC9B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;SACb,IAAI,EAAE;SACN,OAAO,CAAC,GAAG,CAAC,EAAE;QACb,MAAM,CAAC,GAAG,CAAC,GAAG,cAAc,CAAE,GAAmB,CAAC,GAAG,CAAC,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IACJ,OAAO,MAAM,CAAA;AACf,CAAC;AAEM,KAAK,UAAU,aAAa,CAAC,IAAY,EAAE,IAAgB;IAChE,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,CAAA;IACvC,MAAM,KAAK,GAAG,IAAA,aAAK,EAAC,UAAU,CAAC,CAAA;IAC/B,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;AACjC,CAAC;AAEM,KAAK,UAAU,cAAc,CAAI,IAAY;IAClD,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAC5C,OAAO,IAAA,aAAK,EAAC,IAAI,CAAM,CAAA;AACzB,CAAC","sourcesContent":["import { build, parse } from \"plist\"\nimport * as fs from \"fs/promises\"\n\ntype PlistValue = string | number | boolean | Date | PlistObject | PlistValue[]\n\ninterface PlistObject {\n [key: string]: PlistValue\n}\n\nfunction sortObjectKeys(obj: PlistValue): PlistValue {\n if (obj === null || typeof obj !== \"object\") {\n return obj\n }\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys)\n }\n\n const result: PlistObject = {}\n Object.keys(obj)\n .sort()\n .forEach(key => {\n result[key] = sortObjectKeys((obj as PlistObject)[key])\n })\n return result\n}\n\nexport async function savePlistFile(path: string, data: PlistValue): Promise<void> {\n const sortedData = sortObjectKeys(data)\n const plist = build(sortedData)\n await fs.writeFile(path, plist)\n}\n\nexport async function parsePlistFile<T>(file: string): Promise<T> {\n const data = await fs.readFile(file, \"utf8\")\n return parse(data) as T\n}\n\nexport type { PlistValue, PlistObject }\n"]}

View file

@ -0,0 +1,2 @@
import type { RebuildOptions } from "@electron/rebuild";
export declare const rebuild: (options: RebuildOptions) => Promise<void>;

View file

@ -0,0 +1,60 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rebuild = void 0;
const builder_util_1 = require("builder-util");
const cp = require("child_process");
const path = require("path");
const rebuild = async (options) => {
var _a, _b;
const { arch } = options;
builder_util_1.log.info({ arch }, `installing native dependencies`);
const child = cp.fork(path.resolve(__dirname, "../../helpers/remote-rebuild.js"), [JSON.stringify(options)], {
stdio: ["pipe", "pipe", "pipe", "ipc"],
});
let pendingError;
(_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", chunk => {
builder_util_1.log.info(chunk.toString());
});
(_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on("data", chunk => {
builder_util_1.log.error(chunk.toString());
});
child.on("message", (message) => {
var _a;
const { moduleName, msg } = message;
switch (msg) {
case "module-found": {
builder_util_1.log.info({ moduleName, arch }, "preparing");
break;
}
case "module-done": {
builder_util_1.log.info({ moduleName, arch }, "finished");
break;
}
case "module-skip": {
(_a = builder_util_1.log.debug) === null || _a === void 0 ? void 0 : _a.call(builder_util_1.log, { moduleName, arch }, "skipped. set ENV=electron-rebuild to determine why");
break;
}
case "rebuild-error": {
pendingError = new Error(message.err.message);
pendingError.stack = message.err.stack;
break;
}
case "rebuild-done": {
builder_util_1.log.info("completed installing native dependencies");
break;
}
}
});
await new Promise((resolve, reject) => {
child.on("exit", code => {
if (code === 0 && !pendingError) {
resolve();
}
else {
reject(pendingError || new Error(`Rebuilder failed with exit code: ${code}`));
}
});
});
};
exports.rebuild = rebuild;
//# sourceMappingURL=rebuild.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"rebuild.js","sourceRoot":"","sources":["../../src/util/rebuild.ts"],"names":[],"mappings":";;;AACA,+CAAkC;AAClC,oCAAmC;AACnC,6BAA4B;AAErB,MAAM,OAAO,GAAG,KAAK,EAAE,OAAuB,EAAiB,EAAE;;IACtE,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IACxB,kBAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,gCAAgC,CAAC,CAAA;IAEpD,MAAM,KAAK,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,iCAAiC,CAAC,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAAE;QAC3G,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC;KACvC,CAAC,CAAA;IAEF,IAAI,YAAmB,CAAA;IAEvB,MAAA,KAAK,CAAC,MAAM,0CAAE,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;QAC/B,kBAAG,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC5B,CAAC,CAAC,CAAA;IACF,MAAA,KAAK,CAAC,MAAM,0CAAE,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;QAC/B,kBAAG,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC7B,CAAC,CAAC,CAAA;IAEF,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,OAAqF,EAAE,EAAE;;QAC5G,MAAM,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,OAAO,CAAA;QACnC,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,cAAc,CAAC,CAAC,CAAC;gBACpB,kBAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,WAAW,CAAC,CAAA;gBAC3C,MAAK;YACP,CAAC;YACD,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,kBAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,UAAU,CAAC,CAAA;gBAC1C,MAAK;YACP,CAAC;YACD,KAAK,aAAa,CAAC,CAAC,CAAC;gBACnB,MAAA,kBAAG,CAAC,KAAK,mEAAG,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,oDAAoD,CAAC,CAAA;gBACvF,MAAK;YACP,CAAC;YACD,KAAK,eAAe,CAAC,CAAC,CAAC;gBACrB,YAAY,GAAG,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;gBAC7C,YAAY,CAAC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAA;gBACtC,MAAK;YACP,CAAC;YACD,KAAK,cAAc,CAAC,CAAC,CAAC;gBACpB,kBAAG,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAA;gBACpD,MAAK;YACP,CAAC;QACH,CAAC;IACH,CAAC,CAAC,CAAA;IAEF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE;YACtB,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;gBAChC,OAAO,EAAE,CAAA;YACX,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,YAAY,IAAI,IAAI,KAAK,CAAC,oCAAoC,IAAI,EAAE,CAAC,CAAC,CAAA;YAC/E,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAA;AArDY,QAAA,OAAO,WAqDnB","sourcesContent":["import type { RebuildOptions } from \"@electron/rebuild\"\nimport { log } from \"builder-util\"\nimport * as cp from \"child_process\"\nimport * as path from \"path\"\n\nexport const rebuild = async (options: RebuildOptions): Promise<void> => {\n const { arch } = options\n log.info({ arch }, `installing native dependencies`)\n\n const child = cp.fork(path.resolve(__dirname, \"../../helpers/remote-rebuild.js\"), [JSON.stringify(options)], {\n stdio: [\"pipe\", \"pipe\", \"pipe\", \"ipc\"],\n })\n\n let pendingError: Error\n\n child.stdout?.on(\"data\", chunk => {\n log.info(chunk.toString())\n })\n child.stderr?.on(\"data\", chunk => {\n log.error(chunk.toString())\n })\n\n child.on(\"message\", (message: { msg: string; moduleName: string; err: { message: string; stack: string } }) => {\n const { moduleName, msg } = message\n switch (msg) {\n case \"module-found\": {\n log.info({ moduleName, arch }, \"preparing\")\n break\n }\n case \"module-done\": {\n log.info({ moduleName, arch }, \"finished\")\n break\n }\n case \"module-skip\": {\n log.debug?.({ moduleName, arch }, \"skipped. set ENV=electron-rebuild to determine why\")\n break\n }\n case \"rebuild-error\": {\n pendingError = new Error(message.err.message)\n pendingError.stack = message.err.stack\n break\n }\n case \"rebuild-done\": {\n log.info(\"completed installing native dependencies\")\n break\n }\n }\n })\n\n await new Promise<void>((resolve, reject) => {\n child.on(\"exit\", code => {\n if (code === 0 && !pendingError) {\n resolve()\n } else {\n reject(pendingError || new Error(`Rebuilder failed with exit code: ${code}`))\n }\n })\n })\n}\n"]}

View file

@ -1,16 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRepositoryInfo = void 0;
const promise_1 = require("builder-util/out/promise");
exports.getRepositoryInfo = getRepositoryInfo;
const builder_util_1 = require("builder-util");
const fs_extra_1 = require("fs-extra");
const hosted_git_info_1 = require("hosted-git-info");
const path = require("path");
function getRepositoryInfo(projectDir, metadata, devMetadata) {
return _getInfo(projectDir, (devMetadata == null ? null : devMetadata.repository) || (metadata == null ? null : metadata.repository));
}
exports.getRepositoryInfo = getRepositoryInfo;
async function getGitUrlFromGitConfig(projectDir) {
const data = await promise_1.orNullIfFileNotExist(fs_extra_1.readFile(path.join(projectDir, ".git", "config"), "utf8"));
const data = await (0, builder_util_1.orNullIfFileNotExist)((0, fs_extra_1.readFile)(path.join(projectDir, ".git", "config"), "utf8"));
if (data == null) {
return null;
}
@ -51,7 +50,7 @@ async function _getInfo(projectDir, repo) {
return url == null ? null : parseRepositoryUrl(url);
}
function parseRepositoryUrl(url) {
const info = hosted_git_info_1.fromUrl(url);
const info = (0, hosted_git_info_1.fromUrl)(url);
if (info == null) {
return null;
}

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,10 @@
import { RequestedExecutionLevel } from "../options/winOptions";
export interface ResourceEditOptions {
file: string;
versionStrings: Record<string, string>;
fileVersion: string;
productVersion: string;
requestedExecutionLevel?: RequestedExecutionLevel | null;
iconPath?: string | null;
}
export declare function editWindowsResources(opts: ResourceEditOptions): Promise<void>;

View file

@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.editWindowsResources = editWindowsResources;
const builder_util_1 = require("builder-util");
const promises_1 = require("fs/promises");
const resedit_1 = require("resedit");
async function editWindowsResources(opts) {
const buffer = await (0, promises_1.readFile)(opts.file);
const executable = resedit_1.NtExecutable.from(buffer);
const res = resedit_1.NtExecutableResource.from(executable);
const viList = resedit_1.Resource.VersionInfo.fromEntries(res.entries);
// Mirror rcedit: create version info from scratch if none exists; use first if multiple
const vi = viList.length > 0 ? viList[0] : resedit_1.Resource.VersionInfo.createEmpty();
// Mirror rcedit: default to en-US (1033) if no languages present; use first if multiple
const languages = vi.getAllLanguagesForStringValues();
const lang = languages.length > 0 ? languages[0] : { lang: 0x0409, codepage: 1200 };
vi.setStringValues(lang, opts.versionStrings);
vi.setFileVersion(opts.fileVersion);
vi.setProductVersion(opts.productVersion);
// resedit normalizes the string to 4-part numeric; restore the original (e.g. "1.1.0" or "3.0.0-beta.2")
vi.setStringValues(lang, { FileVersion: opts.fileVersion });
vi.outputToResourceEntries(res.entries);
if (opts.iconPath) {
const iconBuf = await (0, promises_1.readFile)(opts.iconPath);
const iconFile = resedit_1.Data.IconFile.from(iconBuf);
resedit_1.Resource.IconGroupEntry.replaceIconsForResource(res.entries, 1, lang.lang, iconFile.icons.map(i => i.data));
}
if (opts.requestedExecutionLevel && opts.requestedExecutionLevel !== "asInvoker") {
patchManifestExecutionLevel(res, opts.requestedExecutionLevel, opts.file);
}
res.outputResource(executable);
await (0, promises_1.writeFile)(opts.file, Buffer.from(executable.generate()));
}
function patchManifestExecutionLevel(res, level, file) {
const manifestEntry = res.entries.find(e => e.type === 24 && e.id === 1);
if (!manifestEntry) {
builder_util_1.log.warn({ file }, "no RT_MANIFEST resource found; requestedExecutionLevel will not be applied");
return;
}
const originalXml = Buffer.from(manifestEntry.bin).toString("utf-8");
const updatedXml = originalXml.replace(/(<requestedExecutionLevel[^>]*\blevel=")[^"]*(")/i, `$1${level}$2`);
if (updatedXml === originalXml) {
builder_util_1.log.warn({ file, requestedExecutionLevel: level }, "requestedExecutionLevel node not found in manifest; execution level not updated");
return;
}
const newBuf = Buffer.from(updatedXml, "utf-8");
manifestEntry.bin = newBuf.buffer.slice(newBuf.byteOffset, newBuf.byteOffset + newBuf.byteLength);
}
//# sourceMappingURL=resEdit.js.map

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
export declare function resolveModule<T>(type: string | undefined, name: string): Promise<T>;
export declare function resolveFunction<T>(type: string | undefined, executor: T | string, name: string, rootSearchDir: string): Promise<T>;

View file

@ -0,0 +1,59 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveModule = resolveModule;
exports.resolveFunction = resolveFunction;
const builder_util_1 = require("builder-util");
const log_1 = require("builder-util/out/log");
const debug_1 = require("debug");
const promises_1 = require("fs/promises");
const path = require("path");
const requireMaybe = require("../../helpers/dynamic-import");
async function resolveModule(type, name) {
var _a;
try {
return requireMaybe.dynamicImportMaybe(name);
}
catch (error) {
log_1.log.error({ moduleName: name, message: (_a = error.message) !== null && _a !== void 0 ? _a : error.stack }, "Unable to dynamically `import` or `require`");
throw error;
}
}
async function resolveFunction(type, executor, name, rootSearchDir) {
if (executor == null || typeof executor !== "string") {
// is already function or explicitly ignored by user
return executor;
}
let p = executor;
if (p.startsWith(".")) {
p = path.resolve(p);
let realP = p;
let realRoot = rootSearchDir;
try {
realP = await (0, promises_1.realpath)(p);
realRoot = await (0, promises_1.realpath)(rootSearchDir);
}
catch {
// path may not exist yet; fall back to lexical check
}
const relative = path.relative(realRoot, realP);
if (relative.startsWith("..") || path.isAbsolute(relative)) {
throw new builder_util_1.InvalidConfigurationError(`Hook module path "${executor}" resolves outside the workspace root ("${rootSearchDir}")`);
}
}
try {
p = require.resolve(p);
}
catch (e) {
(0, debug_1.default)(e);
p = path.resolve(p);
}
const m = await resolveModule(type, p);
const namedExport = m[name];
if (namedExport == null) {
return m.default || m;
}
else {
return namedExport;
}
}
//# sourceMappingURL=resolve.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/util/resolve.ts"],"names":[],"mappings":";;AAOA,sCAOC;AAED,0CAqCC;AArDD,+CAAwD;AACxD,8CAA0C;AAC1C,iCAAyB;AACzB,0CAAsC;AACtC,6BAA4B;AAC5B,6DAA4D;AAErD,KAAK,UAAU,aAAa,CAAI,IAAwB,EAAE,IAAY;;IAC3E,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAA;IAC9C,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,SAAG,CAAC,KAAK,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAA,KAAK,CAAC,OAAO,mCAAI,KAAK,CAAC,KAAK,EAAE,EAAE,6CAA6C,CAAC,CAAA;QACrH,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,eAAe,CAAI,IAAwB,EAAE,QAAoB,EAAE,IAAY,EAAE,aAAqB;IAC1H,IAAI,QAAQ,IAAI,IAAI,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACrD,oDAAoD;QACpD,OAAO,QAAQ,CAAA;IACjB,CAAC;IAED,IAAI,CAAC,GAAG,QAAkB,CAAA;IAC1B,IAAI,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QACnB,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,IAAI,QAAQ,GAAG,aAAa,CAAA;QAC5B,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,IAAA,mBAAQ,EAAC,CAAC,CAAC,CAAA;YACzB,QAAQ,GAAG,MAAM,IAAA,mBAAQ,EAAC,aAAa,CAAC,CAAA;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,qDAAqD;QACvD,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;QAC/C,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC3D,MAAM,IAAI,wCAAyB,CAAC,qBAAqB,QAAQ,2CAA2C,aAAa,IAAI,CAAC,CAAA;QAChI,CAAC;IACH,CAAC;IAED,IAAI,CAAC;QACH,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACxB,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,IAAA,eAAK,EAAC,CAAC,CAAC,CAAA;QACR,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACrB,CAAC;IAED,MAAM,CAAC,GAAQ,MAAM,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;IAC3C,MAAM,WAAW,GAAG,CAAC,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,WAAW,IAAI,IAAI,EAAE,CAAC;QACxB,OAAO,CAAC,CAAC,OAAO,IAAI,CAAC,CAAA;IACvB,CAAC;SAAM,CAAC;QACN,OAAO,WAAW,CAAA;IACpB,CAAC;AACH,CAAC","sourcesContent":["import { InvalidConfigurationError } from \"builder-util\"\nimport { log } from \"builder-util/out/log\"\nimport debug from \"debug\"\nimport { realpath } from \"fs/promises\"\nimport * as path from \"path\"\nimport * as requireMaybe from \"../../helpers/dynamic-import\"\n\nexport async function resolveModule<T>(type: string | undefined, name: string): Promise<T> {\n try {\n return requireMaybe.dynamicImportMaybe(name)\n } catch (error: any) {\n log.error({ moduleName: name, message: error.message ?? error.stack }, \"Unable to dynamically `import` or `require`\")\n throw error\n }\n}\n\nexport async function resolveFunction<T>(type: string | undefined, executor: T | string, name: string, rootSearchDir: string): Promise<T> {\n if (executor == null || typeof executor !== \"string\") {\n // is already function or explicitly ignored by user\n return executor\n }\n\n let p = executor as string\n if (p.startsWith(\".\")) {\n p = path.resolve(p)\n let realP = p\n let realRoot = rootSearchDir\n try {\n realP = await realpath(p)\n realRoot = await realpath(rootSearchDir)\n } catch {\n // path may not exist yet; fall back to lexical check\n }\n const relative = path.relative(realRoot, realP)\n if (relative.startsWith(\"..\") || path.isAbsolute(relative)) {\n throw new InvalidConfigurationError(`Hook module path \"${executor}\" resolves outside the workspace root (\"${rootSearchDir}\")`)\n }\n }\n\n try {\n p = require.resolve(p)\n } catch (e: any) {\n debug(e)\n p = path.resolve(p)\n }\n\n const m: any = await resolveModule(type, p)\n const namedExport = m[name]\n if (namedExport == null) {\n return m.default || m\n } else {\n return namedExport\n }\n}\n"]}

View file

@ -1,6 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.time = exports.DevTimer = void 0;
exports.DevTimer = void 0;
exports.time = time;
const builder_util_1 = require("builder-util");
class DevTimer {
constructor(label) {
@ -24,5 +25,4 @@ class ProductionTimer {
function time(label) {
return builder_util_1.debug.enabled ? new DevTimer(label) : new ProductionTimer();
}
exports.time = time;
//# sourceMappingURL=timer.js.map

View file

@ -1 +1 @@
{"version":3,"file":"timer.js","sourceRoot":"","sources":["../../src/util/timer.ts"],"names":[],"mappings":";;;AAAA,+CAAoC;AAMpC,MAAa,QAAQ;IAGnB,YAA6B,KAAa;QAAb,UAAK,GAAL,KAAK,CAAQ;QAFlC,UAAK,GAAG,OAAO,CAAC,MAAM,EAAE,CAAA;IAEa,CAAC;IAE9C,SAAS;QACP,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAA;IACvD,CAAC;IAED,GAAG;QACD,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IACpD,CAAC;CACF;AAbD,4BAaC;AAED,MAAM,eAAe;IACnB,GAAG;QACD,SAAS;IACX,CAAC;CACF;AAED,SAAgB,IAAI,CAAC,KAAa;IAChC,OAAO,oBAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,eAAe,EAAE,CAAA;AACpE,CAAC;AAFD,oBAEC","sourcesContent":["import { debug } from \"builder-util\"\n\nexport interface Timer {\n end(): void\n}\n\nexport class DevTimer implements Timer {\n private start = process.hrtime()\n\n constructor(private readonly label: string) {}\n\n endAndGet(): string {\n const end = process.hrtime(this.start)\n return `${end[0]}s ${Math.round(end[1] / 1000000)}ms`\n }\n\n end(): void {\n console.info(`${this.label}: ${this.endAndGet()}`)\n }\n}\n\nclass ProductionTimer implements Timer {\n end(): void {\n // ignore\n }\n}\n\nexport function time(label: string): Timer {\n return debug.enabled ? new DevTimer(label) : new ProductionTimer()\n}\n"]}
{"version":3,"file":"timer.js","sourceRoot":"","sources":["../../src/util/timer.ts"],"names":[],"mappings":";;;AA2BA,oBAEC;AA7BD,+CAAoC;AAMpC,MAAa,QAAQ;IAGnB,YAA6B,KAAa;QAAb,UAAK,GAAL,KAAK,CAAQ;QAFlC,UAAK,GAAG,OAAO,CAAC,MAAM,EAAE,CAAA;IAEa,CAAC;IAE9C,SAAS;QACP,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACtC,OAAO,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAA;IACvD,CAAC;IAED,GAAG;QACD,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;IACpD,CAAC;CACF;AAbD,4BAaC;AAED,MAAM,eAAe;IACnB,GAAG;QACD,SAAS;IACX,CAAC;CACF;AAED,SAAgB,IAAI,CAAC,KAAa;IAChC,OAAO,oBAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,eAAe,EAAE,CAAA;AACpE,CAAC","sourcesContent":["import { debug } from \"builder-util\"\n\nexport interface Timer {\n end(): void\n}\n\nexport class DevTimer implements Timer {\n private start = process.hrtime()\n\n constructor(private readonly label: string) {}\n\n endAndGet(): string {\n const end = process.hrtime(this.start)\n return `${end[0]}s ${Math.round(end[1] / 1000000)}ms`\n }\n\n end(): void {\n console.info(`${this.label}: ${this.endAndGet()}`)\n }\n}\n\nclass ProductionTimer implements Timer {\n end(): void {\n // ignore\n }\n}\n\nexport function time(label: string): Timer {\n return debug.enabled ? new DevTimer(label) : new ProductionTimer()\n}\n"]}

View file

@ -0,0 +1 @@
export declare function withToolsetLock<T>(task: () => Promise<T>): Promise<T>;

View file

@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.withToolsetLock = withToolsetLock;
const builder_util_1 = require("builder-util");
const promises_1 = require("fs/promises");
const lockfile = require("proper-lockfile");
const os = require("os");
const path = require("path");
const LOCK_FILE = path.join(os.tmpdir(), ".electron-builder-toolset.lock");
async function withToolsetLock(task) {
await (0, promises_1.writeFile)(LOCK_FILE, "", { flag: "a" });
const release = await lockfile.lock(LOCK_FILE, {
retries: { retries: 100, minTimeout: 1000, maxTimeout: 5000 },
stale: 120000,
});
try {
return await task();
}
finally {
await release().catch((err) => builder_util_1.log.warn({ err }, "failed to release toolset lock"));
}
}
//# sourceMappingURL=toolsetLock.js.map

View file

@ -0,0 +1 @@
{"version":3,"file":"toolsetLock.js","sourceRoot":"","sources":["../../src/util/toolsetLock.ts"],"names":[],"mappings":";;AAQA,0CAWC;AAnBD,+CAAkC;AAClC,0CAAuC;AACvC,4CAA2C;AAC3C,yBAAwB;AACxB,6BAA4B;AAE5B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,gCAAgC,CAAC,CAAA;AAEnE,KAAK,UAAU,eAAe,CAAI,IAAsB;IAC7D,MAAM,IAAA,oBAAS,EAAC,SAAS,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAA;IAC7C,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE;QAC7C,OAAO,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE;QAC7D,KAAK,EAAE,MAAO;KACf,CAAC,CAAA;IACF,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,EAAE,CAAA;IACrB,CAAC;YAAS,CAAC;QACT,MAAM,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE,CAAC,kBAAG,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,gCAAgC,CAAC,CAAC,CAAA;IAC5F,CAAC;AACH,CAAC","sourcesContent":["import { log } from \"builder-util\"\nimport { writeFile } from \"fs/promises\"\nimport * as lockfile from \"proper-lockfile\"\nimport * as os from \"os\"\nimport * as path from \"path\"\n\nconst LOCK_FILE = path.join(os.tmpdir(), \".electron-builder-toolset.lock\")\n\nexport async function withToolsetLock<T>(task: () => Promise<T>): Promise<T> {\n await writeFile(LOCK_FILE, \"\", { flag: \"a\" })\n const release = await lockfile.lock(LOCK_FILE, {\n retries: { retries: 100, minTimeout: 1000, maxTimeout: 5000 },\n stale: 120_000,\n })\n try {\n return await task()\n } finally {\n await release().catch((err: Error) => log.warn({ err }, \"failed to release toolset lock\"))\n }\n}\n"]}

View file

@ -1,19 +1,22 @@
/// <reference types="node" />
import { Lazy } from "lazy-val";
import { Configuration } from "../configuration";
import { NodeModuleDirInfo } from "./packageDependencies";
export declare function installOrRebuild(config: Configuration, appDir: string, options: RebuildOptions, forceInstall?: boolean): Promise<void>;
import { Nullish } from "builder-util-runtime";
export declare function installOrRebuild(config: Configuration, { appDir, projectDir, workspaceRoot }: DirectoryPaths, options: RebuildOptions, forceInstall: boolean | undefined, env: NodeJS.ProcessEnv): Promise<void>;
export interface DesktopFrameworkInfo {
version: string;
useCustomDist: boolean;
}
export declare function getGypEnv(frameworkInfo: DesktopFrameworkInfo, platform: NodeJS.Platform, arch: string, buildFromSource: boolean): any;
export declare function installDependencies(config: Configuration, { appDir, projectDir, workspaceRoot }: DirectoryPaths, options: RebuildOptions, env: NodeJS.ProcessEnv): Promise<any>;
export declare function nodeGypRebuild(platform: NodeJS.Platform, arch: string, frameworkInfo: DesktopFrameworkInfo): Promise<void>;
export interface RebuildOptions {
frameworkInfo: DesktopFrameworkInfo;
productionDeps?: Lazy<Array<NodeModuleDirInfo>>;
platform?: NodeJS.Platform;
arch?: string;
buildFromSource?: boolean;
additionalArgs?: Array<string> | null;
}
export interface DirectoryPaths {
appDir: string;
projectDir: string;
workspaceRoot: string | Nullish;
}

View file

@ -1,39 +1,46 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.rebuild = exports.nodeGypRebuild = exports.getGypEnv = exports.installOrRebuild = void 0;
exports.installOrRebuild = installOrRebuild;
exports.getGypEnv = getGypEnv;
exports.installDependencies = installDependencies;
exports.nodeGypRebuild = nodeGypRebuild;
exports.rebuild = rebuild;
const builder_util_1 = require("builder-util");
const fs_extra_1 = require("fs-extra");
const os_1 = require("os");
const path = require("path");
const appBuilder_1 = require("./appBuilder");
async function installOrRebuild(config, appDir, options, forceInstall = false) {
const node_module_collector_1 = require("../node-module-collector");
const packageManager_1 = require("../node-module-collector/packageManager");
const rebuild_1 = require("./rebuild");
const which = require("which");
async function installOrRebuild(config, { appDir, projectDir, workspaceRoot }, options, forceInstall = false, env) {
const effectiveOptions = {
buildFromSource: config.buildDependenciesFromSource === true,
additionalArgs: builder_util_1.asArray(config.npmArgs),
additionalArgs: (0, builder_util_1.asArray)(config.npmArgs),
...options,
};
let isDependenciesInstalled = false;
const dirsToCheck = [...new Set([projectDir, appDir, workspaceRoot].filter((d) => !!d))];
for (const fileOrDir of ["node_modules", ".pnp.js"]) {
if (await fs_extra_1.pathExists(path.join(appDir, fileOrDir))) {
if ((await Promise.all(dirsToCheck.map(d => (0, fs_extra_1.pathExists)(path.join(d, fileOrDir))))).some(Boolean)) {
isDependenciesInstalled = true;
break;
}
}
if (forceInstall || !isDependenciesInstalled) {
await installDependencies(appDir, effectiveOptions);
await installDependencies(config, { appDir, projectDir, workspaceRoot }, effectiveOptions, env);
}
else {
await rebuild(appDir, effectiveOptions);
await rebuild(config, { appDir, projectDir, workspaceRoot }, effectiveOptions);
}
}
exports.installOrRebuild = installOrRebuild;
function getElectronGypCacheDir() {
return path.join(os_1.homedir(), ".electron-gyp");
return path.join((0, os_1.homedir)(), ".electron-gyp");
}
function getGypEnv(frameworkInfo, platform, arch, buildFromSource) {
const npmConfigArch = arch === "armv7l" ? "arm" : arch;
const common = {
...process.env,
...(0, builder_util_1.stripSensitiveEnvVars)(process.env),
npm_config_arch: npmConfigArch,
npm_config_target_arch: npmConfigArch,
npm_config_platform: platform,
@ -55,57 +62,57 @@ function getGypEnv(frameworkInfo, platform, arch, buildFromSource) {
// https://github.com/nodejs/node-gyp/issues/21
return {
...common,
npm_config_disturl: "https://electronjs.org/headers",
npm_config_disturl: common.npm_config_electron_mirror || "https://electronjs.org/headers",
npm_config_target: frameworkInfo.version,
npm_config_runtime: "electron",
npm_config_devdir: getElectronGypCacheDir(),
};
}
exports.getGypEnv = getGypEnv;
function checkYarnBerry() {
var _a;
const npmUserAgent = process.env["npm_config_user_agent"] || "";
const regex = /yarn\/(\d+)\./gm;
const yarnVersionMatch = regex.exec(npmUserAgent);
const yarnMajorVersion = Number((_a = yarnVersionMatch === null || yarnVersionMatch === void 0 ? void 0 : yarnVersionMatch[1]) !== null && _a !== void 0 ? _a : 0);
return yarnMajorVersion >= 2;
}
function installDependencies(appDir, options) {
async function installDependencies(config, { appDir, projectDir, workspaceRoot }, options, env) {
const platform = options.platform || process.platform;
const arch = options.arch || process.arch;
const additionalArgs = options.additionalArgs;
builder_util_1.log.info({ platform, arch, appDir }, `installing production dependencies`);
let execPath = process.env.npm_execpath || process.env.NPM_CLI_JS;
const searchPaths = [projectDir, appDir].concat(workspaceRoot ? [workspaceRoot] : []);
const { pm, resolvedDirectory: _resolvedWorkspaceDir } = await (0, packageManager_1.detectPackageManager)(searchPaths);
builder_util_1.log.info({ pm, platform, arch, projectDir, appDir, workspaceRoot: _resolvedWorkspaceDir }, "installing dependencies");
const execArgs = ["install"];
const isYarnBerry = checkYarnBerry();
if (!isYarnBerry) {
if (pm === node_module_collector_1.PM.YARN) {
execArgs.push("--prefer-offline");
}
else if (pm === node_module_collector_1.PM.YARN_BERRY) {
if (process.env.NPM_NO_BIN_LINKS === "true") {
execArgs.push("--no-bin-links");
}
execArgs.push("--production");
}
if (!isRunningYarn(execPath)) {
execArgs.push("--prefer-offline");
}
if (execPath == null) {
execPath = getPackageToolPath();
}
else if (!isYarnBerry) {
execArgs.unshift(execPath);
execPath = process.env.npm_node_execpath || process.env.NODE_EXE || "node";
}
const execPath = (0, node_module_collector_1.getPackageManagerCommand)(pm);
if (additionalArgs != null) {
execArgs.push(...additionalArgs);
}
return builder_util_1.spawn(execPath, execArgs, {
cwd: appDir,
env: getGypEnv(options.frameworkInfo, platform, arch, options.buildFromSource === true),
const spawnEnv = {
...getGypEnv(options.frameworkInfo, platform, arch, options.buildFromSource === true),
...env,
};
await (0, builder_util_1.retry)(() => (0, builder_util_1.spawn)(execPath, execArgs, { cwd: appDir, env: spawnEnv }), {
retries: 3,
interval: 1000,
backoff: 2000,
shouldRetry: (e) => {
var _a;
const isTransient = /ENOTFOUND|ECONNRESET|ETIMEDOUT|EAI_AGAIN|ECONNREFUSED/.test((_a = e === null || e === void 0 ? void 0 : e.message) !== null && _a !== void 0 ? _a : "");
if (isTransient) {
builder_util_1.log.warn({ error: String(e === null || e === void 0 ? void 0 : e.message).split("\n")[0] }, "transient network error during package install, retrying");
}
return isTransient;
},
});
// Some native dependencies no longer use `install` hook for building their native module, (yarn 3+ removed implicit link of `install` and `rebuild` steps)
// https://github.com/electron-userland/electron-builder/issues/8024
return rebuild(config, { appDir, projectDir, workspaceRoot }, options);
}
async function nodeGypRebuild(platform, arch, frameworkInfo) {
builder_util_1.log.info({ platform, arch }, "executing node-gyp rebuild");
// this script must be used only for electron
const nodeGyp = `node-gyp${process.platform === "win32" ? ".cmd" : ""}`;
const nodeGyp = process.platform === "win32" ? which.sync("node-gyp") : "node-gyp";
const args = ["rebuild"];
// headers of old Electron versions do not have a valid config.gypi file
// and --force-process-config must be passed to node-gyp >= 8.4.0 to
@ -118,34 +125,36 @@ async function nodeGypRebuild(platform, arch, frameworkInfo) {
if (major <= 13 || (major == 14 && minor <= 1) || (major == 15 && minor <= 2)) {
args.push("--force-process-config");
}
await builder_util_1.spawn(nodeGyp, args, { env: getGypEnv(frameworkInfo, platform, arch, true) });
}
exports.nodeGypRebuild = nodeGypRebuild;
function getPackageToolPath() {
if (process.env.FORCE_YARN === "true") {
return process.platform === "win32" ? "yarn.cmd" : "yarn";
}
else {
return process.platform === "win32" ? "npm.cmd" : "npm";
}
}
function isRunningYarn(execPath) {
const userAgent = process.env.npm_config_user_agent;
return process.env.FORCE_YARN === "true" || (execPath != null && path.basename(execPath).startsWith("yarn")) || (userAgent != null && /\byarn\b/.test(userAgent));
await (0, builder_util_1.spawn)(nodeGyp, args, { env: getGypEnv(frameworkInfo, platform, arch, true) });
}
/** @internal */
async function rebuild(appDir, options) {
const configuration = {
dependencies: await options.productionDeps.value,
nodeExecPath: process.execPath,
platform: options.platform || process.platform,
arch: options.arch || process.arch,
additionalArgs: options.additionalArgs,
execPath: process.env.npm_execpath || process.env.NPM_CLI_JS,
buildFromSource: options.buildFromSource === true,
async function rebuild(config, { appDir, projectDir, workspaceRoot }, options) {
const buildFromSource = options.buildFromSource === true;
const platform = options.platform || process.platform;
const arch = options.arch || process.arch;
const { frameworkInfo: { version: electronVersion }, } = options;
const projectRootPath = workspaceRoot || projectDir || appDir;
const logInfo = {
electronVersion,
arch,
buildFromSource,
workspaceRoot,
projectDir: builder_util_1.log.filePath(projectDir) || "./",
appDir: builder_util_1.log.filePath(appDir) || "./",
};
const env = getGypEnv(options.frameworkInfo, configuration.platform, configuration.arch, options.buildFromSource === true);
await appBuilder_1.executeAppBuilderAndWriteJson(["rebuild-node-modules"], configuration, { env, cwd: appDir });
builder_util_1.log.info(logInfo, "executing @electron/rebuild");
// "legacy" previously used the app-builder-bin Go binary; it now maps to sequential @electron/rebuild.
const mode = config.nativeRebuilder === "legacy" || !config.nativeRebuilder ? "sequential" : config.nativeRebuilder;
const rebuildOptions = {
buildPath: appDir,
electronVersion,
arch,
platform,
buildFromSource,
projectRootPath,
mode,
disablePreGypCopy: true,
};
return (0, rebuild_1.rebuild)(rebuildOptions);
}
exports.rebuild = rebuild;
//# sourceMappingURL=yarn.js.map

File diff suppressed because one or more lines are too long