From faa4420055d9c9f5c9591c07f333c3535782890e Mon Sep 17 00:00:00 2001 From: Adeel Date: Sat, 7 Mar 2015 15:55:49 +0200 Subject: [PATCH] Build: Centralises binary naming convensions. * Delivers binary name, paths and download URL from lib/extensions.js. * Allows user to set binary name as environment variable with `SASS_BINARY_NAME`. * This name will be used to construct the: * Binary path. * Binary download URL. * Upload URL. * Note: this will supersede default name. * Allows user to set binary name as parameter to invoke any node-sass script with `--binary-name` flag. * This name will be used to construct the: * Binary path. * Binary download URL. * Upload URL. * Note: this will supersede both default name as well as the `SASS_BINARY_NAME` environment variable. * Allows user to set binary path as environment variable with `SASS_BINARY_PATH`. * This name will be used when: * Requiring node-sass package. * Downloading binary. * Uploading binary. * Note: this will supersede default path. * Allows user to set binary path as parameter to invoke any node-sass script with `--binary-path` flag. * This name will be used when: * Requiring node-sass package. * Downloading binary. * Uploading binary. * Note: this will supersede both default path as well as the `SASS_BINARY_PATH` environment variable. * Wraps all extensions in `process.sass` namespace. Issue URL: #712. PR URL: #743. --- bin/node-sass | 3 +- lib/extensions.js | 102 +++++++++++++++++++++++++++++++++++++++----- lib/index.js | 35 ++++----------- lib/render.js | 4 ++ scripts/build.js | 47 ++++++++++---------- scripts/coverage.js | 4 ++ scripts/install.js | 58 ++++++++++--------------- scripts/upload.js | 17 ++++---- src/binding.cpp | 6 +-- test/api.js | 12 ++---- test/cli.js | 2 +- 11 files changed, 172 insertions(+), 118 deletions(-) diff --git a/bin/node-sass b/bin/node-sass index cd3ef1be1..157f81bc0 100755 --- a/bin/node-sass +++ b/bin/node-sass @@ -1,4 +1,5 @@ #!/usr/bin/env node + var Emitter = require('events').EventEmitter, Gaze = require('gaze'), grapher = require('sass-graph'), @@ -13,7 +14,7 @@ var Emitter = require('events').EventEmitter, var cli = meow({ pkg: '../package.json', - version: process.sassInfo, + version: process.sass.versionInfo, help: [ 'Usage', ' node-sass [options] [output.css]', diff --git a/lib/extensions.js b/lib/extensions.js index e3fa386ee..dc8878230 100644 --- a/lib/extensions.js +++ b/lib/extensions.js @@ -1,6 +1,12 @@ +/*! + * node-sass: lib/extensions.js + */ + var eol = require('os').EOL, + flags = require('meow')({ pkg: '../package.json' }).flags, fs = require('fs'), - package = require('../package.json'); + package = require('../package.json'), + path = require('path'); /** * Get Runtime Info @@ -24,26 +30,100 @@ function getRuntimeInfo() { } /** - * Get unique name of binary for current platform + * Get binary name. + * If environment variable SASS_BINARY_NAME or + * process aurgument --binary-name is provide, + * return it as is, otherwise make default binary + * name: {platform}-{arch}-{v8 version}.node * * @api private */ -function getBinaryIdentifiableName() { - var v8SemVersion = process.versions.v8.split('.').slice(0, 3).join('.'); +function getBinaryName() { + var binaryName; + + if (flags.binaryName) { + binaryName = flags.binaryName; + } else if (process.env.SASS_BINARY_NAME) { + binaryName = process.env.SASS_BINARY_NAME; + } else { + var v8SemVersion = process.versions.v8.split('.').slice(0, 3).join('.'); + + binaryName = [process.platform, '-', + process.arch, '-', + v8SemVersion].join(''); + } + + return [binaryName, 'binding.node'].join('/'); +} + +/** + * Retrieve the URL to fetch binary. + * If environment variable SASS_BINARY_URL + * is set, return that path. Otherwise make + * path using current release version and + * binary name. + * + * @api private + */ - return [process.platform, '-', - process.arch, '-', - v8SemVersion].join(''); +function getBinaryUrl() { + return flags.binaryUrl || + process.env.SASS_BINARY_URL || + ['https://github.com/sass/node-sass/releases/download//v', + package.version, '/', sass.binaryName].join(''); } -function getSassInfo() { +/** + * Get Sass version information + * + * @api private + */ + +function getVersionInfo() { return [ ['node-sass', package.version, '(Wrapper)', '[JavaScript]'].join('\t'), ['libsass ', package.libsass, '(Sass Compiler)', '[C/C++]'].join('\t'), ].join(eol); } -process.runtime = getRuntimeInfo(); -process.sassInfo = getSassInfo(); -process.sassBinaryName = getBinaryIdentifiableName(); +var sass = process.sass = {}; + +sass.binaryName = getBinaryName(); +sass.binaryUrl = getBinaryUrl(); +sass.runtime = getRuntimeInfo(); +sass.versionInfo = getVersionInfo(); + +/** + * Get binary path. + * If environment variable SASS_BINARY_PATH or + * process aurgument --binary-path is provide, + * select it by appending binary name, otherwise + * make default binary path using binary name. + * Once the primary selection is made, check if + * callers wants to throw if file not exists before + * returning. + * + * @param {Boolean} throwIfNotExists + * @api private + */ + +sass.getBinaryPath = function(throwIfNotExists) { + var binaryPath; + + if (flags.binaryPath) { + binaryPath = path.join(flags.binaryPath, sass.binaryName); + } else if (process.env.SASS_BINARY_PATH) { + binaryPath = path.join(process.env.SASS_BINARY_PATH, sass.binaryName); + } else { + binaryPath = path.join(__dirname, '..', 'vendor', sass.binaryName); + } + + if (!fs.existsSync(binaryPath) && throwIfNotExists) { + throw new Error('`libsass` bindings not found. Try reinstalling `node-sass`?'); + } + + return binaryPath; +}; + +sass.binaryPath = sass.getBinaryPath(); diff --git a/lib/index.js b/lib/index.js index 4fcf291a8..e05469285 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,30 +1,17 @@ -var fs = require('fs'), - path = require('path'), +/*! + * node-sass: lib/index.js + */ + +var path = require('path'), util = require('util'); require('./extensions'); /** - * Get binding - * - * @api private + * Require binding */ -function getBinding() { - var candidates = [ - path.join(__dirname, '..', 'build', 'Debug', 'binding.node'), - path.join(__dirname, '..', 'build', 'Release', 'binding.node'), - path.join(__dirname, '..', 'vendor', process.sassBinaryName, 'binding.node') - ]; - - var candidate = candidates.filter(fs.existsSync).shift(); - - if (!candidate) { - throw new Error('`libsass` bindings not found. Try reinstalling `node-sass`?'); - } - - return candidate; -} +var binding = require(process.sass.getBinaryPath(true)); /** * Get input file @@ -149,12 +136,6 @@ function getOptions(options, cb) { return options; } -/** - * Require binding - */ - -var binding = require(getBinding()); - /** * Render * @@ -246,4 +227,4 @@ module.exports.renderSync = function(options) { * @api public */ -module.exports.info = process.sassInfo; +module.exports.info = process.sass.versionInfo; diff --git a/lib/render.js b/lib/render.js index a71a83eb3..743c12e15 100644 --- a/lib/render.js +++ b/lib/render.js @@ -1,3 +1,7 @@ +/*! + * node-sass: lib/render.js + */ + var fs = require('fs'), chalk = require('chalk'), sass = require('./'), diff --git a/scripts/build.js b/scripts/build.js index b7314b9d6..8811102ba 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -1,3 +1,7 @@ +/*! + * node-sass: scripts/build.js + */ + var eol = require('os').EOL, fs = require('fs'), mkdir = require('mkdirp'), @@ -14,11 +18,10 @@ require('../lib/extensions'); */ function afterBuild(options) { - var folder = options.debug ? 'Debug' : 'Release'; - var target = path.join(__dirname, '..', 'build', folder, 'binding.node'); - var install = path.join(__dirname, '..', 'vendor', process.sassBinaryName, 'binding.node'); + var install = process.sass.binaryPath; + var target = path.join(__dirname, '..', 'build', options.debug ? 'Debug' : 'Release', 'binding.node'); - mkdir(path.join(__dirname, '..', 'vendor', process.sassBinaryName), function(err) { + mkdir(path.dirname(install), function(err) { if (err && err.code !== 'EEXIST') { console.error(err.message); return; @@ -36,7 +39,7 @@ function afterBuild(options) { return; } - console.log('Installed in `' + install + '`'); + console.log('Installed in `', install, '`'); }); }); }); @@ -52,9 +55,9 @@ function afterBuild(options) { function build(options) { var arguments = [path.join('node_modules', 'pangyp', 'bin', 'node-gyp'), 'rebuild'].concat(options.args); - console.log(['Building:', process.runtime.execPath].concat(arguments).join(' ')); + console.log(['Building:', process.sass.runtime.execPath].concat(arguments).join(' ')); - var proc = spawn(process.runtime.execPath, arguments, { + var proc = spawn(process.sass.runtime.execPath, arguments, { stdio: [0, 1, 2] }); @@ -110,25 +113,25 @@ function testBinary(options) { return build(options); } - fs.stat(path.join(__dirname, '..', 'vendor', process.sassBinaryName, 'binding.node'), function(err) { - if (err) { - return build(options); - } + try { + process.sass.getBinaryPath(true); + } catch (e) { + return build(options); + } - console.log('`' + process.sassBinaryName + '` exists; testing.'); + console.log('`', process.sass.binaryName, '`exists at', eol, process.sass.binaryPath, eol, 'testing binary.'); - try { - require('../').renderSync({ - data: 's: { a: ss }' - }); + try { + require('../').renderSync({ + data: 's: { a: ss }' + }); - console.log('Binary is fine; exiting.'); - } catch (e) { - console.log(['Problem with the binary.', 'Manual build incoming.'].join(eol)); + console.log('Binary is fine; exiting.'); + } catch (e) { + console.log(['Problem with the binary.', 'Manual build incoming.'].join(eol)); - return build(options); - } - }); + return build(options); + } } /** diff --git a/scripts/coverage.js b/scripts/coverage.js index e54f0748e..676245b68 100644 --- a/scripts/coverage.js +++ b/scripts/coverage.js @@ -1,3 +1,7 @@ +/*! + * node-sass: scripts/coverage.js + */ + var path = require('path'), spawn = require('child_process').spawn, bin = path.join.bind(null, __dirname, '..', 'node_modules', '.bin'); diff --git a/scripts/install.js b/scripts/install.js index a4fd5f4df..7e63604c9 100644 --- a/scripts/install.js +++ b/scripts/install.js @@ -1,9 +1,13 @@ +/*! + * node-sass: scripts/install.js + */ + var fs = require('fs'), - path = require('path'), - request = require('request'), - mkdirp = require('mkdirp'), - npmconf = require('npmconf'), - packageInfo = require('../package.json'); + mkdir = require('mkdirp'); +path = require('path'), +request = require('request'), +npmconf = require('npmconf'), +packageInfo = require('../package.json'); require('../lib/extensions'); @@ -24,7 +28,7 @@ function download(url, dest, cb) { request.get(url, options).on('response', function(response) { if (response.statusCode < 200 || response.statusCode >= 300) { - returnError('Can not download file from ' + url); + returnError(['Can not download file from:', url].join()); return; } @@ -64,49 +68,31 @@ function applyProxy(options, cb) { } /** - * Check if binaries exists - * - * @api private - */ - -function checkAndFetchBinaries() { - fs.exists(path.join(__dirname, '..', 'vendor', process.sassBinaryName), function (exists) { - if (exists) { - return; - } - - fetch(); - }); -} - -/** - * Fetch binaries + * Check and download binary * * @api private */ -function fetch() { - var url = [ - 'https://github.com/raw/sass/node-sass-binaries/v', - packageInfo.version, '/', process.sassBinaryName, - '/binding.node' - ].join(''); - var dir = path.join(__dirname, '..', 'vendor', process.sassBinaryName); - var dest = path.join(dir, 'binding.node'); +function checkAndDownloadBinary() { + try { + process.sass.getBinaryPath(true); + } catch (e) { + return; + } - mkdirp(dir, function(err) { + mkdirp(path.dirname(process.sass.binaryPath), function(err) { if (err) { console.error(err); return; } - download(url, dest, function(err) { + download(process.sass.binaryUrl, process.sass.binaryPath, function(err) { if (err) { console.error(err); return; } - console.log('Binary downloaded and installed at ' + dest); + console.log('Binary downloaded and installed at', process.sass.binaryPath); }); }); } @@ -121,7 +107,7 @@ if (process.env.SKIP_SASS_BINARY_DOWNLOAD_FOR_CI) { } /** - * Run + * If binary does not exsits, download it */ -checkAndFetchBinaries(); +checkAndDownloadBinary(); diff --git a/scripts/upload.js b/scripts/upload.js index a8c4ecca4..2bb0bc12f 100644 --- a/scripts/upload.js +++ b/scripts/upload.js @@ -1,19 +1,18 @@ /*! * node-sass: scripts/upload.js */ + require('../lib/extensions'); var flags = require('meow')({ pkg: '../' }).flags; -var fetchReleaseInfoUrl = ['https://github.com/gitapi/repos/sass/node-sass/releases/tags/v', +var eol = require('os').EOL, + fetchReleaseInfoUrl = ['https://github.com/gitapi/repos/sass/node-sass/releases/tags/v', flags.tag ? flags.tag : require('../package.json').version].join(''), - file = flags.path ? - flags.path : - require('path').resolve(__dirname, '..', 'vendor', process.sassBinaryName, 'binding.node'), + file = flags.path ? flags.path : process.sass.binaryPath, fs = require('fs'), - os = require('os'), request = require('request'), - uploadReleaseAssetUrl = ['?name=', process.sassBinaryName, '.node', '&label=', process.sassBinaryName].join(''); + uploadReleaseAssetUrl = ['?name=', process.sass.binaryName].join(''); /** * Upload binary using GitHub API @@ -48,8 +47,8 @@ function uploadBinary() { } console.log(['Binary uploaded successfully.', - 'Please test the following link before announcement it:', - formattedResponse.browser_download_url].join(os.EOL)); + 'Please test the following link before announcing it:', + formattedResponse.browser_download_url].join(eol)); }); }; @@ -75,7 +74,7 @@ function uploadBinary() { function throwFormattedError(err) { throw new Error([ 'Error uploading release asset.', - 'The server returned:', JSON.stringify(err)].join(os.EOL)); + 'The server returned:', JSON.stringify(err)].join(eol)); } /** diff --git a/src/binding.cpp b/src/binding.cpp index 6d652b90b..71dd1f18a 100644 --- a/src/binding.cpp +++ b/src/binding.cpp @@ -24,7 +24,7 @@ void prepare_import_results(Local returned_value, sass_context_wrapper* c ctx_w->imports = sass_make_import_list(array->Length()); for (size_t i = 0; i < array->Length(); ++i) { - Local value = array->Get(i); + Local value = array->Get(static_cast(i)); if (!value->IsObject()) continue; @@ -186,12 +186,12 @@ int get_result(sass_context_wrapper* ctx_w, Sass_Context* ctx, bool is_sync = fa const char* css = sass_context_get_output_string(ctx); const char* map = sass_context_get_source_map_string(ctx); - NanNew(ctx_w->result)->Set(NanNew("css"), NanNewBufferHandle(css, strlen(css))); + NanNew(ctx_w->result)->Set(NanNew("css"), NanNewBufferHandle(css, static_cast(strlen(css)))); get_stats(ctx_w, ctx); if (map) { - NanNew(ctx_w->result)->Set(NanNew("map"), NanNewBufferHandle(map, strlen(map))); + NanNew(ctx_w->result)->Set(NanNew("map"), NanNewBufferHandle(map, static_cast(strlen(map)))); } } else if (is_sync) { diff --git a/test/api.js b/test/api.js index b441738c2..d68834329 100644 --- a/test/api.js +++ b/test/api.js @@ -104,20 +104,16 @@ describe('api', function() { }); it('should throw error when libsass binary is missing.', function(done) { - var originalBin = path.join('vendor', process.sassBinaryName, 'binding.node'), + var originalBin = process.sass.binaryPath, renamedBin = [originalBin, '_moved'].join(''); assert.throws(function() { - // un-require node-sass - var resolved = require.resolve('../lib'); - delete require.cache[resolved]; - fs.renameSync(originalBin, renamedBin); - // try to re-require it - require('../lib'); + process.sass.getBinaryPath(true); }, function(err) { + fs.renameSync(renamedBin, originalBin); + console.log(err); if ((err instanceof Error) && /`libsass` bindings not found. Try reinstalling `node-sass`?/.test(err)) { - fs.renameSync(renamedBin, originalBin); done(); return true; } diff --git a/test/cli.js b/test/cli.js index 002d24b64..dd81da17d 100644 --- a/test/cli.js +++ b/test/cli.js @@ -201,8 +201,8 @@ describe('cli', function() { bin.on('close', function() { assert.equal(read(destCss, 'utf8').trim(), expectedCss); assert.equal(read(destMap, 'utf8').trim(), expectedMap); - fs.unlinkSync(destMap); fs.unlinkSync(destCss); + fs.unlinkSync(destMap); done(); }); });