From 817ed9bd78a74dd1d47f7ca3e315d3f3ea033f31 Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Sun, 4 Oct 2015 13:09:08 +0200 Subject: [PATCH] Add test for python executable search logic. Break out the search logic into a separate function and add a regression test. References: https://github.com/nodejs/node-gyp/pull/668 PR-URL: https://github.com/nodejs/node-gyp/pull/756 Reviewed-By: Sakthipriyan Vairamani --- lib/configure.js | 192 +++++++++++++++++++++------------------ test/test-find-python.js | 20 ++++ 2 files changed, 122 insertions(+), 90 deletions(-) create mode 100644 test/test-find-python.js diff --git a/lib/configure.js b/lib/configure.js index 48646151d9..e10475840f 100644 --- a/lib/configure.js +++ b/lib/configure.js @@ -1,4 +1,5 @@ module.exports = exports = configure +module.exports.test = { findPython: findPython } /** * Module dependencies. @@ -32,97 +33,14 @@ function configure (gyp, argv, callback) { , nodeDir , release = processRelease(argv, gyp, process.version, process.release) - checkPython() - - // Check if Python is in the $PATH - function checkPython () { - log.verbose('check python', 'checking for Python executable "%s" in the PATH', python) - which(python, function (err, execPath) { - if (err) { - log.verbose('`which` failed', python, err) - if (python === 'python2') { - python = 'python' - return checkPython() - } - if (win) { - guessPython() - } else { - failNoPython() - } - } else { - log.verbose('`which` succeeded', python, execPath) - checkPythonVersion() - } - }) - } - - // Called on Windows when "python" isn't available in the current $PATH. - // We're gonna check if "%SystemDrive%\python27\python.exe" exists. - function guessPython () { - log.verbose('could not find "' + python + '". guessing location') - var rootDir = process.env.SystemDrive || 'C:\\' - if (rootDir[rootDir.length - 1] !== '\\') { - rootDir += '\\' + findPython(python, function (err, found) { + if (err) { + callback(err) + } else { + python = found + getNodeDir() } - var pythonPath = path.resolve(rootDir, 'Python27', 'python.exe') - log.verbose('ensuring that file exists:', pythonPath) - fs.stat(pythonPath, function (err, stat) { - if (err) { - if (err.code == 'ENOENT') { - failNoPython() - } else { - callback(err) - } - return - } - python = pythonPath - checkPythonVersion() - }) - } - - function checkPythonVersion () { - var env = extend({}, process.env) - env.TERM = 'dumb' - - execFile(python, ['-c', 'import platform; print(platform.python_version());'], { env: env }, function (err, stdout) { - if (err) { - return callback(err) - } - log.verbose('check python version', '`%s -c "import platform; print(platform.python_version());"` returned: %j', python, stdout) - var version = stdout.trim() - if (~version.indexOf('+')) { - log.silly('stripping "+" sign(s) from version') - version = version.replace(/\+/g, '') - } - if (~version.indexOf('rc')) { - log.silly('stripping "rc" identifier from version') - version = version.replace(/rc(.*)$/ig, '') - } - var range = semver.Range('>=2.5.0 <3.0.0') - var valid = false - try { - valid = range.test(version) - } catch (e) { - log.silly('range.test() error', e) - } - if (valid) { - getNodeDir() - } else { - failPythonVersion(version) - } - }) - } - - function failNoPython () { - callback(new Error('Can\'t find Python executable "' + python + - '", you can set the PYTHON env variable.')) - } - - function failPythonVersion (badVersion) { - callback(new Error('Python executable "' + python + - '" is v' + badVersion + ', which is not supported by gyp.\n' + - 'You can pass the --python switch to point to Python >= v2.5.0 & < 3.0.0.')) - } + }) function getNodeDir () { @@ -392,3 +310,97 @@ function configure (gyp, argv, callback) { } } + +function findPython (python, callback) { + checkPython() + + // Check if Python is in the $PATH + function checkPython () { + log.verbose('check python', 'checking for Python executable "%s" in the PATH', python) + which(python, function (err, execPath) { + if (err) { + log.verbose('`which` failed', python, err) + if (python === 'python2') { + python = 'python' + return checkPython() + } + if (win) { + guessPython() + } else { + failNoPython() + } + } else { + log.verbose('`which` succeeded', python, execPath) + checkPythonVersion() + } + }) + } + + // Called on Windows when "python" isn't available in the current $PATH. + // We're gonna check if "%SystemDrive%\python27\python.exe" exists. + function guessPython () { + log.verbose('could not find "' + python + '". guessing location') + var rootDir = process.env.SystemDrive || 'C:\\' + if (rootDir[rootDir.length - 1] !== '\\') { + rootDir += '\\' + } + var pythonPath = path.resolve(rootDir, 'Python27', 'python.exe') + log.verbose('ensuring that file exists:', pythonPath) + fs.stat(pythonPath, function (err, stat) { + if (err) { + if (err.code == 'ENOENT') { + failNoPython() + } else { + callback(err) + } + return + } + python = pythonPath + checkPythonVersion() + }) + } + + function checkPythonVersion () { + var env = extend({}, process.env) + env.TERM = 'dumb' + + execFile(python, ['-c', 'import platform; print(platform.python_version());'], { env: env }, function (err, stdout) { + if (err) { + return callback(err) + } + log.verbose('check python version', '`%s -c "import platform; print(platform.python_version());"` returned: %j', python, stdout) + var version = stdout.trim() + if (~version.indexOf('+')) { + log.silly('stripping "+" sign(s) from version') + version = version.replace(/\+/g, '') + } + if (~version.indexOf('rc')) { + log.silly('stripping "rc" identifier from version') + version = version.replace(/rc(.*)$/ig, '') + } + var range = semver.Range('>=2.5.0 <3.0.0') + var valid = false + try { + valid = range.test(version) + } catch (e) { + log.silly('range.test() error', e) + } + if (valid) { + callback(null, python) + } else { + failPythonVersion(version) + } + }) + } + + function failNoPython () { + callback(new Error('Can\'t find Python executable "' + python + + '", you can set the PYTHON env variable.')) + } + + function failPythonVersion (badVersion) { + callback(new Error('Python executable "' + python + + '" is v' + badVersion + ', which is not supported by gyp.\n' + + 'You can pass the --python switch to point to Python >= v2.5.0 & < 3.0.0.')) + } +} diff --git a/test/test-find-python.js b/test/test-find-python.js new file mode 100644 index 0000000000..7f5c394679 --- /dev/null +++ b/test/test-find-python.js @@ -0,0 +1,20 @@ +'use strict' + +var test = require('tape') +var configure = require('../lib/configure') +var execFile = require('child_process').execFile + +test('find python executable', function (t) { + t.plan(4) + + configure.test.findPython('python', function (err, found) { + t.strictEqual(err, null) + var proc = execFile(found, ['-V'], function (err, stdout, stderr) { + t.strictEqual(err, null) + t.strictEqual(stdout, '') + t.ok(/Python 2/.test(stderr)) + }) + proc.stdout.setEncoding('utf-8') + proc.stderr.setEncoding('utf-8') + }) +})