/**
* @name index.js<lib/fsys>
* @author Kei Funagayama <funagayama_kei@cyberagent.co.jp>
* copyright (c) Cyberagent Inc.
* @overview fsys library
*/
var fs = require('fs');
var path = require('path');
var util = require('util');
var vm = require('vm');
var _ = require('lodash');
var mkdirp = require('mkdirp');
var jsonminify = require('jsonminify');
var jsonlint = require('jsonlint');
var store = require('./store');
var Checker = require('./checker');
/**
* @name fsys
* @namespace fsys
*/
module.exports = {
/**
* store library
* @name store
* @memberof fsys
*/
store: store,
/**
* checker library
* @name checker
* @memberof fsys
*/
Checker: Checker,
/**
* file type
* @name TYPE
* @memberof fsys
*/
TYPE: {
FILE: 'file',
DIRECTORY: 'directory',
BLOCK_DEVICE: 'block',
CHARACTER_DEVICE: 'character',
SYMLINK: 'symlink',
FIFO: 'fifo',
SOCKET: 'socket'
},
/**
* @name isFileSync
* @memberof fsys
* @method
* @param {String} p target file path
* @return {boolean}
*/
isFileSync: function (p) {
if (!fs.existsSync(p)) {
return false;
}
var stats = fs.statSync(p);
return stats.isFile();
},
/**
* @name isDirectorySync
* @memberof fsys
* @method
* @param {String} p target directory path
* @return {boolean}
*/
isDirectorySync: function (p) {
if (!fs.existsSync(p)) {
return false;
}
var stats = fs.statSync(p);
return stats.isDirectory();
},
/**
* @name typeSync
* @memberof fsys
* @method
* @param {String} p target path
* @return {String} this.TYPES
*/
typeSync: function (p) {
if (!fs.existsSync(p)) {
return undefined;
}
var TYPE = this.TYPE;
var stats = fs.statSync(p);
if (stats.isDirectory()) {
return TYPE.DIRECTORY;
} else if (stats.isFile()) {
return TYPE.FILE;
} else if (stats.isBlockDevice()) {
return TYPE.BLOCK_DEVICE;
} else if (stats.isCharacterDevice()) {
return TYPE.CHARACTER_DEVICE;
} else if (stats.isSymbolicLink()) {
return TYPE.SYMLINK;
} else if (stats.isFIFO()) {
return TYPE.FIFO;
} else if (stats.isSocket()) {
return TYPE.SOCKET;
} else {
return undefined;
}
},
/**
* bash: $ rm -rf <path>
*
* @name typeSync
* @param {String} p delete path
* @param {String} f path.resolve#from
* @memberof fsys
* @method
*/
rmrfSync: function (p, f) {
var self = this;
f = f || '';
p = path.resolve(f, path.normalize(p));
if (this.typeSync(p) === this.TYPE.DIRECTORY) {
_.each(fs.readdirSync(p), function(f) {
self.rmrfSync(path.join(p, f));
});
return fs.rmdirSync(p);
}
return fs.unlinkSync(p);
},
/**
* bash: $ mkdir -p <path> (async)
*
* @name mkdirp
* @memberof fsys
* @method
* @see https://npmjs.org/package/mkdirp
*/
mkdirp: mkdirp,
/**
* bash: $ mkdir -p <path> (sync)
*
* @name mkdirpSync
* @memberof fsys
* @method
* @see https://npmjs.org/package/mkdirp
*/
mkdirpSync: mkdirp.sync,
/**
* file system walk function
*
* @name walk
* @memberof fsys
* @method
* @param {String} basedir base path
* @param {function} filefn Function to be executed when the file is found
* @param {function} dirfnFunction to be executed when the directory is found
*
*/
walk: function (basedir, filefn, dirfn) {
filefn = filefn || function() {};
dirfn = dirfn || function() {};
var readdirSync = function(dir) {
var files = fs.readdirSync(dir);
for (var i = 0; i < files.length; i++) {
var file = dir+'/'+files[i];
//debug('before fs.statsSync:', file);
var stats = fs.statSync(file);
if (stats.isFile()) {
var prefix = dir.replace(basedir, '');
filefn(prefix, dir, files[i], stats);
} else if (stats.isDirectory()) {
var prefix = file.replace(basedir, '');
dirfn(prefix, stats);
readdirSync(file);
} else {
console.error('error:'.error, 'It is a file type that is not assumed. file:', file);
return;
}
}
};
readdirSync(basedir);
},
/**
* Read file Sync(json format)
*
* @name readJsonSync
* @memberof fsys
* @method
* @param {String} path read file path
* @param {boolean} minify use jsonminify
* @param {String} encode file read encode
*/
readJsonSync: function (path, minify, encode) {
minify = minify || false;
encode = encode || 'utf-8';
if (this.isFileSync(path)) {
var raw = fs.readFileSync(path, encode);
if (minify) {
raw = jsonminify(raw);
}
try {
return JSON.parse(raw);
} catch (e1) {
try {
jsonlint.parse(raw);
} catch (e2) {
throw e2;
}
}
}
return {};
},
/**
* JS設定ファイルからJSONデータを読み込む
*
* @name readFileFnJSONSync
* @memberof fsys
* @method
* @param {String} filePath load file path
* @param {String} encode file encode
* @return {Object} load json data
*/
readFileFnJSONSync: function (filePath, encode) {
encode = encode || 'utf-8';
if (this.isFileSync(filePath)) {
var raw = fs.readFileSync(filePath, encode);
var exports = {};
var context = {
process: process,
require: function(name) {
var module;
try {
module = require((function (_module) {
if (_module.charAt(0) !== '.') {
return _module;
}
return path.resolve(path.dirname(filePath), _module);
}(name)));
} catch (e) {
throw e;
}
return module;
},
__filename: __filename,
__dirname: __dirname,
console: console,
module: {
exports: exports
},
exports: exports
};
try {
return vm.runInNewContext(raw, context);
} catch (e) {
throw e;
}
}
return {};
},
/**
* change file modes or Access Control Lists
* bash: $ chmod {mode} {path} ...
*
* @name chmodfilesSync
* @memberof fsys
* @method
* @param {Array} list target files
* @param {int} mode change file mode
*/
chmodfilesSync: function(list, mode) {
list = list || [];
mode = mode || 0755;
_.find(list, function (p) {
fs.chmodSync(p, mode);
});
},
/**
* ファイルをコピーする
*
* @name cp
* @memberof fsys
* @method
* @param {String} src コピー元のファイルパス
* @param {String} dst コピー先のファイルパス
* @param {function} callback コールバック
*/
cp: function (src, dst, callback) {
var srcstream = fs.createReadStream(src);
var dststream = fs.createWriteStream(dst);
srcstream.on('error', callback);
dststream.on('error', callback);
dststream.on('close', function() {
return callback && callback();
});
srcstream.pipe(dststream);
},
/**
* '~'付きのファイルパスから絶対パスを返却する
*
* @name resolveTilde
* @memberof fsys
* @method
* @param {String} str 相対パス
* @return {String} file path
*/
resolveTilde: function (str) {
if (!str) {
return str;
}
if (str.substr(0,1) === '~') {
str = process.env.HOME + str.substr(1);
}
return path.resolve(str);
},
/**
* '~'付きのファイルパスの'~'をパスに置き換えて返却する
*
* @name resolveTilde
* @memberof fsys
* @method
* @param {String} str 相対パス
* @return {String} file path
*/
pathTilde: function (str) {
if (str && str.substr(0,1) === '~') {
return process.env.HOME + str.substr(1);
}
return str;
},
/**
* 拡張子が.jsはjavascript で、.jsonはJSON.parseでファイルをロードして返却します。
*
* @name readFileMultiConfigureSync
* @memberof fsys
* @method
* @param {String} path read file path
* @param {String} encode file read encode
*/
readFileMultiConfigureSync: function (path, encode) {
if (/.json$/.test(path)) {
return this.readJsonSync(path, true, this.encode);
} else if (/.js$/.test(path)) {
return this.readFileFnJSONSync(path, this.encode);
} else {
throw new Error('Extension, please specify the ".json" or ".js".');
}
}
};