From 307b29238f4426f807e9e8fa7f9b68d9c84ddf40 Mon Sep 17 00:00:00 2001 From: Matias Lopez Date: Wed, 31 Mar 2021 20:10:01 -0400 Subject: [PATCH] feat: promisify build An effort to modernize the code --- lib/build.js | 172 +++++++++++++++++++++++---------------------------- 1 file changed, 79 insertions(+), 93 deletions(-) diff --git a/lib/build.js b/lib/build.js index c2388fb348..6d712582b0 100644 --- a/lib/build.js +++ b/lib/build.js @@ -2,130 +2,116 @@ const fs = require('graceful-fs') const path = require('path') +const util = require('util') const glob = require('glob') const log = require('npmlog') const which = require('which') const win = process.platform === 'win32' -function build (gyp, argv, callback) { - var platformMake = 'make' +async function build (gyp, argv) { + let platformMake = 'make' if (process.platform === 'aix') { platformMake = 'gmake' } else if (process.platform.indexOf('bsd') !== -1) { platformMake = 'gmake' } else if (win && argv.length > 0) { - argv = argv.map(function (target) { - return '/t:' + target - }) + argv = argv.map(target => '/t:' + target) } - var makeCommand = gyp.opts.make || process.env.MAKE || platformMake - var command = win ? 'msbuild' : makeCommand - var jobs = gyp.opts.jobs || process.env.JOBS - var buildType - var config - var arch - var nodeDir - var guessedSolution + const makeCommand = gyp.opts.make || process.env.MAKE || platformMake + const jobs = gyp.opts.jobs || process.env.JOBS + let command = win ? 'msbuild' : makeCommand + let buildType + let config + let arch + let nodeDir + let guessedSolution - loadConfigGypi() + await loadConfigGypi() /** * Load the "config.gypi" file that was generated during "configure". */ - function loadConfigGypi () { - var configPath = path.resolve('build', 'config.gypi') + async function loadConfigGypi () { + const configPath = path.resolve('build', 'config.gypi') + + try { + const data = await fs.promises.readFile(configPath, 'utf8') - fs.readFile(configPath, 'utf8', function (err, data) { - if (err) { - if (err.code === 'ENOENT') { - callback(new Error('You must run `node-gyp configure` first!')) - } else { - callback(err) - } - return - } config = JSON.parse(data.replace(/#.+\n/, '')) + } catch (err) { + if (err.code === 'ENOENT') { + throw new Error('You must run `node-gyp configure` first!') + } + throw err + } - // get the 'arch', 'buildType', and 'nodeDir' vars from the config - buildType = config.target_defaults.default_configuration - arch = config.variables.target_arch - nodeDir = config.variables.nodedir + // get the 'arch', 'buildType', and 'nodeDir' vars from the config + buildType = config.target_defaults.default_configuration + arch = config.variables.target_arch + nodeDir = config.variables.nodedir - if ('debug' in gyp.opts) { - buildType = gyp.opts.debug ? 'Debug' : 'Release' - } - if (!buildType) { - buildType = 'Release' - } + if ('debug' in gyp.opts) { + buildType = gyp.opts.debug ? 'Debug' : 'Release' + } + if (!buildType) { + buildType = 'Release' + } - log.verbose('build type', buildType) - log.verbose('architecture', arch) - log.verbose('node dev dir', nodeDir) + log.verbose('build type', buildType) + log.verbose('architecture', arch) + log.verbose('node dev dir', nodeDir) - if (win) { - findSolutionFile() - } else { - doWhich() - } - }) + if (win) { + return findSolutionFile() + } + return doWhich() } /** * On Windows, find the first build/*.sln file. */ - function findSolutionFile () { - glob('build/*.sln', function (err, files) { - if (err) { - return callback(err) - } - if (files.length === 0) { - return callback(new Error('Could not find *.sln file. Did you run "configure"?')) - } - guessedSolution = files[0] - log.verbose('found first Solution file', guessedSolution) - doWhich() - }) + async function findSolutionFile () { + const files = await util.promisify(glob)('build/*.sln') + if (files.length === 0) { + throw new Error('Could not find *.sln file. Did you run "configure"?') + } + guessedSolution = files[0] + log.verbose('found first Solution file', guessedSolution) + return doWhich() } /** * Uses node-which to locate the msbuild / make executable. */ - function doWhich () { + async function doWhich () { // On Windows use msbuild provided by node-gyp configure if (win) { if (!config.variables.msbuild_path) { - return callback(new Error( - 'MSBuild is not set, please run `node-gyp configure`.')) + throw new Error('MSBuild is not set, please run `node-gyp configure`.') } command = config.variables.msbuild_path log.verbose('using MSBuild:', command) - doBuild() - return + return doBuild() } // First make sure we have the build command in the PATH - which(command, function (err, execPath) { - if (err) { - // Some other error or 'make' not found on Unix, report that to the user - callback(err) - return - } - log.verbose('`which` succeeded for `' + command + '`', execPath) - doBuild() - }) + // If there's an error or 'make' not found on Unix, propagate that to the user + const execPath = await which(command) + log.verbose('`which` succeeded for `' + command + '`', execPath) + return doBuild() } /** * Actually spawn the process and compile the module. */ - function doBuild () { + async function doBuild () { // Enable Verbose build - var verbose = log.levels[log.level] <= log.levels.verbose - var j + const verbose = log.levels[log.level] <= log.levels.verbose + let j if (!win && verbose) { argv.push('V=1') @@ -145,11 +131,11 @@ function build (gyp, argv, callback) { // Convert .gypi config target_arch to MSBuild /Platform // Since there are many ways to state '32-bit Intel', default to it. // N.B. msbuild's Condition string equality tests are case-insensitive. - var archLower = arch.toLowerCase() - var p = archLower === 'x64' ? 'x64' + const archLower = arch.toLowerCase() + const p = archLower === 'x64' ? 'x64' : (archLower === 'arm' ? 'ARM' : (archLower === 'arm64' ? 'ARM64' : 'Win32')) - argv.push('/p:Configuration=' + buildType + ';Platform=' + p) + argv.push(`/p:Configuration=${buildType};Platform=${p}`) if (jobs) { j = parseInt(jobs, 10) if (!isNaN(j) && j > 0) { @@ -177,28 +163,28 @@ function build (gyp, argv, callback) { if (win) { // did the user specify their own .sln file? - var hasSln = argv.some(function (arg) { - return path.extname(arg) === '.sln' - }) + const hasSln = argv.some(arg => path.extname(arg) === '.sln') if (!hasSln) { argv.unshift(gyp.opts.solution || guessedSolution) } } - var proc = gyp.spawn(command, argv) - proc.on('exit', onExit) - } - - function onExit (code, signal) { - if (code !== 0) { - return callback(new Error('`' + command + '` failed with exit code: ' + code)) - } - if (signal) { - return callback(new Error('`' + command + '` got signal: ' + signal)) - } - callback() + return new Promise((resolve, reject) => { + const proc = gyp.spawn(command, argv) + proc.on('exit', (code, signal) => { + if (code !== 0) { + reject(new Error('`' + command + '` failed with exit code: ' + code)) + } else if (signal) { + reject(new Error('`' + command + '` got signal: ' + signal)) + } else { + resolve() + } + }) + }) } } -module.exports = build -module.exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module' +module.exports = function (gyp, argv, callback) { + build(gyp, argv).then(callback.bind(undefined, null), callback) +} +module.exports.usage = `Invokes \`${win ? 'msbuild' : 'make'}\` and builds the module`