Commit 2220ba96 by Adeel

Build: Centralises binary naming conventions.

* Delivers binary name, paths and download URL
  from lib/extensions.js.

* Allows user to set binary name as environment
  variable with `SASS_BINARY_NAME`.
  * Note: this will supersede default name.
* Allows user to set binary name as in package
  file `"nodeSassConfig": { "binary-name": "" }`.
  * Note: this will supersede default name and
    `SASS_BINARY_NAME` environment variable.
* Allows user to set binary name as parameter to
  invoke any node-sass script with
  `--binary-name` flag.
  * Note: this will supersede default name, name
    defined in package `nodeSassConfig` as well
    as the `SASS_BINARY_NAME` environment
    variable.

* This binary name will be used to construct the:
  * Binary path.
  * Binary download URL.
  * Upload URL.

* Allows user to set binary path as environment
  variable with `SASS_BINARY_PATH`.
  * Note: this will supersede default path.
* Allows user to set binary name as in package
  file `"nodeSassConfig": { "binary-path": "" }`.
  * Note: this will supersede default path and
    `SASS_BINARY_PATH` environment variable.
* Allows user to set binary path as parameter to
  invoke any node-sass script with
  `--binary-path` flag.
  * Note: this will supersede default path, path
    as well as the `SASS_BINARY_PATH` environment
    variable.

* This binary path will be used when:
  * Requiring node-sass package.
  * Downloading binary.
  * Uploading binary.

* Wraps all extensions in `process.sass`
  namespace.

Issue URL: #712.
PR URL: #743.
parent 492099e1
#!/usr/bin/env node #!/usr/bin/env node
var Emitter = require('events').EventEmitter, var Emitter = require('events').EventEmitter,
Gaze = require('gaze'), Gaze = require('gaze'),
grapher = require('sass-graph'), grapher = require('sass-graph'),
...@@ -13,7 +14,7 @@ var Emitter = require('events').EventEmitter, ...@@ -13,7 +14,7 @@ var Emitter = require('events').EventEmitter,
var cli = meow({ var cli = meow({
pkg: '../package.json', pkg: '../package.json',
version: process.sassInfo, version: process.sass.versionInfo,
help: [ help: [
'Usage', 'Usage',
' node-sass [options] <input.scss> [output.css]', ' node-sass [options] <input.scss> [output.css]',
......
/*!
* node-sass: lib/extensions.js
*/
var eol = require('os').EOL, var eol = require('os').EOL,
flags = require('meow')({ pkg: '../package.json' }).flags,
fs = require('fs'), fs = require('fs'),
package = require('../package.json'); package = require('../package.json'),
path = require('path');
/** /**
* Get Runtime Info * Get Runtime Info
...@@ -24,26 +30,105 @@ function getRuntimeInfo() { ...@@ -24,26 +30,105 @@ 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 * @api private
*/ */
function getBinaryIdentifiableName() { function getBinaryName() {
var binaryName;
if (flags.binaryName) {
binaryName = flags.binaryName;
} else if (package.nodeSassConfig && package.nodeSassConfig.binaryName) {
binaryName = package.nodeSassConfig.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('.'); var v8SemVersion = process.versions.v8.split('.').slice(0, 3).join('.');
return [process.platform, '-', binaryName = [process.platform, '-',
process.arch, '-', process.arch, '-',
v8SemVersion].join(''); 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
*/
function getBinaryUrl() {
return flags.binaryUrl ||
package.nodeSassConfig ? package.nodeSassConfig.binaryUrl : null ||
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 [ return [
['node-sass', package.version, '(Wrapper)', '[JavaScript]'].join('\t'), ['node-sass', package.version, '(Wrapper)', '[JavaScript]'].join('\t'),
['libsass ', package.libsass, '(Sass Compiler)', '[C/C++]'].join('\t'), ['libsass ', package.libsass, '(Sass Compiler)', '[C/C++]'].join('\t'),
].join(eol); ].join(eol);
} }
process.runtime = getRuntimeInfo(); var sass = process.sass = {};
process.sassInfo = getSassInfo();
process.sassBinaryName = getBinaryIdentifiableName(); 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 = flags.binaryPath;
} else if (package.nodeSassConfig && package.nodeSassConfig.binaryPath) {
binaryPath = package.nodeSassConfig.binaryPath;
} else if (process.env.SASS_BINARY_PATH) {
binaryPath = process.env.SASS_BINARY_PATH;
} else {
binaryPath = path.join(__dirname, '..', 'vendor', sass.binaryName.replace(/_/, '/'));
}
if (!fs.existsSync(binaryPath) && throwIfNotExists) {
throw new Error('`libsass` bindings not found. Try reinstalling `node-sass`?');
}
return binaryPath;
};
sass.binaryPath = sass.getBinaryPath();
var fs = require('fs'), /*!
path = require('path'), * node-sass: lib/index.js
*/
var path = require('path'),
util = require('util'); util = require('util');
require('./extensions'); require('./extensions');
/** /**
* Get binding * Require binding
*
* @api private
*/ */
function getBinding() { var binding = require(process.sass.getBinaryPath(true));
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;
}
/** /**
* Get input file * Get input file
...@@ -150,12 +137,6 @@ function getOptions(options, cb) { ...@@ -150,12 +137,6 @@ function getOptions(options, cb) {
} }
/** /**
* Require binding
*/
var binding = require(getBinding());
/**
* Render * Render
* *
* @param {Object} options * @param {Object} options
...@@ -246,4 +227,4 @@ module.exports.renderSync = function(options) { ...@@ -246,4 +227,4 @@ module.exports.renderSync = function(options) {
* @api public * @api public
*/ */
module.exports.info = process.sassInfo; module.exports.info = process.sass.versionInfo;
var fs = require('fs'), /*!
chalk = require('chalk'), * node-sass: lib/render.js
sass = require('./'), */
var chalk = require('chalk'),
fs = require('fs'),
mkdirp = require('mkdirp'),
path = require('path'), path = require('path'),
mkdirp = require('mkdirp'); sass = require('./');
/** /**
* Render * Render
......
/*!
* node-sass: scripts/build.js
*/
var eol = require('os').EOL, var eol = require('os').EOL,
fs = require('fs'), fs = require('fs'),
mkdir = require('mkdirp'), mkdir = require('mkdirp'),
...@@ -14,11 +18,10 @@ require('../lib/extensions'); ...@@ -14,11 +18,10 @@ require('../lib/extensions');
*/ */
function afterBuild(options) { function afterBuild(options) {
var folder = options.debug ? 'Debug' : 'Release'; var install = process.sass.binaryPath;
var target = path.join(__dirname, '..', 'build', folder, 'binding.node'); var target = path.join(__dirname, '..', 'build', options.debug ? 'Debug' : 'Release', 'binding.node');
var install = path.join(__dirname, '..', 'vendor', process.sassBinaryName, 'binding.node');
mkdir(path.join(__dirname, '..', 'vendor', process.sassBinaryName), function(err) { mkdir(path.dirname(install), function(err) {
if (err && err.code !== 'EEXIST') { if (err && err.code !== 'EEXIST') {
console.error(err.message); console.error(err.message);
return; return;
...@@ -36,7 +39,7 @@ function afterBuild(options) { ...@@ -36,7 +39,7 @@ function afterBuild(options) {
return; return;
} }
console.log('Installed in `' + install + '`'); console.log('Installed in `', install, '`');
}); });
}); });
}); });
...@@ -52,9 +55,9 @@ function afterBuild(options) { ...@@ -52,9 +55,9 @@ function afterBuild(options) {
function build(options) { function build(options) {
var arguments = [path.join('node_modules', 'pangyp', 'bin', 'node-gyp'), 'rebuild'].concat(options.args); 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] stdio: [0, 1, 2]
}); });
...@@ -110,12 +113,13 @@ function testBinary(options) { ...@@ -110,12 +113,13 @@ function testBinary(options) {
return build(options); return build(options);
} }
fs.stat(path.join(__dirname, '..', 'vendor', process.sassBinaryName, 'binding.node'), function(err) { try {
if (err) { process.sass.getBinaryPath(true);
} catch (e) {
return build(options); return build(options);
} }
console.log('`' + process.sassBinaryName + '` exists; testing.'); console.log('`', process.sass.binaryPath, '` exists.', eol, 'testing binary.');
try { try {
require('../').renderSync({ require('../').renderSync({
...@@ -128,7 +132,6 @@ function testBinary(options) { ...@@ -128,7 +132,6 @@ function testBinary(options) {
return build(options); return build(options);
} }
});
} }
/** /**
......
var path = require('path'), /*!
spawn = require('child_process').spawn, * node-sass: scripts/coverage.js
bin = path.join.bind(null, __dirname, '..', 'node_modules', '.bin'); */
require('../lib/extensions');
var bin = require('path').join.bind(null, __dirname, '..', 'node_modules', '.bin'),
spawn = require('child_process').spawn;
/** /**
* Run test suite * Run test suite
...@@ -14,7 +19,7 @@ function suite() { ...@@ -14,7 +19,7 @@ function suite() {
var coveralls = spawn(bin('coveralls')); var coveralls = spawn(bin('coveralls'));
var args = [bin('_mocha')].concat(['--reporter', 'mocha-lcov-reporter']); var args = [bin('_mocha')].concat(['--reporter', 'mocha-lcov-reporter']);
var mocha = spawn(process.execPath, args, { var mocha = spawn(process.sass.runtime.execPath, args, {
env: process.env env: process.env
}); });
......
/*!
* node-sass: scripts/install.js
*/
var fs = require('fs'), var fs = require('fs'),
path = require('path'), mkdir = require('mkdirp'),
request = require('request'),
mkdirp = require('mkdirp'),
npmconf = require('npmconf'), npmconf = require('npmconf'),
packageInfo = require('../package.json'); path = require('path'),
request = require('request');
require('../lib/extensions'); require('../lib/extensions');
...@@ -24,7 +27,7 @@ function download(url, dest, cb) { ...@@ -24,7 +27,7 @@ function download(url, dest, cb) {
request.get(url, options).on('response', function(response) { request.get(url, options).on('response', function(response) {
if (response.statusCode < 200 || response.statusCode >= 300) { if (response.statusCode < 200 || response.statusCode >= 300) {
returnError('Can not download file from ' + url); returnError(['Can not download file from:', url].join());
return; return;
} }
...@@ -64,49 +67,31 @@ function applyProxy(options, cb) { ...@@ -64,49 +67,31 @@ function applyProxy(options, cb) {
} }
/** /**
* Check if binaries exists * Check and download binary
* *
* @api private * @api private
*/ */
function checkAndFetchBinaries() { function checkAndDownloadBinary() {
fs.exists(path.join(__dirname, '..', 'vendor', process.sassBinaryName), function (exists) { try {
if (exists) { process.sass.getBinaryPath(true);
} catch (e) {
return; return;
} }
fetch(); mkdirp(path.dirname(process.sass.binaryPath), function(err) {
});
}
/**
* Fetch binaries
*
* @api private
*/
function fetch() {
var url = [
'https://raw.githubusercontent.com/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');
mkdirp(dir, function(err) {
if (err) { if (err) {
console.error(err); console.error(err);
return; return;
} }
download(url, dest, function(err) { download(process.sass.binaryUrl, process.sass.binaryPath, function(err) {
if (err) { if (err) {
console.error(err); console.error(err);
return; return;
} }
console.log('Binary downloaded and installed at ' + dest); console.log('Binary downloaded and installed at', process.sass.binaryPath);
}); });
}); });
} }
...@@ -121,7 +106,7 @@ if (process.env.SKIP_SASS_BINARY_DOWNLOAD_FOR_CI) { ...@@ -121,7 +106,7 @@ if (process.env.SKIP_SASS_BINARY_DOWNLOAD_FOR_CI) {
} }
/** /**
* Run * If binary does not exsit, download it
*/ */
checkAndFetchBinaries(); checkAndDownloadBinary();
/*! /*!
* node-sass: scripts/upload.js * node-sass: scripts/upload.js
*/ */
require('../lib/extensions'); require('../lib/extensions');
var flags = require('meow')({ pkg: '../' }).flags; var flags = require('meow')({ pkg: '../' }).flags;
var eol = require('os').EOL,
var fetchReleaseInfoUrl = ['https://api.github.com/repos/sass/node-sass/releases/tags/v', fetchReleaseInfoUrl = ['https://api.github.com/repos/sass/node-sass/releases/tags/v',
flags.tag ? flags.tag : require('../package.json').version].join(''), flags.tag ? flags.tag : require('../package.json').version].join(''),
file = flags.path ? file = flags.path ? flags.path : process.sass.binaryPath,
flags.path :
require('path').resolve(__dirname, '..', 'vendor', process.sassBinaryName, 'binding.node'),
fs = require('fs'), fs = require('fs'),
os = require('os'),
request = require('request'), request = require('request'),
uploadReleaseAssetUrl = ['?name=', process.sassBinaryName, '.node', '&label=', process.sassBinaryName].join(''); uploadReleaseAssetUrl = ['?name=', process.sass.binaryName].join('');
/** /**
* Upload binary using GitHub API * Upload binary using GitHub API
...@@ -45,11 +43,13 @@ function uploadBinary() { ...@@ -45,11 +43,13 @@ function uploadBinary() {
if (formattedResponse.errors) { if (formattedResponse.errors) {
throwFormattedError(formattedResponse.errors); throwFormattedError(formattedResponse.errors);
} else if (res.statusCode > 399) {
throwFormattedError(formattedResponse);
} }
console.log(['Binary uploaded successfully.', console.log(['Binary uploaded successfully.',
'Please test the following link before announcement it:', 'Please test the following link before announcing it:',
formattedResponse.browser_download_url].join(os.EOL)); formattedResponse.browser_download_url].join(eol));
}); });
}; };
...@@ -75,7 +75,7 @@ function uploadBinary() { ...@@ -75,7 +75,7 @@ function uploadBinary() {
function throwFormattedError(err) { function throwFormattedError(err) {
throw new Error([ throw new Error([
'Error uploading release asset.', 'Error uploading release asset.',
'The server returned:', JSON.stringify(err)].join(os.EOL)); 'The server returned:', JSON.stringify(err)].join(eol));
} }
/** /**
......
...@@ -24,7 +24,7 @@ void prepare_import_results(Local<Value> returned_value, sass_context_wrapper* c ...@@ -24,7 +24,7 @@ void prepare_import_results(Local<Value> returned_value, sass_context_wrapper* c
ctx_w->imports = sass_make_import_list(array->Length()); ctx_w->imports = sass_make_import_list(array->Length());
for (size_t i = 0; i < array->Length(); ++i) { for (size_t i = 0; i < array->Length(); ++i) {
Local<Value> value = array->Get(i); Local<Value> value = array->Get(static_cast<uint32_t>(i));
if (!value->IsObject()) if (!value->IsObject())
continue; continue;
...@@ -186,12 +186,12 @@ int get_result(sass_context_wrapper* ctx_w, Sass_Context* ctx, bool is_sync = fa ...@@ -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* css = sass_context_get_output_string(ctx);
const char* map = sass_context_get_source_map_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<uint32_t>(strlen(css))));
get_stats(ctx_w, ctx); get_stats(ctx_w, ctx);
if (map) { if (map) {
NanNew(ctx_w->result)->Set(NanNew("map"), NanNewBufferHandle(map, strlen(map))); NanNew(ctx_w->result)->Set(NanNew("map"), NanNewBufferHandle(map, static_cast<uint32_t>(strlen(map))));
} }
} }
else if (is_sync) { else if (is_sync) {
......
...@@ -104,20 +104,16 @@ describe('api', function() { ...@@ -104,20 +104,16 @@ describe('api', function() {
}); });
it('should throw error when libsass binary is missing.', function(done) { 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(''); renamedBin = [originalBin, '_moved'].join('');
assert.throws(function() { assert.throws(function() {
// un-require node-sass
var resolved = require.resolve('../lib');
delete require.cache[resolved];
fs.renameSync(originalBin, renamedBin); fs.renameSync(originalBin, renamedBin);
// try to re-require it process.sass.getBinaryPath(true);
require('../lib');
}, function(err) { }, function(err) {
if ((err instanceof Error) && /`libsass` bindings not found. Try reinstalling `node-sass`?/.test(err)) {
fs.renameSync(renamedBin, originalBin); fs.renameSync(renamedBin, originalBin);
if ((err instanceof Error) && /`libsass` bindings not found. Try reinstalling `node-sass`?/.test(err)) {
done(); done();
return true; return true;
} }
......
...@@ -201,8 +201,8 @@ describe('cli', function() { ...@@ -201,8 +201,8 @@ describe('cli', function() {
bin.on('close', function() { bin.on('close', function() {
assert.equal(read(destCss, 'utf8').trim(), expectedCss); assert.equal(read(destCss, 'utf8').trim(), expectedCss);
assert.equal(read(destMap, 'utf8').trim(), expectedMap); assert.equal(read(destMap, 'utf8').trim(), expectedMap);
fs.unlinkSync(destMap);
fs.unlinkSync(destCss); fs.unlinkSync(destCss);
fs.unlinkSync(destMap);
done(); done();
}); });
}); });
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment