diff --git a/bin/grunt-lodashbuilder b/bin/grunt-lodashbuilder deleted file mode 100755 index 32baee0..0000000 --- a/bin/grunt-lodashbuilder +++ /dev/null @@ -1,2 +0,0 @@ -#!/usr/bin/env node -require('grunt').npmTasks('grunt-lodashbuilder').cli(); diff --git a/bin/post-install.js b/bin/post-install.js new file mode 100644 index 0000000..2da445c --- /dev/null +++ b/bin/post-install.js @@ -0,0 +1,140 @@ +#!/usr/bin/env node + +// Post install script is totally stolen from lodash itself +// with slight modifications to install closure compiler & uglify, +// cause we need them for the buildprocess & lodash only installs them +// when installed gloablly via npm. We´re going to install them anyways + +;(function() { + 'use strict'; + + /** Load Node modules */ + var exec = require('child_process').exec, + fs = require('fs'), + https = require('https'), + path = require('path'), + tar = require(require.resolve('lodash').replace('lodash.js', '') + 'vendor/tar/tar.js'), + zlib = require('zlib'); + + /** The path of the directory that is the base of the repository */ + var basePath = fs.realpathSync(path.join(__dirname, '..', 'node_modules', 'lodash')); + + /** The path of the `vendor` directory */ + var vendorPath = path.join(basePath, 'vendor'); + + /** The Git object ID of `closure-compiler.tar.gz` */ + var closureId = 'a2787b470c577cee2404d186c562dd9835f779f5'; + + /** The Git object ID of `uglifyjs.tar.gz` */ + var uglifyId = '3390b259e04829538e4d3635d12b317dd6103eca'; + + /** The media type for raw blob data */ + var mediaType = 'application/vnd.github.v3.raw'; + + /** Used to reference parts of the blob href */ + var location = (function() { + var host = 'api.github.com', + origin = 'https://api.github.com', + pathname = '/repos/bestiejs/lodash/git/blobs'; + + return { + 'host': host, + 'href': host + origin + pathname, + 'origin': origin, + 'pathname': pathname + }; + }()); + + /*--------------------------------------------------------------------------*/ + + /** + * Fetches a required `.tar.gz` dependency with the given Git object ID from + * the Lo-Dash repo on GitHub. The object ID may be obtained by running + * `git hash-object path/to/dependency.tar.gz`. + * + * @private + * @param {Object} options The options object. + * id - The Git object ID of the `.tar.gz` file. + * onComplete - The function, invoked with one argument (exception), + * called once the extraction has finished. + * path - The path of the extraction directory. + * title - The dependency's title used in status updates logged to the console. + */ + function getDependency(options) { + options || (options = {}); + + var id = options.id, + onComplete = options.onComplete, + path = options.path, + title = options.title; + + function callback(exception) { + if (exception) { + console.error([ + 'There was a problem installing ' + title + '. To manually install, run:', + '', + "curl -H 'Accept: " + mediaType + "' " + location.href + '/' + id + " | tar xvz -C '" + path + "'" + ].join('\n')); + } + onComplete(exception); + } + + console.log('Downloading ' + title + '...'); + + https.get({ + 'host': location.host, + 'path': location.pathname + '/' + id, + 'headers': { + // By default, all GitHub blob API endpoints return a JSON document + // containing Base64-encoded blob data. Overriding the `Accept` header + // with the GitHub raw media type returns the blob data directly. + // See http://developer.github.com/v3/media/. + 'Accept': mediaType + } + }, function(response) { + var decompressor = zlib.createUnzip(), + parser = new tar.Extract({ 'path': path }); + + decompressor.on('error', callback) + parser.on('end', callback).on('error', callback); + response.pipe(decompressor).pipe(parser); + }) + .on('error', callback); + } + + /*--------------------------------------------------------------------------*/ + + exec('npm -g root', function(exception, stdout) { + if (exception) { + console.error([ + 'Oops! There was a problem detecting the install mode. If you’re installing the', + 'Lo-Dash command-line executable (via `npm install -g lodash`), you’ll need to', + 'manually install UglifyJS and the Closure Compiler by running:', + '', + "curl -H 'Accept: " + mediaType + "' " + location.href + '/' + closureId + " | tar xvz -C '" + vendorPath + "'", + "curl -H 'Accept: " + mediaType + "' " + location.href + '/' + uglifyId + " | tar xvz -C '" + vendorPath + "'", + '', + 'Please submit an issue on the GitHub issue tracker: ' + process.env.npm_package_bugs_url + ].join('\n')); + + console.error(exception); + } + // download the Closure Compiler + getDependency({ + 'title': 'the Closure Compiler', + 'id': closureId, + 'path': vendorPath, + 'onComplete': function() { + // download UglifyJS + getDependency({ + 'title': 'UglifyJS', + 'id': uglifyId, + 'path': vendorPath, + 'onComplete': function() { + process.exit(); + } + }); + } + }); + }); +}()); diff --git a/lib/builder.js b/lib/builder.js index c16257e..d6d20a1 100644 --- a/lib/builder.js +++ b/lib/builder.js @@ -1,5 +1,3 @@ -/*global exports:true, require:true */ - /* * grunt-lodashbuilder * https://github.com/asciidisco/grunt-lodashbuilder @@ -13,6 +11,7 @@ // External libs. var _ = require('lodash'); + var semver = require('semver'); exports.init = function(grunt) { var exports = {}; @@ -24,73 +23,62 @@ // spawns the lodash build process exports.build = function (options, contentCb) { var lodashPath = require.resolve('lodash'); - var lodashVersion = 'latest'; + var lodashBuilder = require(lodashPath.replace('lodash.js', 'build.js')); + var lodashTarget = _; // check if we should use a different lodash version if (options.config.src) { try { grunt.file.read(options.config.src + '/build.js'); lodashPath = options.config.src + '/lodash.js'; + lodashTarget = require(options.config.src + '/lodash.js'); } catch (e) { contentCb(new Transport('error', 'Could not load given lodash version at "' + options.config.src + '"'), options); return null; } } - var mappedConfig = [lodashPath.replace('lodash.js', 'build.js'), '--stdout']; - + var mappedConfig = ['--stdout']; // load lodash version - grunt.utils.spawn({ - cmd: 'node', - args: [lodashPath.replace('lodash.js', 'build.js'), '--version'] - }, function (error, result, code) { - var version = parseFloat(result.stdout); - - // check lodash version - if (version >= 0.7) { - - // check for debug or minified output - if (options.debug === true && version > 0.7) { - mappedConfig.push('--debug'); - } + var version = lodashTarget.VERSION; + // check lodash version + if (semver.gte(version, '0.7.0')) { + // check for debug or minified output + if ((options.debug === true || options.minify === true) && semver.gte(version, '0.7.0')) { + mappedConfig.push('--debug'); + } - // parse arguments - var args = exports.parseArgs(options.config, mappedConfig); - - // launch lodash builder - grunt.utils.spawn({ - cmd: 'node', - args: args - }, function (error, result, code) { - var output = result.stdout; - var outputSize = output.length; - - // catch lodash errors - if (output.search("Invalid argument passed:") === 1) { - contentCb(new Transport('error', result.stdout), options); - return null; - } - - // catch 'no output' failure - if (outputSize === 0) { - contentCb(new Transport('error', 'No output'), options); - return null; - } - - // catch lodash result - if (outputSize > 0) { - contentCb(new Transport('content', output), options); - } else { - // catch unexpected error - contentCb(new Transport('error', 'Unknown'), options); - } + // parse arguments + var args = exports.parseArgs(options.config, mappedConfig); + // launch lodash builder + lodashBuilder(args, function (output) { + var outputSize = output.length; + // catch lodash errors + if (output.search("Invalid argument passed:") === 1) { + contentCb(new Transport('error', result.stdout), options); return null; - }); - } else { - contentCb(new Transport('error', 'Given lodash version (' + version + ') is too old, must 0.7 or higher'), options); - } - }); + } + + // catch 'no output' failure + if (outputSize === 0) { + contentCb(new Transport('error', 'No output'), options); + return null; + } + + // catch lodash result + if (outputSize > 0) { + contentCb(new Transport('content', output), options); + } else { + // catch unexpected error + contentCb(new Transport('error', 'Unknown'), options); + } + + return null; + }); + } else { + contentCb(new Transport('error', 'Given lodash version (' + version + ') is too old, must 0.7 or higher'), options); + } }; // spawns the lodash build process diff --git a/package.json b/package.json index 7360f25..80f71c0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "grunt-lodashbuilder", "description": "Build your Lo-Dash experience with grunt", - "version": "0.1.2", + "version": "0.1.3", "homepage": "https://github.com/asciidisco/grunt-lodashbuilder", "author": { "name": "asciidisco", @@ -21,20 +21,19 @@ } ], "main": "grunt.js", - "bin": { - "grunt-lodashbuilder": "bin/grunt-lodashbuilder" - }, "engines": { "node": ">=0.8.0" }, "scripts": { + "postinstall": "node ./bin/post-install.js", "test": "grunt travis --verbose" }, "dependencies": { "grunt": ">=0.3.x", - "lodash": "0.9.x" + "lodash": "latest", + "semver": "1.1.x" }, "keywords": [ - "gruntplugin" + "gruntplugin", "lodash", "underscore", "custom", "builder" ] } diff --git a/tasks/lodashbuilder.js b/tasks/lodashbuilder.js index 187dc60..924d218 100644 --- a/tasks/lodashbuilder.js +++ b/tasks/lodashbuilder.js @@ -40,7 +40,8 @@ module.exports = function (grunt) { builder.build({ config: config, done: done, - debug: !!config.debug + debug: !!config.debug, + minify: !!config.minify }, fileWriter); return done;