UNPKG

electron-rebuild

Version:

Electron supporting package to rebuild native node modules against the currently installed electron

146 lines (145 loc) 6.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NodeGyp = void 0; const debug_1 = __importDefault(require("debug")); const detect_libc_1 = __importDefault(require("detect-libc")); const node_gyp_1 = __importDefault(require("node-gyp")); const path_1 = __importDefault(require("path")); const util_1 = require("util"); const semver_1 = __importDefault(require("semver")); const constants_1 = require("../constants"); const clang_fetcher_1 = require("../clang-fetcher"); const _1 = require("."); const d = (0, debug_1.default)('electron-rebuild'); class NodeGyp extends _1.NativeModule { async buildArgs(prefixedArgs) { const args = [ 'node', 'node-gyp', 'rebuild', ...prefixedArgs, `--runtime=electron`, `--target=${this.rebuilder.electronVersion}`, `--arch=${this.rebuilder.arch}`, `--dist-url=${this.rebuilder.headerURL}`, '--build-from-source' ]; args.push(d.enabled ? '--verbose' : '--silent'); if (this.rebuilder.debug) { args.push('--debug'); } args.push(...(await this.buildArgsFromBinaryField())); if (this.rebuilder.msvsVersion) { args.push(`--msvs_version=${this.rebuilder.msvsVersion}`); } // 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 // correctly build modules for them. // See also https://github.com/nodejs/node-gyp/pull/2497 if (!semver_1.default.satisfies(this.rebuilder.electronVersion, '^14.2.0 || ^15.3.0 || >= 16.0.0-alpha.1')) { args.push('--force-process-config'); } return args; } async buildArgsFromBinaryField() { const binary = await this.packageJSONFieldWithDefault('binary', {}); const flags = await Promise.all(Object.entries(binary).map(async ([binaryKey, binaryValue]) => { if (binaryKey === 'napi_versions') { return; } let value = binaryValue; if (binaryKey === 'module_path') { value = path_1.default.resolve(this.modulePath, value); } value = value.replace('{configuration}', this.rebuilder.buildType) .replace('{node_abi}', `electron-v${this.rebuilder.electronVersion.split('.').slice(0, 2).join('.')}`) .replace('{platform}', this.rebuilder.platform) .replace('{arch}', this.rebuilder.arch) .replace('{version}', await this.packageJSONField('version')) .replace('{libc}', detect_libc_1.default.family || 'unknown'); for (const [replaceKey, replaceValue] of Object.entries(binary)) { value = value.replace(`{${replaceKey}}`, replaceValue); } return `--${binaryKey}=${value}`; })); return flags.filter(value => value); } async rebuildModule() { if (this.modulePath.includes(' ')) { console.error('Attempting to build a module with a space in the path'); console.error('See https://github.com/nodejs/node-gyp/issues/65#issuecomment-368820565 for reasons why this may not work'); // FIXME: Re-enable the throw when more research has been done // throw new Error(`node-gyp does not support building modules with spaces in their path, tried to build: ${modulePath}`); } let env; const extraNodeGypArgs = []; if (this.rebuilder.useElectronClang) { env = { ...process.env }; const { env: clangEnv, args: clangArgs } = await (0, clang_fetcher_1.getClangEnvironmentVars)(this.rebuilder.electronVersion, this.rebuilder.arch); Object.assign(process.env, clangEnv); extraNodeGypArgs.push(...clangArgs); } const nodeGypArgs = await this.buildArgs(extraNodeGypArgs); d('rebuilding', this.moduleName, 'with args', nodeGypArgs); const nodeGyp = (0, node_gyp_1.default)(); nodeGyp.parseArgv(nodeGypArgs); nodeGyp.devDir = constants_1.ELECTRON_GYP_DIR; let command = nodeGyp.todo.shift(); const originalWorkingDir = process.cwd(); try { process.chdir(this.modulePath); while (command) { if (command.name === 'configure') { command.args = command.args.filter((arg) => !extraNodeGypArgs.includes(arg)); } else if (command.name === 'build' && process.platform === 'win32') { // This is disgusting but it prevents node-gyp from destroying our MSBuild arguments command.args.map = (fn) => { return Array.prototype.map.call(command.args, (arg) => { if (arg.startsWith('/p:')) return arg; return fn(arg); }); }; } await (0, util_1.promisify)(nodeGyp.commands[command.name])(command.args); command = nodeGyp.todo.shift(); } } catch (err) { const errorMessage = `node-gyp failed to rebuild '${this.modulePath}'. For more information, rerun with the DEBUG environment variable set to "electron-rebuild". Error: ${err.message || err}\n\n`; throw new Error(errorMessage); } finally { process.chdir(originalWorkingDir); } if (this.rebuilder.useElectronClang) { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion this.restoreEnv(env); } } restoreEnv(env) { const gotKeys = new Set(Object.keys(process.env)); const expectedKeys = new Set(Object.keys(env)); for (const key of Object.keys(process.env)) { if (!expectedKeys.has(key)) { delete process.env[key]; } else if (env[key] !== process.env[key]) { process.env[key] = env[key]; } } for (const key of Object.keys(env)) { if (!gotKeys.has(key)) { process.env[key] = env[key]; } } } } exports.NodeGyp = NodeGyp; //# sourceMappingURL=node-gyp.js.map