diff --git a/bin/node-gyp.js b/bin/node-gyp.js index f8317b47b3..ee0ad6d93c 100755 --- a/bin/node-gyp.js +++ b/bin/node-gyp.js @@ -4,71 +4,124 @@ process.title = 'node-gyp' -const envPaths = require('env-paths') const gyp = require('../') const log = require('../lib/log') const os = require('os') /** - * Process and execute the selected commands. + * Create node-gyp instance and global state */ - const prog = gyp() let completed = false -prog.parseArgv(process.argv) -prog.devDir = prog.opts.devdir - -const homeDir = os.homedir() -if (prog.devDir) { - prog.devDir = prog.devDir.replace(/^~/, homeDir) -} else if (homeDir) { - prog.devDir = envPaths('node-gyp', { suffix: '' }).cache -} else { - throw new Error( - "node-gyp requires that the user's home directory is specified " + - 'in either of the environmental variables HOME or USERPROFILE. ' + - 'Overide with: --devdir /path/to/.node-gyp') +let init = false + +function errorMessage () { + // copied from npm's lib/utils/error-handler.js + log.error('System', os.type() + ' ' + os.release()) + log.error('command', process.argv.map(JSON.stringify).join(' ')) + log.error('cwd', process.cwd()) + log.error('node -v', process.version) + log.error('node-gyp -v', 'v' + prog.package.version) } -if (prog.todo.length === 0) { - if (~process.argv.indexOf('-v') || ~process.argv.indexOf('--version')) { - log.stdout('v%s', prog.version) - } else { - log.stdout('%s', prog.usage()) +function issueMessage () { + log.error('', [ + 'Node-gyp failed to build your package.', + 'Try to update npm and/or node-gyp and if it does not help file an issue with the package author.' + ].join('\n')) +} + +process.on('exit', function (code) { + if (!completed && !code) { + log.error('Completion callback never invoked!') + errorMessage() + issueMessage() + process.exit(6) } - process.exit(0) +}) + +process.on('uncaughtException', function (err) { + log.error('UNCAUGHT EXCEPTION') + log.error('stack', err.stack) + errorMessage() + issueMessage() + process.exit(7) +}) + +function exitError (err) { + log.error('stack', err.stack) + errorMessage() + log.error('not ok') + process.exit(1) } -log.info('it worked if it ends with', 'ok') -log.verbose('cli', process.argv) -log.info('using', 'node-gyp@%s', prog.version) -log.info('using', 'node@%s | %s | %s', process.versions.node, process.platform, process.arch) +async function runInit () { + prog.parseArgv(process.argv) + prog.devDir = prog.opts.devdir -/** - * Change dir if -C/--directory was passed. - */ + const homeDir = os.homedir() + if (prog.devDir) { + prog.devDir = prog.devDir.replace(/^~/, homeDir) + } else if (homeDir) { + const { default: envPaths } = await import('env-paths') + prog.devDir = envPaths('node-gyp', { suffix: '' }).cache + } else { + throw new Error( + "node-gyp requires that the user's home directory is specified " + + 'in either of the environmental variables HOME or USERPROFILE. ' + + 'Overide with: --devdir /path/to/.node-gyp' + ) + } -const dir = prog.opts.directory -if (dir) { - const fs = require('fs') - try { - const stat = fs.statSync(dir) - if (stat.isDirectory()) { - log.info('chdir', dir) - process.chdir(dir) + if (prog.todo.length === 0) { + if (~process.argv.indexOf('-v') || ~process.argv.indexOf('--version')) { + log.stdout('v%s', prog.version) } else { - log.warn('chdir', dir + ' is not a directory') + log.stdout('%s', prog.usage()) } - } catch (e) { - if (e.code === 'ENOENT') { - log.warn('chdir', dir + ' is not a directory') - } else { - log.warn('chdir', 'error during chdir() "%s"', e.message) + process.exit(0) + } + + log.info('it worked if it ends with', 'ok') + log.verbose('cli', process.argv) + log.info('using', 'node-gyp@%s', prog.version) + log.info('using', 'node@%s | %s | %s', process.versions.node, process.platform, process.arch) + + /** + * Change dir if -C/--directory was passed. + */ + const dir = prog.opts.directory + if (dir) { + const fs = require('fs/promises') + try { + const stat = await fs.stat(dir) + if (stat.isDirectory()) { + log.info('chdir', dir) + process.chdir(dir) + } else { + log.warn('chdir', dir + ' is not a directory') + } + } catch (e) { + if (e.code === 'ENOENT') { + log.warn('chdir', dir + ' is not a directory') + } else { + log.warn('chdir', 'error during chdir() "%s"', e.message) + } } } } async function run () { + if (!init) { + init = true + try { + await runInit() + } catch (err) { + exitError(err) + return + } + } + const command = prog.todo.shift() if (!command) { // done! @@ -91,48 +144,12 @@ async function run () { } // now run the next command in the queue - return run() + await run() } catch (err) { log.error(command.name + ' error') - log.error('stack', err.stack) - errorMessage() - log.error('not ok') - return process.exit(1) + exitError(err) } } -process.on('exit', function (code) { - if (!completed && !code) { - log.error('Completion callback never invoked!') - issueMessage() - process.exit(6) - } -}) - -process.on('uncaughtException', function (err) { - log.error('UNCAUGHT EXCEPTION') - log.error('stack', err.stack) - issueMessage() - process.exit(7) -}) - -function errorMessage () { - // copied from npm's lib/utils/error-handler.js - const os = require('os') - log.error('System', os.type() + ' ' + os.release()) - log.error('command', process.argv - .map(JSON.stringify).join(' ')) - log.error('cwd', process.cwd()) - log.error('node -v', process.version) - log.error('node-gyp -v', 'v' + prog.package.version) -} - -function issueMessage () { - errorMessage() - log.error('', ['Node-gyp failed to build your package.', - 'Try to update npm and/or node-gyp and if it does not help file an issue with the package author.' - ].join('\n')) -} - // start running the given commands! run() diff --git a/package.json b/package.json index 80c63f2e72..b9bf27cc62 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "bin": "./bin/node-gyp.js", "main": "./lib/node-gyp.js", "dependencies": { - "env-paths": "^2.2.0", + "env-paths": "^3.0.0", "exponential-backoff": "^3.1.1", "glob": "^10.3.10", "graceful-fs": "^4.2.6", diff --git a/test/common.js b/test/common.js index 489502d4dd..f972191312 100644 --- a/test/common.js +++ b/test/common.js @@ -1,7 +1,9 @@ -const envPaths = require('env-paths') const semver = require('semver') -module.exports.devDir = envPaths('node-gyp', { suffix: '' }).cache +module.exports.devDir = async () => { + const { default: envPaths } = await import('env-paths') + return envPaths('node-gyp', { suffix: '' }).cache +} module.exports.poison = (object, property) => { function fail () { diff --git a/test/test-configure-python.js b/test/test-configure-python.js index eee230a496..2ab0a271b1 100644 --- a/test/test-configure-python.js +++ b/test/test-configure-python.js @@ -3,7 +3,7 @@ const { describe, it } = require('mocha') const assert = require('assert') const path = require('path') -const { devDir } = require('./common') +const { devDir: getDevDir } = require('./common') const gyp = require('../lib/node-gyp') const requireInject = require('require-inject') @@ -23,7 +23,9 @@ const EXPECTED_PYPATH = path.join(__dirname, '..', 'gyp', 'pylib') const SEPARATOR = process.platform === 'win32' ? ';' : ':' const SPAWN_RESULT = cb => ({ on: function () { cb() } }) -describe('configure-python', function () { +describe('configure-python', async function () { + const devDir = await getDevDir() + it('configure PYTHONPATH with no existing env', function (done) { delete process.env.PYTHONPATH @@ -51,7 +53,7 @@ describe('configure-python', function () { return SPAWN_RESULT(done) } - prog.devDir = devDir + prog.devDir = devDir() configure(prog, [], assert.fail) }) @@ -71,7 +73,7 @@ describe('configure-python', function () { return SPAWN_RESULT(done) } - prog.devDir = devDir + prog.devDir = devDir() configure(prog, [], assert.fail) }) }) diff --git a/test/test-download.js b/test/test-download.js index 1d0f3ab286..ff9320fcb3 100644 --- a/test/test-download.js +++ b/test/test-download.js @@ -162,12 +162,12 @@ describe('download', function () { this.timeout(platformTimeout(1, { win32: 5 })) - const expectedDir = path.join(devDir, process.version.replace(/^v/, '')) + const expectedDir = path.join(await devDir(), process.version.replace(/^v/, '')) await fs.rm(expectedDir, { recursive: true, force: true }) const prog = gyp() prog.parseArgv([]) - prog.devDir = devDir + prog.devDir = await devDir() await install(prog, []) const data = await fs.readFile(path.join(expectedDir, 'installVersion'), 'utf8')