Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add io.js support #564

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
test: build-buffertools build-leveldown

build-buffertools:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and build-leveldown should probably depend on an npm install task if you want these tests to be self-contained for CI.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

howso? that's why they are in devDependencies, doesn't that suffice?

cd node_modules/buffertools/ && \
../../bin/node-gyp.js rebuild

build-leveldown:
cd node_modules/leveldown/ && \
../../bin/node-gyp.js rebuild

test-docker-node:
docker run \
--rm=true -i -v `pwd`:/opt/node-gyp/ \
nodesource/node:wheezy \
bash -c 'rm -rf /root/.node-gyp/ && cd /opt/node-gyp && make test'

test-docker-iojs:
docker run \
--rm=true -i -v `pwd`:/opt/node-gyp/ \
iojs/iojs:1.0 \
bash -c 'rm -rf /root/.node-gyp/ && cd /opt/node-gyp && make test'

test-docker: test-docker-node test-docker-iojs
8 changes: 5 additions & 3 deletions lib/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ var fs = require('graceful-fs')
, mkdirp = require('mkdirp')
, exec = require('child_process').exec
, win = process.platform == 'win32'
, semver = require('semver')
, runtime = semver.parse(process.version).major < 1 ? 'node' : 'iojs'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this be a problem when node v1 is released?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can there be an override for this as an env variable? e.g. tcr/pangyp@b9209b8

If I want to enable gyp configure --target=1.3.0 and gyp configure --target=0.12.0, I'd rather not have to install both iojs and node, just to alter the meaning of process.version.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in iojs you can check for process.release.name.
in nodejs process.release doesn't even exist, yet.

To set as a target I would recommend to use same notation as nvm: gyp configure --target=iojs-v3.0.0


exports.usage = 'Invokes `' + (win ? 'msbuild' : 'make') + '` and builds the module'

Expand Down Expand Up @@ -181,15 +183,15 @@ function build (gyp, argv, callback) {
if (!win || !copyDevLib) return doBuild()

var buildDir = path.resolve(nodeDir, buildType)
, archNodeLibPath = path.resolve(nodeDir, arch, 'node.lib')
, buildNodeLibPath = path.resolve(buildDir, 'node.lib')
, archNodeLibPath = path.resolve(nodeDir, arch, runtime + '.lib')
, buildNodeLibPath = path.resolve(buildDir, runtime + '.lib')

mkdirp(buildDir, function (err, isNew) {
if (err) return callback(err)
log.verbose('"' + buildType + '" dir needed to be created?', isNew)
var rs = fs.createReadStream(archNodeLibPath)
, ws = fs.createWriteStream(buildNodeLibPath)
log.verbose('copying "node.lib" for ' + arch, buildNodeLibPath)
log.verbose('copying "' + runtime + '.lib" for ' + arch, buildNodeLibPath)
rs.pipe(ws)
rs.on('error', callback)
ws.on('error', callback)
Expand Down
30 changes: 3 additions & 27 deletions lib/configure.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,36 +123,12 @@ function configure (gyp, argv, callback) {
createBuildDir()

} else {
// if no --nodedir specified, ensure node dependencies are installed
var version
var versionStr

if (gyp.opts.target) {
// if --target was given, then determine a target version to compile for
versionStr = gyp.opts.target
log.verbose('get node dir', 'compiling against --target node version: %s', versionStr)
} else {
// if no --target was specified then use the current host node version
versionStr = process.version
log.verbose('get node dir', 'no --target version specified, falling back to host node version: %s', versionStr)
}

// make sure we have a valid version
try {
version = semver.parse(versionStr)
} catch (e) {
return callback(e)
}
if (!version) {
return callback(new Error('Invalid version number: ' + versionStr))
}

// ensure that the target node version's dev files are installed
gyp.opts.ensure = true
gyp.commands.install([ versionStr ], function (err, version) {
gyp.commands.install([], function (err, release) {
if (err) return callback(err)
log.verbose('get node dir', 'target node version installed:', version)
nodeDir = path.resolve(gyp.devDir, version)
log.verbose('get node dir', 'target node version installed:', release.version)
nodeDir = release.devDir
createBuildDir()
})
}
Expand Down
135 changes: 61 additions & 74 deletions lib/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,50 +15,45 @@ var fs = require('graceful-fs')
, crypto = require('crypto')
, zlib = require('zlib')
, log = require('npmlog')
, semver = require('semver')
, fstream = require('fstream')
, request = require('request')
, minimatch = require('minimatch')
, mkdir = require('mkdirp')
, getRelease = require('./util/release')
, win = process.platform == 'win32'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any idea to support nvm custom dist url env by default? https://github.com/creationix/nvm/blob/master/nvm.sh#L73

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@fengmk2 would this be to support mirrors, like in China? I'm tinkering around in there currently and it wouldn't be hard to bring in custom URLs from where my local version is at.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not only for mirrors, but also can be used in private NPM services. @rvagg

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rvagg yes, it will be very helpful for us.

function install (gyp, argv, callback) {

// Determine which node dev files version we are installing
var release
try {
release = getRelease(gyp, argv[0] || gyp.opts.target)
} catch (e) {
return callback(e)
}

console.log(release)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this (I assume?)


log.verbose('install', 'input version string %j', release.versionStr)

// ensure no double-callbacks happen
function cb (err) {
if (cb.done) return
cb.done = true
if (err) {
log.warn('install', 'got an error, rolling back install')
// roll-back the install if anything went wrong
gyp.commands.remove([ version ], function (err2) {
gyp.commands.remove([ release.version.version ], function (err2) {
callback(err)
})
} else {
callback(null, version)
callback(null, release)
}
}

var distUrl = gyp.opts['dist-url'] || gyp.opts.disturl || 'http://nodejs.org/dist'


// Determine which node dev files version we are installing
var versionStr = argv[0] || gyp.opts.target || process.version
log.verbose('install', 'input version string %j', versionStr)

// parse the version to normalize and ensure it's valid
var version = semver.parse(versionStr)
if (!version) {
return callback(new Error('Invalid version number: ' + versionStr))
}

if (semver.lt(versionStr, '0.8.0')) {
return callback(new Error('Minimum target version is `0.8.0` or greater. Got: ' + versionStr))
}

// 0.x.y-pre versions are not published yet and cannot be installed. Bail.
if (version.prerelease[0] === 'pre') {
log.verbose('detected "pre" node version', versionStr)
if (release.version.prerelease[0] === 'pre') {
log.verbose('detected "pre" node version', release.versionStr)
if (gyp.opts.nodedir) {
log.verbose('--nodedir flag was passed; skipping install', gyp.opts.nodedir)
callback()
Expand All @@ -69,23 +64,16 @@ function install (gyp, argv, callback) {
}

// flatten version into String
version = version.version
log.verbose('install', 'installing version: %s', version)

// distributions starting with 0.10.0 contain sha256 checksums
var checksumAlgo = semver.gte(version, '0.10.0') ? 'sha256' : 'sha1'

// the directory where the dev files will be installed
var devDir = path.resolve(gyp.devDir, version)
log.verbose('install', 'installing version: %s', release.version.version)

// If '--ensure' was passed, then don't *always* install the version;
// check if it is already installed, and only install when needed
if (gyp.opts.ensure) {
log.verbose('install', '--ensure was passed, so won\'t reinstall if already installed')
fs.stat(devDir, function (err, stat) {
fs.stat(release.devDir, function (err, stat) {
if (err) {
if (err.code == 'ENOENT') {
log.verbose('install', 'version not already installed, continuing with install', version)
log.verbose('install', 'version not already installed, continuing with install', release.versionStr)
go()
} else if (err.code == 'EACCES') {
eaccesFallback()
Expand All @@ -95,7 +83,7 @@ function install (gyp, argv, callback) {
return
}
log.verbose('install', 'version is already installed, need to check "installVersion"')
var installVersionFile = path.resolve(devDir, 'installVersion')
var installVersionFile = path.resolve(release.devDir, 'installVersion')
fs.readFile(installVersionFile, 'ascii', function (err, ver) {
if (err && err.code != 'ENOENT') {
return cb(err)
Expand Down Expand Up @@ -156,7 +144,7 @@ function install (gyp, argv, callback) {
}

function getContentSha(res, callback) {
var shasum = crypto.createHash(checksumAlgo)
var shasum = crypto.createHash(release.checksumAlgo)
res.on('data', function (chunk) {
shasum.update(chunk)
}).on('end', function () {
Expand All @@ -166,10 +154,10 @@ function install (gyp, argv, callback) {

function go () {

log.verbose('ensuring nodedir is created', devDir)
log.verbose('ensuring nodedir is created', release.devDir)

// first create the dir for the node dev files
mkdir(devDir, function (err, created) {
mkdir(release.devDir, function (err, created) {
if (err) {
if (err.code == 'EACCES') {
eaccesFallback()
Expand All @@ -184,33 +172,32 @@ function install (gyp, argv, callback) {
}

// now download the node tarball
var tarPath = gyp.opts['tarball']
var tarballUrl = tarPath ? tarPath : distUrl + '/v' + version + '/node-v' + version + '.tar.gz'
var tarPath = gyp.opts.tarball
, badDownload = false
, extractCount = 0
, gunzip = zlib.createGunzip()
, extracter = tar.Extract({ path: devDir, strip: 1, filter: isValid })
, extracter = tar.Extract({ path: release.devDir, strip: 1, filter: isValid })

var contentShasums = {}
var expectShasums = {}

// checks if a file to be extracted from the tarball is valid.
// only .h header files and the gyp files get extracted
function isValid () {
var name = this.path.substring(devDir.length + 1)
var isValid = valid(name)
var name = this.path.substring(release.devDir.length + 1)
var validName = valid(name)
if (name === '' && this.type === 'Directory') {
// the first directory entry is ok
return true
}
if (isValid) {
if (validName) {
log.verbose('extracted file from tarball', name)
extractCount++
} else {
// invalid
log.silly('ignoring from tarball', name)
}
return isValid
return validName
}

gunzip.on('error', cb)
Expand All @@ -220,12 +207,12 @@ function install (gyp, argv, callback) {
// download the tarball, gunzip and extract!

if (tarPath) {
var input = fs.createReadStream(tarballUrl)
var input = fs.createReadStream(release.sourceUrl)
input.pipe(gunzip).pipe(extracter)
return
}

var req = download(tarballUrl)
var req = download(release.sourceUrl)
if (!req) return

// something went wrong downloading the tarball?
Expand All @@ -248,7 +235,7 @@ function install (gyp, argv, callback) {
}
// content checksum
getContentSha(res, function (_, checksum) {
var filename = path.basename(tarballUrl).trim()
var filename = path.basename(release.sourceUrl).trim()
contentShasums[filename] = checksum
log.verbose('content checksum', filename, checksum)
})
Expand All @@ -274,7 +261,7 @@ function install (gyp, argv, callback) {

// write the "installVersion" file
async++
var installVersionPath = path.resolve(devDir, 'installVersion')
var installVersionPath = path.resolve(release.devDir, 'installVersion')
fs.writeFile(installVersionPath, gyp.package.installVersion + '\n', deref)

// download SHASUMS.txt
Expand Down Expand Up @@ -306,13 +293,11 @@ function install (gyp, argv, callback) {
}

function downloadShasums(done) {
var shasumsFile = (checksumAlgo === 'sha256') ? 'SHASUMS256.txt' : 'SHASUMS.txt'
log.verbose('check download content checksum, need to download `' + shasumsFile + '`...')
var shasumsPath = path.resolve(devDir, shasumsFile)
, shasumsUrl = distUrl + '/v' + version + '/' + shasumsFile
log.verbose('check download content checksum, need to download `' + release.shasumsFile + '`...')
var shasumsPath = path.resolve(release.devDir, release.shasumsFile)

log.verbose('checksum url', shasumsUrl)
var req = download(shasumsUrl)
log.verbose('checksum url', release.shasumsUrl)
var req = download(release.shasumsUrl)
if (!req) return
req.on('error', done)
req.on('response', function (res) {
Expand Down Expand Up @@ -343,36 +328,38 @@ function install (gyp, argv, callback) {
}

function downloadNodeLib (done) {
log.verbose('on Windows; need to download `node.lib`...')
var dir32 = path.resolve(devDir, 'ia32')
, dir64 = path.resolve(devDir, 'x64')
, nodeLibPath32 = path.resolve(dir32, 'node.lib')
, nodeLibPath64 = path.resolve(dir64, 'node.lib')
, nodeLibUrl32 = distUrl + '/v' + version + '/node.lib'
, nodeLibUrl64 = distUrl + '/v' + version + '/x64/node.lib'

log.verbose('32-bit node.lib dir', dir32)
log.verbose('64-bit node.lib dir', dir64)
log.verbose('`node.lib` 32-bit url', nodeLibUrl32)
log.verbose('`node.lib` 64-bit url', nodeLibUrl64)
log.verbose('on Windows; need to download `' + runtime + '.lib`...')
var dir32 = path.resolve(release.devDir, 'ia32')
, dir64 = path.resolve(release.devDir, 'x64')
, nodeLibPath32 = path.resolve(dir32, runtime + '.lib')
, nodeLibPath64 = path.resolve(dir64, runtime + '.lib')
, nodeLibUrlFile32 = (runtime == 'node' ? 'node.lib' : 'win-x86/iojs.lib')
, nodeLibUrlFile64 = (runtime == 'node' ? 'x64/node.lib' : 'win-x64/iojs.lib')
, nodeLibUrl32 = distUrl + '/v' + version + '/' + nodeLibUrlFile32
, nodeLibUrl64 = distUrl + '/v' + version + '/' + nodeLibUrlFile64

log.verbose('32-bit ' + runtime + '.lib dir', dir32)
log.verbose('64-bit ' + runtime + '.lib dir', dir64)
log.verbose('`' + runtime + '.lib` 32-bit url', nodeLibUrl32)
log.verbose('`' + runtime + '.lib` 64-bit url', nodeLibUrl64)

var async = 2
mkdir(dir32, function (err) {
if (err) return done(err)
log.verbose('streaming 32-bit node.lib to:', nodeLibPath32)
log.verbose('streaming 32-bit ' + runtime + '.lib to:', nodeLibPath32)

var req = download(nodeLibUrl32)
if (!req) return
req.on('error', done)
req.on('response', function (res) {
if (res.statusCode !== 200) {
done(new Error(res.statusCode + ' status code downloading 32-bit node.lib'))
done(new Error(res.statusCode + ' status code downloading 32-bit ' + runtime + '.lib'))
return
}

getContentSha(res, function (_, checksum) {
contentShasums['node.lib'] = checksum
log.verbose('content checksum', 'node.lib', checksum)
contentShasums[nodeLibUrlFile32] = checksum
log.verbose('content checksum', nodeLibUrlFile32, checksum)
})

var ws = fs.createWriteStream(nodeLibPath32)
Expand All @@ -385,20 +372,20 @@ function install (gyp, argv, callback) {
})
mkdir(dir64, function (err) {
if (err) return done(err)
log.verbose('streaming 64-bit node.lib to:', nodeLibPath64)
log.verbose('streaming 64-bit ' + runtime + '.lib to:', nodeLibPath64)

var req = download(nodeLibUrl64)
if (!req) return
req.on('error', done)
req.on('response', function (res) {
if (res.statusCode !== 200) {
done(new Error(res.statusCode + ' status code downloading 64-bit node.lib'))
done(new Error(res.statusCode + ' status code downloading 64-bit ' + runtime + '.lib'))
return
}

getContentSha(res, function (_, checksum) {
contentShasums['x64/node.lib'] = checksum
log.verbose('content checksum', 'x64/node.lib', checksum)
contentShasums[nodeLibUrlFile64] = checksum
log.verbose('content checksum', nodeLibUrlFile64, checksum)
})

var ws = fs.createWriteStream(nodeLibPath64)
Expand Down Expand Up @@ -437,7 +424,7 @@ function install (gyp, argv, callback) {
function eaccesFallback () {
var tmpdir = osenv.tmpdir()
gyp.devDir = path.resolve(tmpdir, '.node-gyp')
log.warn('EACCES', 'user "%s" does not have permission to access the dev dir "%s"', osenv.user(), devDir)
log.warn('EACCES', 'user "%s" does not have permission to access the dev dir "%s"', osenv.user(), release.devDir)
log.warn('EACCES', 'attempting to reinstall using temporary dev dir "%s"', gyp.devDir)
if (process.cwd() == tmpdir) {
log.verbose('tmpdir == cwd', 'automatically will remove dev files after to save disk space')
Expand Down
Loading