11module . exports = exports = configure
2- module . exports . test = { findAccessibleSync : findAccessibleSync ,
3- findPython : findPython }
2+ module . exports . test = {
3+ PythonFinder : PythonFinder ,
4+ findAccessibleSync : findAccessibleSync ,
5+ findPython : findPython ,
6+ }
47
58/**
69 * Module dependencies.
@@ -16,8 +19,6 @@ var fs = require('graceful-fs')
1619 , cp = require ( 'child_process' )
1720 , extend = require ( 'util' ) . _extend
1821 , processRelease = require ( './process-release' )
19- , spawn = cp . spawn
20- , execFile = cp . execFile
2122 , win = process . platform == 'win32'
2223 , findNodeDirectory = require ( './find-node-directory' )
2324 , msgFormat = require ( 'util' ) . format
@@ -336,34 +337,45 @@ function findAccessibleSync (logprefix, dir, candidates) {
336337 return undefined
337338}
338339
339- function findPython ( python , callback ) {
340- checkPython ( )
340+ function PythonFinder ( python , callback ) {
341+ this . callback = callback
342+ this . python = python
343+ }
341344
342- // Check if Python is in the $PATH
343- function checkPython ( ) {
344- log . verbose ( 'check python' , 'checking for Python executable "%s" in the PATH' , python )
345- which ( python , function ( err , execPath ) {
345+ PythonFinder . prototype = {
346+ env : process . env ,
347+ execFile : cp . execFile ,
348+ log : log ,
349+ stat : fs . stat ,
350+ which : which ,
351+ win : win ,
352+
353+ checkPython : function checkPython ( ) {
354+ this . log . verbose ( 'check python' ,
355+ 'checking for Python executable "%s" in the PATH' ,
356+ this . python )
357+ this . which ( this . python , function ( err , execPath ) {
346358 if ( err ) {
347- log . verbose ( '`which` failed' , python , err )
348- if ( python === 'python2' ) {
349- python = 'python'
350- return checkPython ( )
359+ this . log . verbose ( '`which` failed' , this . python , err )
360+ if ( this . python === 'python2' ) {
361+ this . python = 'python'
362+ return this . checkPython ( )
351363 }
352- if ( win ) {
353- checkPythonLauncher ( )
364+ if ( this . win ) {
365+ this . checkPythonLauncher ( )
354366 } else {
355- failNoPython ( )
367+ this . failNoPython ( )
356368 }
357369 } else {
358- log . verbose ( '`which` succeeded' , python , execPath )
359- // Found the `python` exceutable , and from now on we use it explicitly.
370+ this . log . verbose ( '`which` succeeded' , this . python , execPath )
371+ // Found the `python` executable , and from now on we use it explicitly.
360372 // This solves #667 and #750 (`execFile` won't run batch files
361373 // (*.cmd, and *.bat))
362- python = execPath
363- checkPythonVersion ( )
374+ this . python = execPath
375+ this . checkPythonVersion ( )
364376 }
365- } )
366- }
377+ } . bind ( this ) )
378+ } ,
367379
368380 // Distributions of Python on Windows by default install with the "py.exe"
369381 // Python launcher which is more likely to exist than the Python executable
@@ -373,88 +385,105 @@ function findPython (python, callback) {
373385 // the first command line argument. Since "py.exe -2" would be an invalid
374386 // executable for "execFile", we have to use the launcher to figure out
375387 // where the actual "python.exe" executable is located.
376- function checkPythonLauncher ( ) {
377- log . verbose ( 'could not find "' + python + '". checking python launcher' )
378- var env = extend ( { } , process . env )
388+ checkPythonLauncher : function checkPythonLauncher ( ) {
389+ this . log . verbose (
390+ 'could not find "' + this . python + '". checking python launcher' )
391+ var env = extend ( { } , this . env )
379392 env . TERM = 'dumb'
380393
381394 var launcherArgs = [ '-2' , '-c' , 'import sys; print sys.executable' ]
382- execFile ( 'py.exe' , launcherArgs , { env : env } , function ( err , stdout ) {
395+ this . execFile ( 'py.exe' , launcherArgs , { env : env } , function ( err , stdout ) {
383396 if ( err ) {
384- guessPython ( )
385- return
386- }
387- python = stdout . trim ( )
388- log . verbose ( 'check python launcher' , 'python executable found: %j' , python )
389- checkPythonVersion ( )
390- } )
391- }
392-
393- // Called on Windows when "python" isn't available in the current $PATH.
394- // We're gonna check if "%SystemDrive%\python27\python.exe" exists.
395- function guessPython ( ) {
396- log . verbose ( 'could not find "' + python + '". guessing location' )
397- var rootDir = process . env . SystemDrive || 'C:\\'
398- if ( rootDir [ rootDir . length - 1 ] !== '\\' ) {
399- rootDir += '\\'
400- }
401- var pythonPath = path . resolve ( rootDir , 'Python27' , 'python.exe' )
402- log . verbose ( 'ensuring that file exists:' , pythonPath )
403- fs . stat ( pythonPath , function ( err , stat ) {
404- if ( err ) {
405- if ( err . code == 'ENOENT' ) {
406- failNoPython ( )
407- } else {
408- callback ( err )
409- }
397+ this . guessPython ( )
410398 return
411399 }
412- python = pythonPath
413- checkPythonVersion ( )
414- } )
415- }
416-
417- function checkPythonVersion ( ) {
418- var env = extend ( { } , process . env )
400+ this . python = stdout . trim ( )
401+ this . log . verbose ( 'check python launcher' ,
402+ 'python executable found: %j' ,
403+ this . python )
404+ this . checkPythonVersion ( )
405+ } . bind ( this ) )
406+ } ,
407+
408+ checkPythonVersion : function checkPythonVersion ( ) {
409+ var args = [ '-c' , 'import platform; print(platform.python_version());' ]
410+ var env = extend ( { } , this . env )
419411 env . TERM = 'dumb'
420412
421- execFile ( python , [ '-c' , 'import platform; print(platform.python_version());' ] , { env : env } , function ( err , stdout ) {
413+ this . execFile ( this . python , args , { env : env } , function ( err , stdout ) {
422414 if ( err ) {
423- return callback ( err )
415+ return this . callback ( err )
424416 }
425- log . verbose ( 'check python version' , '`%s -c "import platform; print(platform.python_version());"` returned: %j' , python , stdout )
417+ this . log . verbose ( 'check python version' ,
418+ '`%s -c "' + args [ 1 ] + '"` returned: %j' ,
419+ this . python , stdout )
426420 var version = stdout . trim ( )
427421 if ( ~ version . indexOf ( '+' ) ) {
428- log . silly ( 'stripping "+" sign(s) from version' )
422+ this . log . silly ( 'stripping "+" sign(s) from version' )
429423 version = version . replace ( / \+ / g, '' )
430424 }
431425 if ( ~ version . indexOf ( 'rc' ) ) {
432- log . silly ( 'stripping "rc" identifier from version' )
426+ this . log . silly ( 'stripping "rc" identifier from version' )
433427 version = version . replace ( / r c ( .* ) $ / ig, '' )
434428 }
435429 var range = semver . Range ( '>=2.5.0 <3.0.0' )
436430 var valid = false
437431 try {
438432 valid = range . test ( version )
439433 } catch ( e ) {
440- log . silly ( 'range.test() error' , e )
434+ this . log . silly ( 'range.test() error' , e )
441435 }
442436 if ( valid ) {
443- callback ( null , python )
437+ this . callback ( null , this . python )
444438 } else {
445- failPythonVersion ( version )
439+ this . failPythonVersion ( version )
446440 }
447- } )
448- }
441+ } . bind ( this ) )
442+ } ,
443+
444+ failNoPython : function failNoPython ( ) {
445+ var errmsg =
446+ 'Can\'t find Python executable "' + this . python +
447+ '", you can set the PYTHON env variable.'
448+ this . callback ( new Error ( errmsg ) )
449+ } ,
450+
451+ failPythonVersion : function failPythonVersion ( badVersion ) {
452+ var errmsg =
453+ 'Python executable "' + this . python +
454+ '" is v' + badVersion + ', which is not supported by gyp.\n' +
455+ 'You can pass the --python switch to point to ' +
456+ 'Python >= v2.5.0 & < 3.0.0.'
457+ this . callback ( new Error ( errmsg ) )
458+ } ,
449459
450- function failNoPython ( ) {
451- callback ( new Error ( 'Can\'t find Python executable "' + python +
452- '", you can set the PYTHON env variable.' ) )
453- }
460+ // Called on Windows when "python" isn't available in the current $PATH.
461+ // We are going to check if "%SystemDrive%\python27\python.exe" exists.
462+ guessPython : function guessPython ( ) {
463+ this . log . verbose ( 'could not find "' + this . python + '". guessing location' )
464+ var rootDir = this . env . SystemDrive || 'C:\\'
465+ if ( rootDir [ rootDir . length - 1 ] !== '\\' ) {
466+ rootDir += '\\'
467+ }
468+ var resolve = path . win32 && path . win32 . resolve || path . resolve
469+ var pythonPath = resolve ( rootDir , 'Python27' , 'python.exe' )
470+ this . log . verbose ( 'ensuring that file exists:' , pythonPath )
471+ this . stat ( pythonPath , function ( err , stat ) {
472+ if ( err ) {
473+ if ( err . code == 'ENOENT' ) {
474+ this . failNoPython ( )
475+ } else {
476+ this . callback ( err )
477+ }
478+ return
479+ }
480+ this . python = pythonPath
481+ this . checkPythonVersion ( )
482+ } . bind ( this ) )
483+ } ,
484+ }
454485
455- function failPythonVersion ( badVersion ) {
456- callback ( new Error ( 'Python executable "' + python +
457- '" is v' + badVersion + ', which is not supported by gyp.\n' +
458- 'You can pass the --python switch to point to Python >= v2.5.0 & < 3.0.0.' ) )
459- }
486+ function findPython ( python , callback ) {
487+ var finder = new PythonFinder ( python , callback )
488+ finder . checkPython ( )
460489}
0 commit comments