Skip to content

Commit 817ed9b

Browse files
committed
Add test for python executable search logic.
Break out the search logic into a separate function and add a regression test. References: #668 PR-URL: #756 Reviewed-By: Sakthipriyan Vairamani <[email protected]>
1 parent 0e2dfda commit 817ed9b

File tree

2 files changed

+122
-90
lines changed

2 files changed

+122
-90
lines changed

lib/configure.js

+102-90
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
module.exports = exports = configure
2+
module.exports.test = { findPython: findPython }
23

34
/**
45
* Module dependencies.
@@ -32,97 +33,14 @@ function configure (gyp, argv, callback) {
3233
, nodeDir
3334
, release = processRelease(argv, gyp, process.version, process.release)
3435

35-
checkPython()
36-
37-
// Check if Python is in the $PATH
38-
function checkPython () {
39-
log.verbose('check python', 'checking for Python executable "%s" in the PATH', python)
40-
which(python, function (err, execPath) {
41-
if (err) {
42-
log.verbose('`which` failed', python, err)
43-
if (python === 'python2') {
44-
python = 'python'
45-
return checkPython()
46-
}
47-
if (win) {
48-
guessPython()
49-
} else {
50-
failNoPython()
51-
}
52-
} else {
53-
log.verbose('`which` succeeded', python, execPath)
54-
checkPythonVersion()
55-
}
56-
})
57-
}
58-
59-
// Called on Windows when "python" isn't available in the current $PATH.
60-
// We're gonna check if "%SystemDrive%\python27\python.exe" exists.
61-
function guessPython () {
62-
log.verbose('could not find "' + python + '". guessing location')
63-
var rootDir = process.env.SystemDrive || 'C:\\'
64-
if (rootDir[rootDir.length - 1] !== '\\') {
65-
rootDir += '\\'
36+
findPython(python, function (err, found) {
37+
if (err) {
38+
callback(err)
39+
} else {
40+
python = found
41+
getNodeDir()
6642
}
67-
var pythonPath = path.resolve(rootDir, 'Python27', 'python.exe')
68-
log.verbose('ensuring that file exists:', pythonPath)
69-
fs.stat(pythonPath, function (err, stat) {
70-
if (err) {
71-
if (err.code == 'ENOENT') {
72-
failNoPython()
73-
} else {
74-
callback(err)
75-
}
76-
return
77-
}
78-
python = pythonPath
79-
checkPythonVersion()
80-
})
81-
}
82-
83-
function checkPythonVersion () {
84-
var env = extend({}, process.env)
85-
env.TERM = 'dumb'
86-
87-
execFile(python, ['-c', 'import platform; print(platform.python_version());'], { env: env }, function (err, stdout) {
88-
if (err) {
89-
return callback(err)
90-
}
91-
log.verbose('check python version', '`%s -c "import platform; print(platform.python_version());"` returned: %j', python, stdout)
92-
var version = stdout.trim()
93-
if (~version.indexOf('+')) {
94-
log.silly('stripping "+" sign(s) from version')
95-
version = version.replace(/\+/g, '')
96-
}
97-
if (~version.indexOf('rc')) {
98-
log.silly('stripping "rc" identifier from version')
99-
version = version.replace(/rc(.*)$/ig, '')
100-
}
101-
var range = semver.Range('>=2.5.0 <3.0.0')
102-
var valid = false
103-
try {
104-
valid = range.test(version)
105-
} catch (e) {
106-
log.silly('range.test() error', e)
107-
}
108-
if (valid) {
109-
getNodeDir()
110-
} else {
111-
failPythonVersion(version)
112-
}
113-
})
114-
}
115-
116-
function failNoPython () {
117-
callback(new Error('Can\'t find Python executable "' + python +
118-
'", you can set the PYTHON env variable.'))
119-
}
120-
121-
function failPythonVersion (badVersion) {
122-
callback(new Error('Python executable "' + python +
123-
'" is v' + badVersion + ', which is not supported by gyp.\n' +
124-
'You can pass the --python switch to point to Python >= v2.5.0 & < 3.0.0.'))
125-
}
43+
})
12644

12745
function getNodeDir () {
12846

@@ -392,3 +310,97 @@ function configure (gyp, argv, callback) {
392310
}
393311

394312
}
313+
314+
function findPython (python, callback) {
315+
checkPython()
316+
317+
// Check if Python is in the $PATH
318+
function checkPython () {
319+
log.verbose('check python', 'checking for Python executable "%s" in the PATH', python)
320+
which(python, function (err, execPath) {
321+
if (err) {
322+
log.verbose('`which` failed', python, err)
323+
if (python === 'python2') {
324+
python = 'python'
325+
return checkPython()
326+
}
327+
if (win) {
328+
guessPython()
329+
} else {
330+
failNoPython()
331+
}
332+
} else {
333+
log.verbose('`which` succeeded', python, execPath)
334+
checkPythonVersion()
335+
}
336+
})
337+
}
338+
339+
// Called on Windows when "python" isn't available in the current $PATH.
340+
// We're gonna check if "%SystemDrive%\python27\python.exe" exists.
341+
function guessPython () {
342+
log.verbose('could not find "' + python + '". guessing location')
343+
var rootDir = process.env.SystemDrive || 'C:\\'
344+
if (rootDir[rootDir.length - 1] !== '\\') {
345+
rootDir += '\\'
346+
}
347+
var pythonPath = path.resolve(rootDir, 'Python27', 'python.exe')
348+
log.verbose('ensuring that file exists:', pythonPath)
349+
fs.stat(pythonPath, function (err, stat) {
350+
if (err) {
351+
if (err.code == 'ENOENT') {
352+
failNoPython()
353+
} else {
354+
callback(err)
355+
}
356+
return
357+
}
358+
python = pythonPath
359+
checkPythonVersion()
360+
})
361+
}
362+
363+
function checkPythonVersion () {
364+
var env = extend({}, process.env)
365+
env.TERM = 'dumb'
366+
367+
execFile(python, ['-c', 'import platform; print(platform.python_version());'], { env: env }, function (err, stdout) {
368+
if (err) {
369+
return callback(err)
370+
}
371+
log.verbose('check python version', '`%s -c "import platform; print(platform.python_version());"` returned: %j', python, stdout)
372+
var version = stdout.trim()
373+
if (~version.indexOf('+')) {
374+
log.silly('stripping "+" sign(s) from version')
375+
version = version.replace(/\+/g, '')
376+
}
377+
if (~version.indexOf('rc')) {
378+
log.silly('stripping "rc" identifier from version')
379+
version = version.replace(/rc(.*)$/ig, '')
380+
}
381+
var range = semver.Range('>=2.5.0 <3.0.0')
382+
var valid = false
383+
try {
384+
valid = range.test(version)
385+
} catch (e) {
386+
log.silly('range.test() error', e)
387+
}
388+
if (valid) {
389+
callback(null, python)
390+
} else {
391+
failPythonVersion(version)
392+
}
393+
})
394+
}
395+
396+
function failNoPython () {
397+
callback(new Error('Can\'t find Python executable "' + python +
398+
'", you can set the PYTHON env variable.'))
399+
}
400+
401+
function failPythonVersion (badVersion) {
402+
callback(new Error('Python executable "' + python +
403+
'" is v' + badVersion + ', which is not supported by gyp.\n' +
404+
'You can pass the --python switch to point to Python >= v2.5.0 & < 3.0.0.'))
405+
}
406+
}

test/test-find-python.js

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict'
2+
3+
var test = require('tape')
4+
var configure = require('../lib/configure')
5+
var execFile = require('child_process').execFile
6+
7+
test('find python executable', function (t) {
8+
t.plan(4)
9+
10+
configure.test.findPython('python', function (err, found) {
11+
t.strictEqual(err, null)
12+
var proc = execFile(found, ['-V'], function (err, stdout, stderr) {
13+
t.strictEqual(err, null)
14+
t.strictEqual(stdout, '')
15+
t.ok(/Python 2/.test(stderr))
16+
})
17+
proc.stdout.setEncoding('utf-8')
18+
proc.stderr.setEncoding('utf-8')
19+
})
20+
})

0 commit comments

Comments
 (0)