206 lines
6.5 KiB
JavaScript
206 lines
6.5 KiB
JavaScript
/**
|
|
* archiver-utils
|
|
*
|
|
* Copyright (c) 2012-2014 Chris Talkington, contributors.
|
|
* Licensed under the MIT license.
|
|
* https://github.com/archiverjs/node-archiver/blob/master/LICENSE-MIT
|
|
*/
|
|
var fs = require('graceful-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;
|
|
}; |