diff --git a/lib/grunt/file.js b/lib/grunt/file.js index f8a694e5a..0a179103d 100644 --- a/lib/grunt/file.js +++ b/lib/grunt/file.js @@ -38,7 +38,8 @@ file.setBase = function() { // Process specified wildcard glob patterns or filenames against a // callback, excluding and uniquing files in the result set. -var processPatterns = function(patterns, fn) { +var processPatterns = function(patterns, fn, exclusionFn) { + if (typeof exclusionFn === 'undefined') { exclusionFn = fn; } // Filepaths to return. var result = []; // Iterate over flattened patterns array. @@ -48,7 +49,7 @@ var processPatterns = function(patterns, fn) { // If the pattern is an exclusion, remove the ! if (exclusion) { pattern = pattern.slice(1); } // Find all matching files for this pattern. - var matches = fn(pattern); + var matches = (exclusion ? exclusionFn : fn)(pattern, result); if (exclusion) { // If an exclusion, remove matching files. result = grunt.util._.difference(result, matches); @@ -93,6 +94,8 @@ file.expand = function() { // If the first argument is an options object, save those options to pass // into the file.glob.sync method. var options = grunt.util.kindOf(args[0]) === 'object' ? args.shift() : {}; + // Cache fs calls across multiple file.glob.sync operations + var globOptions = grunt.util._.extend(file._createGlobIoCache(), options); // Use the first argument if it's an Array, otherwise convert the arguments // object to an array and use that. var patterns = Array.isArray(args[0]) ? args[0] : args; @@ -101,7 +104,9 @@ file.expand = function() { // Return all matching filepaths. var matches = processPatterns(patterns, function(pattern) { // Find all matching files for this pattern. - return file.glob.sync(pattern, options); + return file.glob.sync(pattern, globOptions); + }, function(pattern, resultsThusFar) { + return file.match(options, [pattern], resultsThusFar); }); // Filter result set? if (options.filter) { @@ -452,3 +457,14 @@ file.isPathInCwd = function() { return false; } }; + +// Creates all glob options that store cached fs results for the `glob` library. +// Can be removed when this glob PR is released: https://github.com/isaacs/node-glob/pull/306 +file._createGlobIoCache = function() { + return { + cache: Object.create(null), + statCache: Object.create(null), + symlinks: Object.create(null), + realpathCache: Object.create(null) + }; +}; diff --git a/lib/grunt/task.js b/lib/grunt/task.js index 48aec3abf..4742b3508 100644 --- a/lib/grunt/task.js +++ b/lib/grunt/task.js @@ -117,6 +117,7 @@ task.normalizeMultiTaskFiles = function(data, target) { } // Process all normalized file objects. + var globIoCache = grunt.file._createGlobIoCache(); files = grunt.util._(files).chain().forEach(function(obj) { if (!('src' in obj) || !obj.src) { return; } // Normalize .src properties to flattened array. @@ -127,7 +128,7 @@ task.normalizeMultiTaskFiles = function(data, target) { } }).map(function(obj) { // Build options object, removing unwanted properties. - var expandOptions = grunt.util._.extend({}, obj); + var expandOptions = grunt.util._.extend({}, globIoCache, obj); delete expandOptions.src; delete expandOptions.dest;