"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 path_1 = __importDefault(require("path"));
const semver_1 = __importDefault(require("semver"));
const constants_1 = require("../../constants");
const clang_fetcher_1 = require("../../clang-fetcher");
const __1 = require("..");
const child_process_1 = require("child_process");
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') && semver_1.default.major(this.rebuilder.electronVersion) < 16) {
            args.push('--force-process-config');
        }
        return args;
    }
    async buildArgsFromBinaryField() {
        const binary = await this.packageJSONFieldWithDefault('binary', {});
        let napiBuildVersion = undefined;
        if (Array.isArray(binary.napi_versions)) {
            napiBuildVersion = this.nodeAPI.getNapiVersion(binary.napi_versions.map(str => Number(str)));
        }
        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}', await detect_libc_1.default.family() || 'unknown');
            if (napiBuildVersion !== undefined) {
                value = value.replace('{napi_build_version}', napiBuildVersion.toString());
            }
            for (const [replaceKey, replaceValue] of Object.entries(binary)) {
                value = value.replace(`{${replaceKey}}`, replaceValue);
            }
            return `--${binaryKey}=${value}`;
        }));
        return flags.filter(value => value);
    }
    async rebuildModule() {
        var _a, _b;
        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}`);
        }
        const env = {
            ...process.env,
        };
        const extraNodeGypArgs = [];
        if (this.rebuilder.useElectronClang) {
            const { env: clangEnv, args: clangArgs } = await (0, clang_fetcher_1.getClangEnvironmentVars)(this.rebuilder.electronVersion, this.rebuilder.arch);
            Object.assign(env, clangEnv);
            extraNodeGypArgs.push(...clangArgs);
        }
        const nodeGypArgs = await this.buildArgs(extraNodeGypArgs);
        d('rebuilding', this.moduleName, 'with args', nodeGypArgs);
        const forkedChild = (0, child_process_1.fork)(path_1.default.resolve(__dirname, 'worker.js'), {
            env,
            cwd: this.modulePath,
            stdio: 'pipe',
        });
        const outputBuffers = [];
        (_a = forkedChild.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (chunk) => {
            outputBuffers.push(chunk);
        });
        (_b = forkedChild.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (chunk) => {
            outputBuffers.push(chunk);
        });
        forkedChild.send({
            moduleName: this.moduleName,
            nodeGypArgs,
            extraNodeGypArgs,
            devDir: this.rebuilder.mode === 'sequential' ? constants_1.ELECTRON_GYP_DIR : path_1.default.resolve(constants_1.ELECTRON_GYP_DIR, '_p', this.moduleName),
        });
        await new Promise((resolve, reject) => {
            forkedChild.on('exit', (code) => {
                if (code === 0)
                    return resolve();
                console.error(Buffer.concat(outputBuffers).toString());
                reject(new Error(`node-gyp failed to rebuild '${this.modulePath}'`));
            });
        });
    }
}
exports.NodeGyp = NodeGyp;
//# sourceMappingURL=node-gyp.js.map