Version 1
[yaffs-website] / node_modules / grunt / lib / grunt / file.js
diff --git a/node_modules/grunt/lib/grunt/file.js b/node_modules/grunt/lib/grunt/file.js
new file mode 100644 (file)
index 0000000..303e0ab
--- /dev/null
@@ -0,0 +1,454 @@
+'use strict';
+
+var grunt = require('../grunt');
+
+// Nodejs libs.
+var fs = require('fs');
+var path = require('path');
+
+// The module to be exported.
+var file = module.exports = {};
+
+// External libs.
+file.glob = require('glob');
+file.minimatch = require('minimatch');
+file.findup = require('findup-sync');
+var YAML = require('js-yaml');
+var rimraf = require('rimraf');
+var iconv = require('iconv-lite');
+var pathIsAbsolute = require('path-is-absolute');
+
+// Windows?
+var win32 = process.platform === 'win32';
+
+// Normalize \\ paths to / paths.
+var unixifyPath = function(filepath) {
+  if (win32) {
+    return filepath.replace(/\\/g, '/');
+  } else {
+    return filepath;
+  }
+};
+
+// Change the current base path (ie, CWD) to the specified path.
+file.setBase = function() {
+  var dirpath = path.join.apply(path, arguments);
+  process.chdir(dirpath);
+};
+
+// 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.
+  grunt.util._.flattenDeep(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 = grunt.util._.difference(result, matches);
+    } else {
+      // Otherwise add matching files.
+      result = grunt.util._.union(result, matches);
+    }
+  });
+  return result;
+};
+
+// Match a filepath or filepaths against one or more wildcard patterns. Returns
+// all matching filepaths.
+file.match = function(options, patterns, filepaths) {
+  if (grunt.util.kindOf(options) !== 'object') {
+    filepaths = patterns;
+    patterns = options;
+    options = {};
+  }
+  // Return empty set if either patterns or filepaths was omitted.
+  if (patterns == null || filepaths == null) { return []; }
+  // Normalize patterns and filepaths to arrays.
+  if (!Array.isArray(patterns)) { patterns = [patterns]; }
+  if (!Array.isArray(filepaths)) { filepaths = [filepaths]; }
+  // Return empty set if there are no patterns or filepaths.
+  if (patterns.length === 0 || filepaths.length === 0) { return []; }
+  // Return all matching filepaths.
+  return processPatterns(patterns, function(pattern) {
+    return file.minimatch.match(filepaths, pattern, options);
+  });
+};
+
+// Match a filepath or filepaths against one or more wildcard patterns. Returns
+// true if any of the patterns match.
+file.isMatch = function() {
+  return file.match.apply(file, arguments).length > 0;
+};
+
+// Return an array of all file paths that match the given wildcard patterns.
+file.expand = function() {
+  var args = grunt.util.toArray(arguments);
+  // 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() : {};
+  // 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 file.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;
+};
+
+var pathSeparatorRe = /[\/\\]/g;
+
+// The "ext" option refers to either everything after the first dot (default)
+// or everything after the last dot.
+var extDotRe = {
+  first: /(\.[^\/]*)?$/,
+  last: /(\.[^\/\.]*)?$/,
+};
+
+// Build a multi task "files" object dynamically.
+file.expandMapping = function(patterns, destBase, options) {
+  options = grunt.util._.defaults({}, options, {
+    extDot: 'first',
+    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 ('ext' in options) {
+      destPath = destPath.replace(extDotRe[options.extDot], 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;
+};
+
+// Like mkdir -p. Create a directory and any intermediary directories.
+file.mkdir = function(dirpath, mode) {
+  if (grunt.option('no-write')) { return; }
+  // Set directory mode in a strict-mode-friendly way.
+  if (mode == null) {
+    mode = parseInt('0777', 8) & (~process.umask());
+  }
+  dirpath.split(pathSeparatorRe).reduce(function(parts, part) {
+    parts += part + '/';
+    var subpath = path.resolve(parts);
+    if (!file.exists(subpath)) {
+      try {
+        fs.mkdirSync(subpath, mode);
+      } catch (e) {
+        throw grunt.util.error('Unable to create directory "' + subpath + '" (Error code: ' + e.code + ').', e);
+      }
+    }
+    return parts;
+  }, '');
+};
+
+// Recurse into a directory, executing callback for each file.
+file.recurse = function recurse(rootdir, callback, subdir) {
+  var abspath = subdir ? path.join(rootdir, subdir) : rootdir;
+  fs.readdirSync(abspath).forEach(function(filename) {
+    var filepath = path.join(abspath, filename);
+    if (fs.statSync(filepath).isDirectory()) {
+      recurse(rootdir, callback, unixifyPath(path.join(subdir || '', filename || '')));
+    } else {
+      callback(unixifyPath(filepath), rootdir, subdir, filename);
+    }
+  });
+};
+
+// The default file encoding to use.
+file.defaultEncoding = 'utf8';
+// Whether to preserve the BOM on file.read rather than strip it.
+file.preserveBOM = false;
+
+// Read a file, return its contents.
+file.read = function(filepath, options) {
+  if (!options) { options = {}; }
+  var contents;
+  grunt.verbose.write('Reading ' + filepath + '...');
+  try {
+    contents = fs.readFileSync(String(filepath));
+    // If encoding is not explicitly null, convert from encoded buffer to a
+    // string. If no encoding was specified, use the default.
+    if (options.encoding !== null) {
+      contents = iconv.decode(contents, options.encoding || file.defaultEncoding, {stripBOM: !file.preserveBOM});
+    }
+    grunt.verbose.ok();
+    return contents;
+  } catch (e) {
+    grunt.verbose.error();
+    throw grunt.util.error('Unable to read "' + filepath + '" file (Error code: ' + e.code + ').', e);
+  }
+};
+
+// Read a file, parse its contents, return an object.
+file.readJSON = function(filepath, options) {
+  var src = file.read(filepath, options);
+  var result;
+  grunt.verbose.write('Parsing ' + filepath + '...');
+  try {
+    result = JSON.parse(src);
+    grunt.verbose.ok();
+    return result;
+  } catch (e) {
+    grunt.verbose.error();
+    throw grunt.util.error('Unable to parse "' + filepath + '" file (' + e.message + ').', e);
+  }
+};
+
+// Read a YAML file, parse its contents, return an object.
+file.readYAML = function(filepath, options) {
+  var src = file.read(filepath, options);
+  var result;
+  grunt.verbose.write('Parsing ' + filepath + '...');
+  try {
+    result = YAML.load(src);
+    grunt.verbose.ok();
+    return result;
+  } catch (e) {
+    grunt.verbose.error();
+    throw grunt.util.error('Unable to parse "' + filepath + '" file (' + e.problem + ').', e);
+  }
+};
+
+// Write a file.
+file.write = function(filepath, contents, options) {
+  if (!options) { options = {}; }
+  var nowrite = grunt.option('no-write');
+  grunt.verbose.write((nowrite ? 'Not actually writing ' : 'Writing ') + filepath + '...');
+  // Create path, if necessary.
+  file.mkdir(path.dirname(filepath));
+  try {
+    // If contents is already a Buffer, don't try to encode it. If no encoding
+    // was specified, use the default.
+    if (!Buffer.isBuffer(contents)) {
+      contents = iconv.encode(contents, options.encoding || file.defaultEncoding);
+    }
+    // Actually write file.
+    if (!nowrite) {
+      fs.writeFileSync(filepath, contents, 'mode' in options ? {mode: options.mode} : {});
+    }
+    grunt.verbose.ok();
+    return true;
+  } catch (e) {
+    grunt.verbose.error();
+    throw grunt.util.error('Unable to write "' + filepath + '" file (Error code: ' + e.code + ').', e);
+  }
+};
+
+// Read a file, optionally processing its content, then write the output.
+// Or read a directory, recursively creating directories, reading files,
+// processing content, writing output.
+file.copy = function copy(srcpath, destpath, options) {
+  if (file.isDir(srcpath)) {
+    // Copy a directory, recursively.
+    // Explicitly create new dest directory.
+    file.mkdir(destpath);
+    // Iterate over all sub-files/dirs, recursing.
+    fs.readdirSync(srcpath).forEach(function(filepath) {
+      copy(path.join(srcpath, filepath), path.join(destpath, filepath), options);
+    });
+  } else {
+    // Copy a single file.
+    file._copy(srcpath, destpath, options);
+  }
+};
+
+// Read a file, optionally processing its content, then write the output.
+file._copy = function(srcpath, destpath, options) {
+  if (!options) { options = {}; }
+  // If a process function was specified, and noProcess isn't true or doesn't
+  // match the srcpath, process the file's source.
+  var process = options.process && options.noProcess !== true &&
+    !(options.noProcess && file.isMatch(options.noProcess, srcpath));
+  // If the file will be processed, use the encoding as-specified. Otherwise,
+  // use an encoding of null to force the file to be read/written as a Buffer.
+  var readWriteOptions = process ? options : {encoding: null};
+  // Actually read the file.
+  var contents = file.read(srcpath, readWriteOptions);
+  if (process) {
+    grunt.verbose.write('Processing source...');
+    try {
+      contents = options.process(contents, srcpath, destpath);
+      grunt.verbose.ok();
+    } catch (e) {
+      grunt.verbose.error();
+      throw grunt.util.error('Error while processing "' + srcpath + '" file.', e);
+    }
+  }
+  // Abort copy if the process function returns false.
+  if (contents === false) {
+    grunt.verbose.writeln('Write aborted.');
+  } else {
+    file.write(destpath, contents, readWriteOptions);
+  }
+};
+
+// Delete folders and files recursively
+file.delete = function(filepath, options) {
+  filepath = String(filepath);
+
+  var nowrite = grunt.option('no-write');
+  if (!options) {
+    options = {force: grunt.option('force') || false};
+  }
+
+  grunt.verbose.write((nowrite ? 'Not actually deleting ' : 'Deleting ') + filepath + '...');
+
+  if (!file.exists(filepath)) {
+    grunt.verbose.error();
+    grunt.log.warn('Cannot delete nonexistent file.');
+    return false;
+  }
+
+  // Only delete cwd or outside cwd if --force enabled. Be careful, people!
+  if (!options.force) {
+    if (file.isPathCwd(filepath)) {
+      grunt.verbose.error();
+      grunt.fail.warn('Cannot delete the current working directory.');
+      return false;
+    } else if (!file.isPathInCwd(filepath)) {
+      grunt.verbose.error();
+      grunt.fail.warn('Cannot delete files outside the current working directory.');
+      return false;
+    }
+  }
+
+  try {
+    // Actually delete. Or not.
+    if (!nowrite) {
+      rimraf.sync(filepath);
+    }
+    grunt.verbose.ok();
+    return true;
+  } catch (e) {
+    grunt.verbose.error();
+    throw grunt.util.error('Unable to delete "' + filepath + '" file (' + e.message + ').', e);
+  }
+};
+
+// True if the file path exists.
+file.exists = function() {
+  var filepath = path.join.apply(path, arguments);
+  return fs.existsSync(filepath);
+};
+
+// True if the file is a symbolic link.
+file.isLink = function() {
+  var filepath = path.join.apply(path, arguments);
+  return file.exists(filepath) && fs.lstatSync(filepath).isSymbolicLink();
+};
+
+// True if the path is a directory.
+file.isDir = function() {
+  var filepath = path.join.apply(path, arguments);
+  return file.exists(filepath) && fs.statSync(filepath).isDirectory();
+};
+
+// True if the path is a file.
+file.isFile = function() {
+  var filepath = path.join.apply(path, arguments);
+  return file.exists(filepath) && fs.statSync(filepath).isFile();
+};
+
+// Is a given file path absolute?
+file.isPathAbsolute = function() {
+  var filepath = path.join.apply(path, arguments);
+  return pathIsAbsolute(filepath);
+};
+
+// Do all the specified paths refer to the same path?
+file.arePathsEquivalent = function(first) {
+  first = path.resolve(first);
+  for (var i = 1; i < arguments.length; i++) {
+    if (first !== path.resolve(arguments[i])) { return false; }
+  }
+  return true;
+};
+
+// Are descendant path(s) contained within ancestor path? Note: does not test
+// if paths actually exist.
+file.doesPathContain = function(ancestor) {
+  ancestor = path.resolve(ancestor);
+  var relative;
+  for (var i = 1; i < arguments.length; i++) {
+    relative = path.relative(path.resolve(arguments[i]), ancestor);
+    if (relative === '' || /\w+/.test(relative)) { return false; }
+  }
+  return true;
+};
+
+// Test to see if a filepath is the CWD.
+file.isPathCwd = function() {
+  var filepath = path.join.apply(path, arguments);
+  try {
+    return file.arePathsEquivalent(fs.realpathSync(process.cwd()), fs.realpathSync(filepath));
+  } catch (e) {
+    return false;
+  }
+};
+
+// Test to see if a filepath is contained within the CWD.
+file.isPathInCwd = function() {
+  var filepath = path.join.apply(path, arguments);
+  try {
+    return file.doesPathContain(fs.realpathSync(process.cwd()), fs.realpathSync(filepath));
+  } catch (e) {
+    return false;
+  }
+};