adamrenklint/asimov-core

View on GitHub
lib/Filesystem.js

Summary

Maintainability
A
2 hrs
Test Coverage
var Klass = require('./Klass');
var _ = require('lodash');
var npath = require('path');
var fs = require('fs');
var watchdirectory = require('watchdirectory');

var _super = Klass.prototype;

module.exports = Klass.extend({

  'pathExists': function (path) {

    return fs.existsSync(path);
  },

  // Reads directory at <path> and executes callback with the <filename> of each file or directory. Returns true if <path> exists, and false if it doesn't.
  'readDirectory': function (path, callback) {

    var self = this;

    if (self.pathExists(path) && self.isDirectory(path)) {
      _.each(fs.readdirSync(path), function (filename) {
        if (filename[0] !== '.') {
          callback(npath.join(path, filename), filename, path);
        }
      });
      return true;
    }
    return false;
  },

  'copyDirectoryIfExists': function (from, to) {

    var self = this;
    if (fs.existsSync(from)) {
      wrench.copyDirSyncRecursive(from, to);
      return true;
    }
    return false;
  },

  // Watches tree at <path>, executing <callback> whenever a file is added, changed or removed. Returns a function that will stop watching.
  'watchTree': function (path, callback) {

    return  watchdirectory.watchDirectory(path, {
      'initial': false,
      'exclude': function (f) {

        var modulesPath = npath.join(process.cwd(), 'node_modules');
        var buildPath = npath.join(process.cwd(), 'build');

        if (f.indexOf('/.') > 0 || f.indexOf(modulesPath) === 0 || f.indexOf(buildPath) === 0) {
          return true;
        }
        return false;
      }
    }, function (filename) {
      callback.apply(null, arguments);
    });
  },

  'cleanDirectory': function (path) {

    var self = this;
    self.readDirectory(path, function (subPath, filename) {
      if (self.isDirectory(subPath)) {
        self.recursiveDelete(subPath);
      }
      else {
        fs.unlinkSync(subPath);
      }
    });
  },

  'writeTree': function (value, path, clean) {

    var self = this;

    if (clean) {
      self.cleanDirectory(path);
    }

    for (var key in value) {

      if (~key.indexOf('dir::')) {

        var pathName = key.replace('dir::', '');
        fs.mkdirSync(npath.join(path, pathName));
        self.writeTree(value[key], npath.join(path, pathName));
      }
      else {

        fs.writeFileSync(npath.join(path, key), value[key]);
      }
    }
  },

  // Steps through each part of <path> and makes sure all directories exist, creating if not.
  'forceExists': function (path) {

    if (path.indexOf(process.cwd()) >= 0) {
      path = path.replace(process.cwd() + '/', '');
    }

    var parts = path.split('/');

    if (parts[0].indexOf('.') > 0) {
      parts.pop();
    }

    var fullPath = '';
    _.each(parts, function (fragment) {

      if (fragment) {

        fullPath += fragment + '/';
        if (!fs.existsSync(fullPath)) {
          fs.mkdirSync(fullPath);
        }
      }
    });
  },

  'readFile': function (path, filename, options) {

    var self = this;
    options = options || {};
    filename || (filename = _.last(path.split('/')));

    if (options.autoEncode !== false) {
      options.autoEncode = true;
    }

    if (options.autoEncode && (self.hasFileExtension(filename, 'txt') || self.hasFileExtension(filename, 'tmpl') || self.hasFileExtension(filename, 'html') || self.hasFileExtension(filename, 'styl') || self.hasFileExtension(filename, 'js'))) {
      return fs.readFileSync(path, 'utf8');
    }
    else {
      return fs.readFileSync(path);
    }
  },

  // Write <value> to <path>
  'writeFile': function (path, value) {

    return fs.writeFileSync(path, value);
  },

  'isDirectory': function (path) {

    return fs.statSync(path).isDirectory();
  },

  'getStats': function (path) {

    return fs.lstatSync(path);
  },

  'recursiveDelete': function (path) {

    var self = this;

    if (!self.pathExists(path)) return;

    if (self.isDirectory(path) && !self.getStats(path).isSymbolicLink()) {

      var exists = self.readDirectory(path, function (currentPath) {
        if (!self.hasFileExtension(currentPath, 'git')) {
          if (self.isDirectory(currentPath)) {
            self.recursiveDelete(currentPath);
          }
          else {
            fs.unlinkSync(currentPath);
          }
        }
      });

      exists && fs.rmdirSync(path);
    }
    else {
      fs.unlinkSync(path);
    }
  },

  'rebuildDirectory': function (path) {

    this.recursiveDelete(path);
    fs.mkdirSync(path);
  },

  'join': function () {

    return npath.join.apply(npath, arguments);
  },

  'hasFileExtension': function (filename, extension) {

    var parts = filename.split('.');
    return parts[parts.length - 1] === extension;
  },

  'readJSON': function (path) {

    var self = this;
    var json = {};

    if (self.hasFileExtension(path, 'json')) {

      var raw = fs.readFileSync(path, 'utf8');
      var contents;

      try {

        contents = JSON.parse(raw);
      }
      catch (e) {

        throw new Error('Malformed JSON in ' + path);
      }

      json = _.merge(json, contents);
    }

    return json;
  },

  'findFirstMatch': function (needle, haystacks) {

    var self = this;
    var paths = [];
    var match = false;
    var path;

    if (!_.isArray(haystacks)) {
      haystacks = [haystacks];
    }

    haystacks.forEach(function (haystack) {

      if (match) return;

      self.recursiveForFolders(haystack, function (_path) {

        if (match) return false;
        var checkPath = npath.join(_path, needle);

        if (self.pathExists(checkPath) && !match) {
          match = checkPath;
          return false;
        }
      });
    });

    return match;
  },

  'recursiveForFolders': function (path, callback) {

    var self = this;
    if (self.pathExists(path) && self.isDirectory(path)) {

      var result = callback(path);
      if (result === false) return;

      self.readDirectory(path, function (subPath) {
        self.recursiveForFolders(subPath, callback);
      });
    }
  },

  'symlink': function (srcPath, destPath, type) {

    var self = this;
    if (!self.pathExists(srcPath) || self.pathExists(destPath)) return;
    return fs.symlinkSync(srcPath, destPath, type);
  }
});