Skip to content
Permalink
Browse files

feat(generic): use electron-rebuild instead of generic rebuild logic

Fixes #57
  • Loading branch information
MarshallOfSound authored and malept committed Jan 7, 2017
1 parent 30082bb commit 3d26da5b1b2280005a7a97f8ea86caffdb5e1e22
Showing with 3 additions and 140 deletions.
  1. +1 −0 package.json
  2. +2 −140 src/util/rebuild.js
@@ -97,6 +97,7 @@
"debug": "^2.3.3",
"electron-installer-dmg": "^0.1.2",
"electron-packager": "^8.4.0",
"electron-rebuild": "^1.5.5",
"electron-sudo": "malept/electron-sudo#fix-linux-sudo-detection",
"electron-windows-store": "^0.6.3",
"electron-winstaller": "^2.5.0",
@@ -1,141 +1,3 @@
import { spawn } from 'child_process';
import debug from 'debug';
import fs from 'fs-promise';
import os from 'os';
import path from 'path';
import readPackageJSON from './read-package-json';
import rebuild from 'electron-rebuild';

import asyncOra from './ora-handler';

const d = debug('electron-forge:rebuild');

export default async (buildPath, electronVersion, pPlatform, pArch) => {
const rebuilds = [];
let rebuildCount = 0;
let rebuildCompleteCount = 0;
const prodDeps = {};

await asyncOra(`Preparing native dependencies ${rebuildCompleteCount}/${rebuildCount}`, async (nativeSpinner) => {
const updateNativeSpinner = () => {
nativeSpinner.text = `Preparing native dependencies ${rebuildCompleteCount}/${rebuildCount}`; // eslint-disable-line
};

const rebuildModuleAt = async (modulePath) => {
if (await fs.exists(path.resolve(modulePath, 'binding.gyp'))) {
const metaPath = path.resolve(modulePath, 'build', 'Release', '.forge-meta');
rebuildCount += 1;
updateNativeSpinner();
if (await fs.exists(metaPath)) {
const meta = await fs.readFile(metaPath, 'utf8');
if (meta === pArch) {
d(`skipping: ${path.basename(modulePath)} as it is already built`);
rebuildCompleteCount += 1;
updateNativeSpinner();
return;
}
}
d('rebuilding:', path.basename(modulePath));
const rebuildArgs = [
'rebuild',
`--target=${electronVersion}`,
`--arch=${pArch}`,
'--dist-url=https://atom.io/download/electron',
'--build-from-source',
];

const modulePackageJSON = await readPackageJSON(modulePath);
Object.keys(modulePackageJSON.binary || {}).forEach((binaryKey) => {
let value = modulePackageJSON.binary[binaryKey];
if (binaryKey === 'module_path') {
value = path.resolve(modulePath, value);
}
rebuildArgs.push(`--${binaryKey}=${value}`);
});

await new Promise((resolve, reject) => {
const child = spawn(path.resolve(__dirname, `../../node_modules/.bin/node-gyp${process.platform === 'win32' ? '.cmd' : ''}`), rebuildArgs, {
cwd: modulePath,
env: Object.assign({}, process.env, {
HOME: path.resolve(os.homedir(), '.electron-gyp'),
USERPROFILE: path.resolve(os.homedir(), '.electron-gyp'),
npm_config_disturl: 'https://atom.io/download/electron',
npm_config_runtime: 'electron',
npm_config_arch: pArch,
npm_config_target_arch: pArch,
npm_config_build_from_source: true,
}),
});
let output = '';
child.stdout.on('data', (data) => { output += data; });
child.stderr.on('data', (data) => { output += data; });
child.on('exit', async (code) => {
d('built:', path.basename(modulePath));
if (code !== 0) return reject(new Error(`Failed to rebuild: ${modulePath}\n\n${output}`));
await fs.mkdirs(path.dirname(metaPath));
await fs.writeFile(metaPath, pArch);
rebuildCompleteCount += 1;
updateNativeSpinner();
resolve();
});
});
}
};

const rebuildAllModulesIn = (nodeModulesPath, prefix = '') => {
d('scanning:', nodeModulesPath);
for (const modulePath of fs.readdirSync(nodeModulesPath)) {
if (prodDeps[`${prefix}${modulePath}`]) {
rebuilds.push(rebuildModuleAt(path.resolve(nodeModulesPath, modulePath)));
}
if (modulePath.startsWith('@')) {
rebuildAllModulesIn(path.resolve(nodeModulesPath, modulePath), `${modulePath}/`);
}
if (fs.existsSync(path.resolve(nodeModulesPath, modulePath, 'node_modules'))) {
rebuildAllModulesIn(path.resolve(nodeModulesPath, modulePath, 'node_modules'));
}
}
};

const findModule = async (moduleName, fromDir, foundFn) => {
let targetDir = fromDir;
const foundFns = [];
while (targetDir !== buildPath) {
const testPath = path.resolve(targetDir, 'node_modules', moduleName);
if (await fs.exists(testPath)) {
foundFns.push(foundFn(testPath));
}
targetDir = path.dirname(targetDir);
}
await Promise.all(foundFns);
};

const markChildrenAsProdDeps = async (modulePath) => {
d('exploring:', modulePath);
let childPackageJSON;
try {
childPackageJSON = await readPackageJSON(modulePath);
} catch (err) {
return;
}
const moduleWait = [];
Object.keys(childPackageJSON.dependencies || {}).forEach((key) => {
if (prodDeps[key]) return;
prodDeps[key] = true;
moduleWait.push(findModule(key, modulePath, markChildrenAsProdDeps));
});
await Promise.all(moduleWait);
};

const rootPackageJSON = await readPackageJSON(buildPath);
const markWaiters = [];
Object.keys(rootPackageJSON.dependencies || {}).concat(Object.keys(rootPackageJSON.optionalDependencies || {})).forEach((key) => {
prodDeps[key] = true;
markWaiters.push(markChildrenAsProdDeps(path.resolve(buildPath, 'node_modules', key)));
});

await Promise.all(markWaiters);

rebuildAllModulesIn(path.resolve(buildPath, 'node_modules'));
await Promise.all(rebuilds);
});
};
export default (buildPath, electronVersion, platform, arch) => rebuild(buildPath, electronVersion, arch);

0 comments on commit 3d26da5

Please sign in to comment.
You can’t perform that action at this time.