Atom/script/lib/verify-machine-requirements.js

174 lines
5.8 KiB
JavaScript

'use strict';
const childProcess = require('child_process');
const path = require('path');
const CONFIG = require('../config');
module.exports = function(ci) {
verifyNode();
verifyNpm(ci);
verifyPython();
};
function verifyNode() {
const fullVersion = process.versions.node;
const majorVersion = fullVersion.split('.')[0];
if (majorVersion >= 6) {
console.log(`Node:\tv${fullVersion}`);
} else if (majorVersion >= 4) {
console.log(`Node:\tv${fullVersion}`);
console.warn(
'\tWarning: Building on Node below version 6 is deprecated. Please use Node 6.x+ to build Atom.'
);
} else {
throw new Error(
`node v4+ is required to build Atom. node v${fullVersion} is installed.`
);
}
}
function verifyNpm(ci) {
const stdout = childProcess.execFileSync(
CONFIG.getNpmBinPath(ci),
['--version'],
{ env: process.env }
);
const fullVersion = stdout.toString().trim();
const majorVersion = fullVersion.split('.')[0];
const oldestMajorVersionSupported = ci ? 6 : 3;
if (majorVersion >= oldestMajorVersionSupported) {
console.log(`Npm:\tv${fullVersion}`);
} else {
throw new Error(
`npm v${oldestMajorVersionSupported}+ is required to build Atom. npm v${fullVersion} was detected.`
);
}
}
function verifyPython() {
// This function essentially re-implements node-gyp's "find-python.js" library,
// but in a synchronous, bootstrap-script-friendly way.
// It is based off of the logic of the file from node-gyp v5.x:
// https://github.com/nodejs/node-gyp/blob/v5.1.1/lib/find-python.js
// This node-gyp is the version in use by current npm (in mid 2020).
//
// TODO: If this repo ships a newer version of node-gyp (v6.x or later), please update this script.
// (Currently, the build scripts and apm each depend on npm v6.14, which depends on node-gyp v5.)
// Differences between major versions of node-gyp:
// node-gyp 5.x looks for python, then python2, then python3.
// node-gyp 6.x looks for python3, then python, then python2.)
// node-gyp 5.x accepts Python ^2.6 || >= 3.5, node-gyp 6+ only accepts Python == 2.7 || >= 3.5.
// node-gyp 7.x stopped using the "-2" flag for "py.exe",
// so as to allow finding Python 3 as well, not just Python 2.
// https://github.com/nodejs/node-gyp/blob/master/CHANGELOG.md#v700-2020-06-03
let stdout;
let fullVersion;
let usablePythonWasFound;
let triedLog = '';
let binaryPlusFlag;
function verifyBinary(binary, prependFlag) {
if (binary && !usablePythonWasFound) {
// clear re-used "result" variables now that we're checking another python binary.
stdout = '';
fullVersion = '';
let allFlags = [
'-c',
'import platform\nprint(platform.python_version())'
];
if (prependFlag) {
// prependFlag is an optional argument,
// used to prepend "-2" for the "py.exe" launcher.
//
// TODO: Refactor this script by eliminating "prependFlag"
// once we update to node-gyp v7.x or newer;
// the "-2" flag is not used in node-gyp v7.x.
allFlags.unshift(prependFlag);
}
try {
stdout = childProcess.execFileSync(binary, allFlags, {
env: process.env,
stdio: ['ignore', 'pipe', 'ignore']
});
} catch {}
if (stdout) {
if (stdout.indexOf('+') !== -1)
stdout = stdout.toString().replace(/\+/g, '');
if (stdout.indexOf('rc') !== -1)
stdout = stdout.toString().replace(/rc(.*)$/gi, '');
fullVersion = stdout.toString().trim();
}
if (fullVersion) {
let versionComponents = fullVersion.split('.');
let majorVersion = Number(versionComponents[0]);
let minorVersion = Number(versionComponents[1]);
if (
(majorVersion === 2 && minorVersion >= 6) ||
(majorVersion === 3 && minorVersion >= 5)
) {
usablePythonWasFound = true;
}
}
// Prepare to log which commands were tried, and the results, in case no usable Python can be found.
if (prependFlag) {
binaryPlusFlag = binary + ' ' + prependFlag;
} else {
binaryPlusFlag = binary;
}
triedLog = triedLog.concat(
`log message: tried to check version of "${binaryPlusFlag}", got: "${fullVersion}"\n`
);
}
}
function verifyForcedBinary(binary) {
if (typeof binary !== 'undefined' && binary.length > 0) {
verifyBinary(binary);
if (!usablePythonWasFound) {
throw new Error(
`NODE_GYP_FORCE_PYTHON is set to: "${binary}", but this is not a valid Python.\n` +
'Please set NODE_GYP_FORCE_PYTHON to something valid, or unset it entirely.\n' +
'(Python 2.6, 2.7 or 3.5+ is required to build Atom.)\n'
);
}
}
}
// These first two checks do nothing if the relevant
// environment variables aren't set.
verifyForcedBinary(process.env.NODE_GYP_FORCE_PYTHON);
// All the following checks will no-op if a previous check has succeeded.
verifyBinary(process.env.PYTHON);
verifyBinary('python');
verifyBinary('python2');
verifyBinary('python3');
if (process.platform === 'win32') {
verifyBinary('py.exe', '-2');
verifyBinary(
path.join(process.env.SystemDrive || 'C:', 'Python27', 'python.exe')
);
verifyBinary(
path.join(process.env.SystemDrive || 'C:', 'Python37', 'python.exe')
);
}
if (usablePythonWasFound) {
console.log(`Python:\tv${fullVersion}`);
} else {
throw new Error(
`\n${triedLog}\n` +
'Python 2.6, 2.7 or 3.5+ is required to build Atom.\n' +
'verify-machine-requirements.js was unable to find such a version of Python.\n' +
"Set the PYTHON env var to e.g. 'C:/path/to/Python27/python.exe'\n" +
'if your Python is installed in a non-default location.\n'
);
}
}