diff --git a/build.js b/build.js index 3d51f8c72..62377b6ba 100755 --- a/build.js +++ b/build.js @@ -2,12 +2,15 @@ ;(function() { 'use strict'; - /** Load modules */ + /** Load Node.js modules */ var fs = require('fs'), path = require('path'), - vm = require('vm'), + vm = require('vm'); + + /** Load other modules */ + var _ = require(path.join(__dirname, 'lodash.js')), minify = require(path.join(__dirname, 'build', 'minify.js')), - _ = require(path.join(__dirname, 'lodash.js')); + mkdirpSync = require(path.join(__dirname, 'build', 'mkdirp-sync.js')); /** The current working directory */ var cwd = process.cwd(); @@ -1513,15 +1516,9 @@ var outputPath = options.reduce(function(result, value, index) { if (/-o|--output/.test(value)) { result = options[index + 1]; - var cwd = process.cwd(); - path.dirname(result).split(path.sep).forEach(function(pathSegment){ - try { - fs.mkdirSync(pathSegment); - } catch(err){} - process.chdir(pathSegment); - }); - process.chdir(cwd); - result = path.join(fs.realpathSync(path.dirname(result)), path.basename(result)); + var dirname = path.dirname(result); + mkdirpSync(dirname); + result = path.join(fs.realpathSync(dirname), path.basename(result)); } return result; }, ''); diff --git a/build/minify.js b/build/minify.js index 798e3a4d6..adb1c1ea1 100755 --- a/build/minify.js +++ b/build/minify.js @@ -2,18 +2,19 @@ ;(function() { 'use strict'; - /** Load modules */ + /** Load Node.js modules */ var fs = require('fs'), https = require('https'), path = require('path'), spawn = require('child_process').spawn, - zlib = require('zlib'), - tar = require('../vendor/tar/tar.js'), - _ = require('../lodash.js'); + zlib = require('zlib'); /** Load other modules */ - var preprocess = require('./pre-compile.js'), - postprocess = require('./post-compile.js'); + var _ = require('../lodash.js'), + mkdirpSync = require('./mkdirp-sync.js'), + preprocess = require('./pre-compile.js'), + postprocess = require('./post-compile.js'), + tar = require('../vendor/tar/tar.js'); /** The Git object ID of `closure-compiler.tar.gz` */ var closureId = '23cf67d0f0b979d97631fc108a2a43bb82225994'; @@ -141,7 +142,9 @@ outputPath = options.reduce(function(result, value, index) { if (/-o|--output/.test(value)) { result = options[index + 1]; - result = path.join(fs.realpathSync(path.dirname(result)), path.basename(result)); + var dirname = path.dirname(result); + mkdirpSync(dirname); + result = path.join(fs.realpathSync(dirname), path.basename(result)); } return result; }, outputPath); diff --git a/build/mkdirp-sync.js b/build/mkdirp-sync.js new file mode 100755 index 000000000..a40b0ea35 --- /dev/null +++ b/build/mkdirp-sync.js @@ -0,0 +1,41 @@ +#!/usr/bin/env node +;(function() { + 'use strict'; + + /** Load Node.js modules */ + var fs = require('fs'), + path = require('path'); + + /** + * Makes the given `path` directory, without throwing errors for existing + * directories and making parent directories as needed. + * + * @param {String} dirname The path of the directory. + * @param {Number|String} mode The permission mode. + */ + function mkdirpSync(dirname, mode) { + var separator = path.sep, + segments = dirname.split(separator), + type = typeof mode; + + if (!(type == 'number' || type == 'string')) { + mode = '0777'; + } + segments.reduce(function(currPath, segment, index) { + // skip leading separator of absolute paths + if (index === 0 && currPath === '') { + return separator; + } + segment = currPath + (currPath === separator ? segment : separator + segment); + try { + segment = fs.realpathSync(segment); + } catch(e) { + fs.mkdirSync(segment, mode); + } + return segment; + }); + } + + // expose + module.exports = mkdirpSync; +}()); diff --git a/test/test-build.js b/test/test-build.js index e68166126..17158e25e 100644 --- a/test/test-build.js +++ b/test/test-build.js @@ -1114,22 +1114,34 @@ QUnit.module('output options'); (function() { - var nestedDir = 'test/mkdir/'; + var nestedPath = path.join(__dirname, 'a', 'b'); + var commands = [ '-o a.js', - '--output a.js', - '-o ' + nestedDir + 'a.js' + '--output b.js', + '-o ./a/b/c.js' ]; - commands.forEach(function(command, index) { + commands.forEach(function(command) { asyncTest('`lodash ' + command +'`', function() { - var counter = -1, - start = _.after(2, _.once(QUnit.start)); + var counter = 0, + expected = /(\w+)(?=\.js$)/.exec(command)[0], + isDirs = _.contains(command, 'c.js'); + var start = _.after(2, _.once(function() { + if (isDirs) { + fs.rmdirSync(nestedPath); + } + QUnit.start(); + })); + + if (isDirs) { + command = command.replace('./a/b/c.js', path.join(nestedPath, 'c.js')); + } build(['-s'].concat(command.split(' ')), function(data) { - equal(path.basename(data.outputPath, '.js'), (++counter ? 'a.min' : 'a'), command); + var basename = path.basename(data.outputPath, '.js'); + equal(basename, expected + (counter++ ? '.min' : ''), command); start(); - fs.existsSync(nestedDir) && fs.rmdirSync(nestedDir); }); }); });