| /** |
| * node-archiver |
| * |
| * Copyright (c) 2012-2014 Chris Talkington, contributors. |
| * Licensed under the MIT license. |
| * https://github.com/ctalkington/node-archiver/blob/master/LICENSE-MIT |
| */ |
| var fs = require('fs'); |
| var path = require('path'); |
| |
| var _ = require('lodash'); |
| var glob = require('glob'); |
| |
| var file = module.exports = {}; |
| |
| var pathSeparatorRe = /[\/\\]/g; |
| |
| // Process specified wildcard glob patterns or filenames against a |
| // callback, excluding and uniquing files in the result set. |
| var processPatterns = function(patterns, fn) { |
| // Filepaths to return. |
| var result = []; |
| // Iterate over flattened patterns array. |
| _.flatten(patterns).forEach(function(pattern) { |
| // If the first character is ! it should be omitted |
| var exclusion = pattern.indexOf('!') === 0; |
| // 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); |
| if (exclusion) { |
| // If an exclusion, remove matching files. |
| result = _.difference(result, matches); |
| } else { |
| // Otherwise add matching files. |
| result = _.union(result, matches); |
| } |
| }); |
| return result; |
| }; |
| |
| // True if the file path exists. |
| file.exists = function() { |
| var filepath = path.join.apply(path, arguments); |
| return fs.existsSync(filepath); |
| }; |
| |
| // Return an array of all file paths that match the given wildcard patterns. |
| file.expand = function() { |
| var args = _.toArray(arguments); |
| // If the first argument is an options object, save those options to pass |
| // into the File.prototype.glob.sync method. |
| var options = _.isPlainObject(args[0]) ? args.shift() : {}; |
| // 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; |
| // Return empty set if there are no patterns or filepaths. |
| if (patterns.length === 0) { return []; } |
| // Return all matching filepaths. |
| var matches = processPatterns(patterns, function(pattern) { |
| // Find all matching files for this pattern. |
| return glob.sync(pattern, options); |
| }); |
| // Filter result set? |
| if (options.filter) { |
| matches = matches.filter(function(filepath) { |
| filepath = path.join(options.cwd || '', filepath); |
| try { |
| if (typeof options.filter === 'function') { |
| return options.filter(filepath); |
| } else { |
| // If the file is of the right type and exists, this should work. |
| return fs.statSync(filepath)[options.filter](); |
| } |
| } catch(e) { |
| // Otherwise, it's probably not the right type. |
| return false; |
| } |
| }); |
| } |
| return matches; |
| }; |
| |
| // Build a multi task "files" object dynamically. |
| file.expandMapping = function(patterns, destBase, options) { |
| options = _.defaults({}, options, { |
| rename: function(destBase, destPath) { |
| return path.join(destBase || '', destPath); |
| } |
| }); |
| var files = []; |
| var fileByDest = {}; |
| // Find all files matching pattern, using passed-in options. |
| file.expand(options, patterns).forEach(function(src) { |
| var destPath = src; |
| // Flatten? |
| if (options.flatten) { |
| destPath = path.basename(destPath); |
| } |
| // Change the extension? |
| if (options.ext) { |
| destPath = destPath.replace(/(\.[^\/]*)?$/, options.ext); |
| } |
| // Generate destination filename. |
| var dest = options.rename(destBase, destPath, options); |
| // Prepend cwd to src path if necessary. |
| if (options.cwd) { src = path.join(options.cwd, src); } |
| // Normalize filepaths to be unix-style. |
| dest = dest.replace(pathSeparatorRe, '/'); |
| src = src.replace(pathSeparatorRe, '/'); |
| // Map correct src path to dest path. |
| if (fileByDest[dest]) { |
| // If dest already exists, push this src onto that dest's src array. |
| fileByDest[dest].src.push(src); |
| } else { |
| // Otherwise create a new src-dest file mapping object. |
| files.push({ |
| src: [src], |
| dest: dest, |
| }); |
| // And store a reference for later use. |
| fileByDest[dest] = files[files.length - 1]; |
| } |
| }); |
| return files; |
| }; |
| |
| // reusing bits of grunt's multi-task source normalization |
| file.normalizeFilesArray = function(data) { |
| var files = []; |
| |
| data.forEach(function(obj) { |
| var prop; |
| if ('src' in obj || 'dest' in obj) { |
| files.push(obj); |
| } |
| }); |
| |
| if (files.length === 0) { |
| return []; |
| } |
| |
| files = _(files).chain().forEach(function(obj) { |
| if (!('src' in obj) || !obj.src) { return; } |
| // Normalize .src properties to flattened array. |
| if (Array.isArray(obj.src)) { |
| obj.src = _.flatten(obj.src); |
| } else { |
| obj.src = [obj.src]; |
| } |
| }).map(function(obj) { |
| // Build options object, removing unwanted properties. |
| var expandOptions = _.extend({}, obj); |
| delete expandOptions.src; |
| delete expandOptions.dest; |
| |
| // Expand file mappings. |
| if (obj.expand) { |
| return file.expandMapping(obj.src, obj.dest, expandOptions).map(function(mapObj) { |
| // Copy obj properties to result. |
| var result = _.extend({}, obj); |
| // Make a clone of the orig obj available. |
| result.orig = _.extend({}, obj); |
| // Set .src and .dest, processing both as templates. |
| result.src = mapObj.src; |
| result.dest = mapObj.dest; |
| // Remove unwanted properties. |
| ['expand', 'cwd', 'flatten', 'rename', 'ext'].forEach(function(prop) { |
| delete result[prop]; |
| }); |
| return result; |
| }); |
| } |
| |
| // Copy obj properties to result, adding an .orig property. |
| var result = _.extend({}, obj); |
| // Make a clone of the orig obj available. |
| result.orig = _.extend({}, obj); |
| |
| if ('src' in result) { |
| // Expose an expand-on-demand getter method as .src. |
| Object.defineProperty(result, 'src', { |
| enumerable: true, |
| get: function fn() { |
| var src; |
| if (!('result' in fn)) { |
| src = obj.src; |
| // If src is an array, flatten it. Otherwise, make it into an array. |
| src = Array.isArray(src) ? _.flatten(src) : [src]; |
| // Expand src files, memoizing result. |
| fn.result = file.expand(expandOptions, src); |
| } |
| return fn.result; |
| } |
| }); |
| } |
| |
| if ('dest' in result) { |
| result.dest = obj.dest; |
| } |
| |
| return result; |
| }).flatten().value(); |
| |
| return files; |
| }; |