From 4d5f6b6fd457a2c3647c67ad9194f7a13c254a8b Mon Sep 17 00:00:00 2001 From: Jackson Ray Hamilton Date: Sun, 28 Sep 2014 10:08:41 -0700 Subject: [PATCH 1/3] Have `nonull: true` cause the task to fail. --- Gruntfile.js | 30 ++++++++++++++--- README.md | 6 ++-- docs/concat-examples.md | 4 ++- tasks/concat.js | 5 +-- test/concat_test.js | 32 ++++++++++++++++--- ...lid_files => handling_invalid_files_force} | 0 6 files changed, 62 insertions(+), 15 deletions(-) rename test/expected/{handling_invalid_files => handling_invalid_files_force} (100%) diff --git a/Gruntfile.js b/Gruntfile.js index 08cff05..62517fd 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -48,11 +48,6 @@ module.exports = function(grunt) { 'tmp/custom_options': ['test/fixtures/file1', 'test/fixtures/file2'] } }, - handling_invalid_files: { - src: ['test/fixtures/file1', 'invalid_file/should_warn/but_not_fail', 'test/fixtures/file2'], - dest: 'tmp/handling_invalid_files', - nonull: true - }, process_function: { options: { process: function(src, filepath) { @@ -160,6 +155,31 @@ module.exports = function(grunt) { }); + // Encapsulates tasks which invoke `grunt.fail.warn` and should abort. + grunt.registerTask('concat-warn', function() { + grunt.config('concat', { + handling_invalid_files: { + src: ['test/fixtures/file1', 'invalid_file/should_warn/and_abort', 'test/fixtures/file2'], + dest: 'tmp/handling_invalid_files', + nonull: true + } + }); + grunt.task.run(['concat']); + }); + + // Encapsulates tasks which invoke `grunt.fail.warn` and should abort, but the + // test is checking behavior in the case of a user-specified `--force` flag. + grunt.registerTask('concat-force', function() { + grunt.config('concat', { + handling_invalid_files_force: { + src: ['test/fixtures/file1', 'invalid_file/should_warn/but_not_fail', 'test/fixtures/file2'], + dest: 'tmp/handling_invalid_files_force', + nonull: true + } + }); + grunt.task.run(['concat']); + }); + // Actually load this plugin's task(s). grunt.loadTasks('tasks'); diff --git a/README.md b/README.md index 7acf9c7..717c239 100644 --- a/README.md +++ b/README.md @@ -235,7 +235,7 @@ grunt.initConfig({ ``` #### Invalid or Missing Files Warning -If you would like the `concat` task to warn if a given file is missing or invalid be sure to set `nonull` to `true`: +If you would like the `concat` task to warn and abort if a given file is missing or invalid be sure to set `nonull` to `true`: ```js grunt.initConfig({ @@ -249,6 +249,8 @@ grunt.initConfig({ }); ``` +Additionally invoke grunt with `--force` to skip over missing files. + See [configuring files for a task](http://gruntjs.com/configuring-tasks#files) for how to configure file globbing in Grunt. @@ -298,4 +300,4 @@ grunt.initConfig({ Task submitted by ["Cowboy" Ben Alman](http://benalman.com/) -*This file was generated on Wed Apr 20 2016 08:41:44.* +*This file was generated on Sun Jun 05 2016 08:36:20.* diff --git a/docs/concat-examples.md b/docs/concat-examples.md index f0c87f9..75fc448 100644 --- a/docs/concat-examples.md +++ b/docs/concat-examples.md @@ -136,7 +136,7 @@ grunt.initConfig({ ``` ## Invalid or Missing Files Warning -If you would like the `concat` task to warn if a given file is missing or invalid be sure to set `nonull` to `true`: +If you would like the `concat` task to warn and abort if a given file is missing or invalid be sure to set `nonull` to `true`: ```js grunt.initConfig({ @@ -150,6 +150,8 @@ grunt.initConfig({ }); ``` +Additionally invoke grunt with `--force` to skip over missing files. + See [configuring files for a task](http://gruntjs.com/configuring-tasks#files) for how to configure file globbing in Grunt. diff --git a/tasks/concat.js b/tasks/concat.js index 81fd862..78f7fe1 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -71,9 +71,10 @@ module.exports = function(grunt) { // Concat banner + specified files + footer. var src = banner + f.src.filter(function(filepath) { - // Warn on and remove invalid source files (if nonull was set). + // Warn on invalid source files (if nonull was set). They will be + // removed if --force is specified. if (!grunt.file.exists(filepath)) { - grunt.log.warn('Source file "' + filepath + '" not found.'); + grunt.fail.warn('Source file "' + filepath + '" not found.'); return false; } return true; diff --git a/test/concat_test.js b/test/concat_test.js index 3de58d6..c6cb32c 100644 --- a/test/concat_test.js +++ b/test/concat_test.js @@ -2,6 +2,11 @@ var grunt = require('grunt'); var comment = require('../tasks/lib/comment').init(grunt); +var exec = require('child_process').exec; +var path = require('path'); +var fs = require('fs'); + +var execOptions = {cwd: path.join(__dirname, '..')}; function getNormalizedFile(filepath) { return grunt.util.normalizelf(grunt.file.read(filepath)); @@ -27,13 +32,30 @@ exports.concat = { test.done(); }, handling_invalid_files: function(test) { - test.expect(1); + test.expect(3); - var actual = getNormalizedFile('tmp/handling_invalid_files'); - var expected = getNormalizedFile('test/expected/handling_invalid_files'); - test.equal(actual, expected, 'will have warned, but should not fail.'); + exec('grunt concat-warn', execOptions, function(error, stdout) { + test.ok(stdout.indexOf('Warning:') > -1, 'should print a warning.'); + test.ok(stdout.indexOf('Aborted due to warnings.') > -1, 'should abort.'); - test.done(); + fs.exists('tmp/handling_invalid_files', function(exists) { + test.ok(!exists, 'should not have created a file.'); + test.done(); + }); + }); + }, + handling_invalid_files_force: function(test) { + test.expect(2); + + exec('grunt concat-force --force', execOptions, function(error, stdout) { + test.ok(stdout.indexOf('Warning:') > -1, 'should print a warning.'); + + var actual = getNormalizedFile('tmp/handling_invalid_files_force'); + var expected = getNormalizedFile('test/expected/handling_invalid_files_force'); + test.equal(actual, expected, 'should not fail.'); + + test.done(); + }); }, strip_banner: function(test) { test.expect(10); diff --git a/test/expected/handling_invalid_files b/test/expected/handling_invalid_files_force similarity index 100% rename from test/expected/handling_invalid_files rename to test/expected/handling_invalid_files_force From 542a3d11ccd9482f22d601702affd4081f6ceef6 Mon Sep 17 00:00:00 2001 From: Jackson Ray Hamilton Date: Sun, 5 Jun 2016 12:42:56 -0700 Subject: [PATCH 2/3] Work around process exiting workaround on Node.js 0.10 on Windows. --- tasks/concat.js | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/tasks/concat.js b/tasks/concat.js index 78f7fe1..bd81409 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -60,6 +60,24 @@ module.exports = function(grunt) { sourceMap = false; } + // grunt.fail.warn uses the "exit" library, which doesn't stop the process + // synchronously on Node.js 0.10 on Windows, which could result in files + // still being concatenated even when some are missing. See: + // https://github.com/nodejs/node-v0.x-archive/issues/3584#issuecomment-8034529 + var exitEarly = false; + this.files.forEach(function(f) { + f.src.forEach(function(filepath) { + // Warn on invalid source files (if nonull was set). + if (!grunt.file.exists(filepath)) { + grunt.fail.warn('Source file "' + filepath + '" not found.'); + exitEarly = true; + } + }); + }); + if (!grunt.option('force') && exitEarly) { + return; + } + // Iterate over all src-dest file pairs. this.files.forEach(function(f) { // Initialize source map objects. @@ -71,13 +89,8 @@ module.exports = function(grunt) { // Concat banner + specified files + footer. var src = banner + f.src.filter(function(filepath) { - // Warn on invalid source files (if nonull was set). They will be - // removed if --force is specified. - if (!grunt.file.exists(filepath)) { - grunt.fail.warn('Source file "' + filepath + '" not found.'); - return false; - } - return true; + // Invalid source files will be removed if --force is specified. + return grunt.file.exists(filepath); }).map(function(filepath, i) { if (grunt.file.isDir(filepath)) { return; From acbdc154822d1bdcae9ecc4d67df76c144d3036b Mon Sep 17 00:00:00 2001 From: Jackson Ray Hamilton Date: Sun, 5 Jun 2016 13:35:09 -0700 Subject: [PATCH 3/3] Use throw to emulate exiting more faithfully. --- tasks/concat.js | 130 +++++++++++++++++++++++++----------------------- 1 file changed, 67 insertions(+), 63 deletions(-) diff --git a/tasks/concat.js b/tasks/concat.js index bd81409..af51d30 100644 --- a/tasks/concat.js +++ b/tasks/concat.js @@ -60,76 +60,80 @@ module.exports = function(grunt) { sourceMap = false; } - // grunt.fail.warn uses the "exit" library, which doesn't stop the process - // synchronously on Node.js 0.10 on Windows, which could result in files - // still being concatenated even when some are missing. See: - // https://github.com/nodejs/node-v0.x-archive/issues/3584#issuecomment-8034529 - var exitEarly = false; - this.files.forEach(function(f) { - f.src.forEach(function(filepath) { - // Warn on invalid source files (if nonull was set). - if (!grunt.file.exists(filepath)) { - grunt.fail.warn('Source file "' + filepath + '" not found.'); - exitEarly = true; + var exitEarly = {}; + try { + // Iterate over all src-dest file pairs. + this.files.forEach(function(f) { + // Initialize source map objects. + var sourceMapHelper; + if (sourceMap) { + sourceMapHelper = sourcemap.helper(f, options); + sourceMapHelper.add(banner); } - }); - }); - if (!grunt.option('force') && exitEarly) { - return; - } - // Iterate over all src-dest file pairs. - this.files.forEach(function(f) { - // Initialize source map objects. - var sourceMapHelper; - if (sourceMap) { - sourceMapHelper = sourcemap.helper(f, options); - sourceMapHelper.add(banner); - } + // Concat banner + specified files + footer. + var src = banner + f.src.filter(function(filepath) { + // Warn on invalid source files (if nonull was set). They will be + // removed if --force is specified. + if (!grunt.file.exists(filepath)) { + grunt.fail.warn('Source file "' + filepath + '" not found.'); + if (!grunt.option('force')) { + // See the catch clause below for why we do this. + throw exitEarly; + } + return false; + } + return true; + }).map(function(filepath, i) { + if (grunt.file.isDir(filepath)) { + return; + } + // Read file source. + var src = grunt.file.read(filepath); + // Process files as templates if requested. + if (typeof options.process === 'function') { + src = options.process(src, filepath); + } else if (options.process) { + src = grunt.template.process(src, options.process); + } + // Strip banners if requested. + if (options.stripBanners) { + src = comment.stripBanner(src, options.stripBanners); + } + // Add the lines of this file to our map. + if (sourceMapHelper) { + src = sourceMapHelper.addlines(src, filepath); + if (i < f.src.length - 1) { + sourceMapHelper.add(options.separator); + } + } + return src; + }).join(options.separator) + footer; - // Concat banner + specified files + footer. - var src = banner + f.src.filter(function(filepath) { - // Invalid source files will be removed if --force is specified. - return grunt.file.exists(filepath); - }).map(function(filepath, i) { - if (grunt.file.isDir(filepath)) { - return; - } - // Read file source. - var src = grunt.file.read(filepath); - // Process files as templates if requested. - if (typeof options.process === 'function') { - src = options.process(src, filepath); - } else if (options.process) { - src = grunt.template.process(src, options.process); - } - // Strip banners if requested. - if (options.stripBanners) { - src = comment.stripBanner(src, options.stripBanners); - } - // Add the lines of this file to our map. if (sourceMapHelper) { - src = sourceMapHelper.addlines(src, filepath); - if (i < f.src.length - 1) { - sourceMapHelper.add(options.separator); - } + sourceMapHelper.add(footer); + sourceMapHelper.write(); + // Add sourceMappingURL to the end. + src += sourceMapHelper.url(); } - return src; - }).join(options.separator) + footer; - - if (sourceMapHelper) { - sourceMapHelper.add(footer); - sourceMapHelper.write(); - // Add sourceMappingURL to the end. - src += sourceMapHelper.url(); - } - // Write the destination file. - grunt.file.write(f.dest, src); + // Write the destination file. + grunt.file.write(f.dest, src); - // Print a success message. - grunt.verbose.write('File ' + chalk.cyan(f.dest) + ' created.'); - }); + // Print a success message. + grunt.verbose.write('File ' + chalk.cyan(f.dest) + ' created.'); + }); + } catch (reason) { + if (reason === exitEarly) { + // grunt.fail.warn uses the "exit" library, which doesn't stop the + // process synchronously on Node.js 0.10 on Windows, which could result + // in files still being concatenated even when some are missing. See: + // https://github.com/nodejs/node-v0.x-archive/issues/3584#issuecomment-8034529 + // Therefore, we throw a unique reference to emulate exiting early. + return; + } + throw reason; + } }); };