Skip to content

Commit

Permalink
Merge branch 'master' of github.com:nodejs/node-gyp
Browse files Browse the repository at this point in the history
  • Loading branch information
peterbraden committed Oct 24, 2016
2 parents 99148a0 + 37ae7be commit 1f18133
Show file tree
Hide file tree
Showing 8 changed files with 517 additions and 96 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ Command Options
| `--thin=yes` | Enable thin static libraries
| `--arch=$arch` | Set target architecture (e.g. ia32)
| `--tarball=$path` | Get headers from a local tarball
| `--devdir=$path` | SDK download directory (default=~/.node-gyp)
| `--ensure` | Don't reinstall headers if already present
| `--dist-url=$url` | Download header tarball from custom URL
| `--proxy=$url` | Set HTTP proxy for downloading header tarball
Expand Down
15 changes: 15 additions & 0 deletions bin/node-gyp.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ process.title = 'node-gyp'

var gyp = require('../')
var log = require('npmlog')
var osenv = require('osenv')
var path = require('path')

/**
* Process and execute the selected commands.
Expand All @@ -21,6 +23,19 @@ var prog = gyp()
var completed = false
prog.parseArgv(process.argv)
prog.buildDir = prog.opts['build-dir'] || 'build'
prog.devDir = prog.opts.devdir

var homeDir = osenv.home()
if (prog.devDir) {
prog.devDir = prog.devDir.replace(/^~/, homeDir)
} else if (homeDir) {
prog.devDir = path.resolve(homeDir, '.node-gyp')
} 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")
}

if (prog.todo.length === 0) {
if (~process.argv.indexOf('-v') || ~process.argv.indexOf('--version')) {
Expand Down
Empty file modified gyp/gyp.bat
100755 → 100644
Empty file.
201 changes: 119 additions & 82 deletions lib/configure.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
module.exports = exports = configure
module.exports.test = { findAccessibleSync: findAccessibleSync,
findPython: findPython }
module.exports.test = {
PythonFinder: PythonFinder,
findAccessibleSync: findAccessibleSync,
findPython: findPython,
}

/**
* Module dependencies.
Expand All @@ -14,11 +17,8 @@ var fs = require('graceful-fs')
, semver = require('semver')
, mkdirp = require('mkdirp')
, cp = require('child_process')
, PathArray = require('path-array')
, extend = require('util')._extend
, processRelease = require('./process-release')
, spawn = cp.spawn
, execFile = cp.execFile
, win = process.platform == 'win32'
, findNodeDirectory = require('./find-node-directory')
, msgFormat = require('util').format
Expand Down Expand Up @@ -289,8 +289,11 @@ function configure (gyp, argv, callback) {
argv.unshift(gyp_script)

// make sure python uses files that came with this particular node package
var pypath = new PathArray(process.env, 'PYTHONPATH')
pypath.unshift(path.join(__dirname, '..', 'gyp', 'pylib'))
var pypath = [path.join(__dirname, '..', 'gyp', 'pylib')]
if (process.env.PYTHONPATH) {
pypath.push(process.env.PYTHONPATH)
}
process.env.PYTHONPATH = pypath.join(win ? ';' : ':')

var cp = gyp.spawn(python, argv)
cp.on('exit', onCpExit)
Expand Down Expand Up @@ -335,34 +338,46 @@ function findAccessibleSync (logprefix, dir, candidates) {
return undefined
}

function findPython (python, callback) {
checkPython()
function PythonFinder(python, callback) {
this.callback = callback
this.python = python
}

// 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) {
PythonFinder.prototype = {
checkPythonLauncherDepth: 0,
env: process.env,
execFile: cp.execFile,
log: log,
stat: fs.stat,
which: which,
win: win,

checkPython: function checkPython () {
this.log.verbose('check python',
'checking for Python executable "%s" in the PATH',
this.python)
this.which(this.python, function (err, execPath) {
if (err) {
log.verbose('`which` failed', python, err)
if (python === 'python2') {
python = 'python'
return checkPython()
this.log.verbose('`which` failed', this.python, err)
if (this.python === 'python2') {
this.python = 'python'
return this.checkPython()
}
if (win) {
checkPythonLauncher()
if (this.win) {
this.checkPythonLauncher()
} else {
failNoPython()
this.failNoPython()
}
} else {
log.verbose('`which` succeeded', python, execPath)
// Found the `python` exceutable, and from now on we use it explicitly.
this.log.verbose('`which` succeeded', this.python, execPath)
// Found the `python` executable, and from now on we use it explicitly.
// This solves #667 and #750 (`execFile` won't run batch files
// (*.cmd, and *.bat))
python = execPath
checkPythonVersion()
this.python = execPath
this.checkPythonVersion()
}
})
}
}.bind(this))
},

// Distributions of Python on Windows by default install with the "py.exe"
// Python launcher which is more likely to exist than the Python executable
Expand All @@ -372,88 +387,110 @@ function findPython (python, callback) {
// the first command line argument. Since "py.exe -2" would be an invalid
// executable for "execFile", we have to use the launcher to figure out
// where the actual "python.exe" executable is located.
function checkPythonLauncher () {
log.verbose('could not find "' + python + '". checking python launcher')
var env = extend({}, process.env)
checkPythonLauncher: function checkPythonLauncher () {
this.checkPythonLauncherDepth += 1

this.log.verbose(
'could not find "' + this.python + '". checking python launcher')
var env = extend({}, this.env)
env.TERM = 'dumb'

var launcherArgs = ['-2', '-c', 'import sys; print sys.executable']
execFile('py.exe', launcherArgs, { env: env }, function (err, stdout) {
this.execFile('py.exe', launcherArgs, { env: env }, function (err, stdout) {
if (err) {
guessPython()
return
}
python = stdout.trim()
log.verbose('check python launcher', 'python executable found: %j', python)
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
this.guessPython()
} else {
this.python = stdout.trim()
this.log.verbose('check python launcher',
'python executable found: %j',
this.python)
this.checkPythonVersion()
}
python = pythonPath
checkPythonVersion()
})
}
this.checkPythonLauncherDepth -= 1
}.bind(this))
},

function checkPythonVersion () {
var env = extend({}, process.env)
checkPythonVersion: function checkPythonVersion () {
var args = ['-c', 'import platform; print(platform.python_version());']
var env = extend({}, this.env)
env.TERM = 'dumb'

execFile(python, ['-c', 'import platform; print(platform.python_version());'], { env: env }, function (err, stdout) {
this.execFile(this.python, args, { env: env }, function (err, stdout) {
if (err) {
return callback(err)
return this.callback(err)
}
log.verbose('check python version', '`%s -c "import platform; print(platform.python_version());"` returned: %j', python, stdout)
this.log.verbose('check python version',
'`%s -c "' + args[1] + '"` returned: %j',
this.python, stdout)
var version = stdout.trim()
if (~version.indexOf('+')) {
log.silly('stripping "+" sign(s) from version')
this.log.silly('stripping "+" sign(s) from version')
version = version.replace(/\+/g, '')
}
if (~version.indexOf('rc')) {
log.silly('stripping "rc" identifier from version')
this.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)
this.log.silly('range.test() error', e)
}
if (valid) {
callback(null, python)
this.callback(null, this.python)
} else if (this.win && this.checkPythonLauncherDepth === 0) {
this.checkPythonLauncher()
} else {
failPythonVersion(version)
this.failPythonVersion(version)
}
})
}
}.bind(this))
},

failNoPython: function failNoPython () {
var errmsg =
'Can\'t find Python executable "' + this.python +
'", you can set the PYTHON env variable.'
this.callback(new Error(errmsg))
},

failPythonVersion: function failPythonVersion (badVersion) {
var errmsg =
'Python executable "' + this.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.'
this.callback(new Error(errmsg))
},

function failNoPython () {
callback(new Error('Can\'t find Python executable "' + python +
'", you can set the PYTHON env variable.'))
}
// Called on Windows when "python" isn't available in the current $PATH.
// We are going to check if "%SystemDrive%\python27\python.exe" exists.
guessPython: function guessPython () {
this.log.verbose('could not find "' + this.python + '". guessing location')
var rootDir = this.env.SystemDrive || 'C:\\'
if (rootDir[rootDir.length - 1] !== '\\') {
rootDir += '\\'
}
var resolve = path.win32 && path.win32.resolve || path.resolve
var pythonPath = resolve(rootDir, 'Python27', 'python.exe')
this.log.verbose('ensuring that file exists:', pythonPath)
this.stat(pythonPath, function (err, stat) {
if (err) {
if (err.code == 'ENOENT') {
this.failNoPython()
} else {
this.callback(err)
}
return
}
this.python = pythonPath
this.checkPythonVersion()
}.bind(this))
},
}

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 findPython (python, callback) {
var finder = new PythonFinder(python, callback)
finder.checkPython()
}
14 changes: 2 additions & 12 deletions lib/node-gyp.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,18 +46,7 @@ function gyp () {
function Gyp () {
var self = this

// set the dir where node-gyp dev files get installed
// TODO: make this *more* configurable?
// see: https://github.com/nodejs/node-gyp/issues/21
var homeDir = process.env.HOME || process.env.USERPROFILE
if (!homeDir) {
throw new Error(
"node-gyp requires that the user's home directory is specified " +
"in either of the environmental variables HOME or USERPROFILE"
);
}
this.devDir = path.resolve(homeDir, '.node-gyp')

this.devDir = ''
this.commands = {}
this.buildDir = ''

Expand Down Expand Up @@ -93,6 +82,7 @@ proto.configDefs = {
, ensure: Boolean // 'install'
, solution: String // 'build' (windows only)
, proxy: String // 'install'
, devdir: String // everywhere
, nodedir: String // 'configure'
, loglevel: String // everywhere
, python: String // 'configure'
Expand Down
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
"nopt": "2 || 3",
"npmlog": "0 || 1 || 2 || 3",
"osenv": "0",
"path-array": "^1.0.0",
"request": "2",
"rimraf": "2",
"semver": "2.x || 3.x || 4 || 5",
Expand Down
Loading

0 comments on commit 1f18133

Please sign in to comment.