UNPKG

fis3

Version:
288 lines (253 loc) 8.02 kB
'use strict'; var _ = require('./util.js'); var glob = require('glob'); var path = require('path'); /** * fis 项目相关 * @namespace fis.project */ exports.DEFAULT_REMOTE_REPOS = 'http://fis.baidu.com/repos'; /** * 获取项目目录中,需要编译的文件集合,返回格式为对象,`key` 为文件基于项目目录的绝对路径, `value` 为文件对象。 * * 当前 media 环境下面设置有 `project.files` 列表时,走 {@link fis.project.getSourceByPatterns}, 否则兼容 fis 2 中 * 的用法,基于 `project.include` 和 `fis.exclude` 走 {@link fis.util.find} 查找。 * * @name getSource * @function * @memberOf fis.project */ exports.getSource = function() { var patterns = fis.media().get('project.files'); if (patterns && patterns.length) { return exports.getSourceByPatterns(patterns); } var root = exports.getProjectPath(), source = {}, project_exclude = /^(\/output\b|\/fis-[^\/]+)$/, include = fis.config.get('project.include'), exclude = fis.config.get('project.exclude'); if (fis.util.is(exclude, 'Array')) { project_exclude = [project_exclude].concat(exclude); } else if (exclude) { project_exclude = [project_exclude, exclude]; } fis.util.find(root, include, project_exclude, root).forEach(function(file) { // 产生对应的 File对象 file = fis.file(file); if (file.release) { source[file.subpath] = file; } }); return source; }; /** * 返回项目目录下符合检索规则的文件。以 `project.files` 为匹配规则,`project.ignore` 为排除规则进行检索 * @param {String} patterns 匹配规则,glob文法 * @param {Object} opts 配置 @see glob.sync options * @return {Object} 返回 * @memberOf fis.project * @name getSourceByPatterns */ exports.getSourceByPatterns = function(patterns, opts) { patterns = patterns || fis.media().get('project.files'); if (!Array.isArray(patterns)) { patterns = [patterns]; } opts = _.assign({ cwd: exports.getProjectPath(), matchBase: true, ignore: fis.media().get('project.ignore', []).map(function(pattern) { return pattern[0] === '/' ? pattern.substring(1) : pattern; }) }, opts || {}); opts.nodir = true; opts.sync = true; var ret = []; var source = {}; patterns.forEach(function(pattern, index) { var exclude = pattern.substring(0, 1) === '!'; if (exclude) { pattern = pattern.substring(1); // 如果第一个规则就是排除用法,都没有获取结果就排除,这是不合理的用法。 // 不过为了保证程序的正确性,在排除之前,通过 `**` 先把所有文件获取到。 // 至于性能问题,请用户使用时规避。 (index === 0) && (ret = glob.sync('**', opts)); } // glob 列文件规则带 / 表现不对。 pattern[0] === '/' && (pattern = pattern.substring(1)); var mathes = glob.sync(pattern, opts); ret = _[exclude ? 'difference' : 'union'](ret, mathes); }); ret.forEach(function(file) { file = fis.file(opts.cwd, file); if (file.release && !file.isDir()) { source[file.subpath] = file; } }); return source; }; //paths var PROJECT_ROOT; var TEMP_ROOT; /* * 返回由 root 和 args 拼接成的标准路径。 * @param {String} root rootPath * @param {String|Array} args 后续路径 * @return {String} 标准路径格式 * @example * getPath('/Users/', ['apple', '/someone/', '/Destop/']) === getPath('/Users/', 'apple/someone//Destop/') * /Users/apple/someone/Destop */ function getPath(root, args) { if (args && args.length > 0) { args = root + '/' + Array.prototype.join.call(args, '/'); return fis.util(args); } else { return fis.util(root); } } /* * 初始化文件夹 * @param {String} path 文件夹路径 * @param {String} title * @return {String} 若文件夹已存在返回其觉得对路径,若不存在新建病返回绝对路径,若为文件则打印错误信息,返回path绝对路径 */ function initDir(path, title) { if (fis.util.exists(path)) { if (!fis.util.isDir(path)) { fis.log.error('unable to set path[%s] as %s directory.', path, title); } } else { fis.util.mkdir(path); } path = fis.util.realpath(path); if (path) { return path; } else { fis.log.error('unable to create dir [%s] for %s directory.', path, title); } } /** * 获取项目所在目录。 * 注意:返回的文件路径,已经被 normalize 了。 * @param {String} [subpath] 如果指定了子目录,将返回子目录路径。 * @return {String} * @function * @memberOf fis.project * @name getProjectPath */ exports.getProjectPath = function() { if (PROJECT_ROOT) { return getPath(PROJECT_ROOT, arguments); } else { fis.log.error('undefined project root'); } }; /** * 设置项目根目录 * @param {String} path 项目根目录 * @function * @memberOf fis.project * @name setProjectRoot */ exports.setProjectRoot = function(path) { if (fis.util.isDir(path)) { PROJECT_ROOT = fis.util.realpath(path); } else { fis.log.error('invalid project root path [%s]', path); } }; /** * 设置并创建临时文件夹 * @param {String} tmp 临时文件夹路径 * @function * @memberOf fis.project * @name setTempRoot */ exports.setTempRoot = function(tmp) { TEMP_ROOT = initDir(tmp); }; /** * 获取临时文件夹根目录,若未手动设置,则遍历用户环境变量中['FIS_TEMP_DIR', 'LOCALAPPDATA', 'APPDATA', 'HOME']这几项是否有设置,有则作为临时目录path,没有则以fis3/.fis-tmp作为临时文件夹 * @function * @memberOf fis.project * @name getTempRoot */ exports.getTempRoot = function() { if (!TEMP_ROOT) { var list = ['FIS_TEMP_DIR', 'LOCALAPPDATA', 'APPDATA', 'HOME']; var name = fis.cli && fis.cli.name ? fis.cli.name : 'fis'; var tmp; for (var i = 0, len = list.length; i < len; i++) { if ((tmp = process.env[list[i]])) { break; } } tmp = tmp || __dirname + '/../'; exports.setTempRoot(tmp + '/.' + name + '-tmp'); } return TEMP_ROOT; }; /** * 获取临时文件夹路径 * @return {String} * @function * @memberOf fis.project * @name getTempPath */ exports.getTempPath = function() { return getPath(exports.getTempRoot(), arguments); }; /** * 获取对应缓存的文件路径,缓存存放在 TEMP_ROOT/cache 下 * @return {String} 对应缓存的路径 * @function * @memberOf fis.project * @name getCachePath */ exports.getCachePath = function() { return getPath(exports.getTempPath('cache'), arguments); }; /** * 根据路径查找路径,支持相对路径和基于项目文件夹的绝对路径。 * * @param {string} path 文件路径。 * @param {File} file 文件对象,当路径为相对路径时,此文件对象所在目录将用于查找目标文件。 * @return {Object} 返回查找结果对象。 * @function * @memberOf fis.project * @name lookup */ exports.lookup = function(path, file, silent) { var info = fis.uri(path, file ? file.dirname : exports.getProjectPath()); /** * 当查找文件时派送, 可以扩展 fis 默认的查找文件功能。如:支持无后缀文件查找,支持 components 文件查找。 * @event lookup:file * @property {Object} info 包含查找路径信息。 * @property {File} file 文件对象。 * @memberOf fis */ fis.emit('lookup:file', info, file, silent); if (!info.id) { info.id = info.file ? info.file.id : info.rest; } if (!info.moduleId) { info.moduleId = info.file && info.file.moduleId || info.id; } return info; }; var mediaName; /** * 返回当前用户所在的 media 名称。 * @return {String} 当前用户所在分支 * @function * @memberOf fis.project * @name currentMedia */ exports.currentMedia = function (value) { if (arguments.length) { mediaName = value; } return mediaName || 'dev'; };