UNPKG

akurath

Version:

IDE Frontend for codepsaces.io

235 lines (198 loc) 7.08 kB
var _ = require('lodash'); var fs = require('fs'); var path = require('path'); var wrench = require('wrench'); var child_process = require('child_process'); var Q = require("q"); var semver = require("semver"); var pkg = require("../../package.json"); var utils = require("../utils"); var Addon = function(_rootPath, options) { this.root = _rootPath; this.infos = {}; this.options = _.defaults(options || {}, { blacklist: [], logger: console }); var logger = this.options.logger; // Load addon infos from an addon's directory this.load = Q.fbind(function(addonDir) { addonDir = addonDir || this.root; // Check addon var packageJsonFile = path.join(addonDir, "package.json"); if (!fs.existsSync(packageJsonFile)) { throw new Error("No 'package.json' in this repository: "+addonDir); } this.infos = JSON.parse(fs.readFileSync(packageJsonFile, 'utf8')); if (!this.isValid()) { throw new Error("Invalid 'package.json' file: "+packageJsonFile); } return this; }); // Valid the addon // Valid data and valid codebox engine version this.isValid = function() { return !(!this.infos.name || !this.infos.version || (!this.infos.main && !this.infos.client && !this.infos.client.main) || !this.infos.engines || !this.infos.engines.codebox || !semver.satisfies(pkg.version, this.infos.engines.codebox)); }; // Test is symlink this.isSymlink = function() { return Q.nfcall(fs.lstat, this.root).then(function(stats) { return stats.isSymbolicLink(); }); }; // Check if an addon is client side this.isClientside = function() { return (this.infos.client && this.infos.client.main); }; // Check if an addon is node addon this.isNode = function() { return (this.infos.main); }; // Check if an addon is already optimized this.isOptmized = function() { return fs.existsSync(path.join(this.root, "addon-built.js")); }; // Check if node dependencies seems to be installed this.areDependenciesInstalled = function() { return fs.existsSync(path.join(this.root, "node_modules")) || this.isOptmized(); }; // Check if an addon has node dependencies this.hasDependencies = function() { return _.size(this.infos.dependencies || {}) > 0; }; // Check if an addon has npm scripts this.hasScripts = function() { return _.size(this.infos.scripts || {}) > 0; }; // Check if the addon is blacklisted this.isBlacklisted = function() { return _.contains(this.options.blacklist, this.infos.name); }; // Optimize the addon this.optimizeClient = function(force) { var that = this; var d = Q.defer(); if (!this.isClientside() || (this.isOptmized() && !force)) { return Q(this); } // Base directory for the addon var addonPath = this.root; // R.js bin var rjs = path.resolve(__dirname, "../../node_modules/requirejs/bin/r.js"); // Path to the require-tools var requiretoolsPath = path.resolve(__dirname, "require-tools"); // Base main var main = this.infos.client.main; // Output file var output = path.resolve(addonPath, "addon-built.js"); // Build config var optconfig = { 'baseUrl': addonPath, 'name': main, 'out': output, 'optimize': 'none', //'logLevel': 4, // silent 'paths': { 'require-tools': requiretoolsPath }, 'map': { '*': { 'css': "require-tools/css/css", 'less': "require-tools/less/less", 'text': "require-tools/text/text" } } }; // Build command for r.js var command = "node "+rjs+" -o "+_.reduce(utils.deepkeys(optconfig), function(s, value, key) { return s+key+"="+value+" "; }, ""); // Run optimization logger.log("Optimizing", this.infos.name); return Q.nfcall(fs.unlink, output).fail(function() { return Q(); }).then(function() { return utils.exec(command, { env: process.env }) }).then(function() { logger.log("Finished", that.infos.name, "optimization"); return Q(that); }, function(err) { logger.error("error for optimization of", that.infos.name); logger.error("options=", optconfig); logger.error(err); return Q.reject(err); }); }; // Install dependencies for this addon this.installDependencies = function(force) { var that = this; if (!force) { if (!this.hasDependencies() && !this.hasScripts()) { return Q(this); } } logger.log("Install dependencies for", this.root); return utils.exec("npm install .", { cwd: this.root, env: process.env }).then(function() { return Q(that); }); }; // Transfer to a new root directory this.transfer = function(newRoot, options) { var that = this; options = _.defaults({}, options || {}, { forceDelete: true, excludeHiddenUnix: false, preserveFiles: false }); var addonPath = path.join(newRoot, this.infos.name); return Q.nfcall(wrench.copyDirRecursive, this.root, addonPath, options).then(function() { var addon = new Addon(addonPath, that.options); return addon.load(); }); }; // Symlink this addons this.symlink = function(newRoot) { var that = this; var addonPath = path.join(newRoot, this.infos.name); return Q.nfcall(fs.symlink, this.root, addonPath, 'dir').then(function() { var addon = new Addon(addonPath, that.options); return addon.load(); }); }; // Unlink this addon this.unlink = function() { return Q.nfcall(fs.unlink, this.root); }; // Start the node process this.start = function(app) { var that = this; if (!this.isNode()) { return Q(this); } logger.log("start addon", this.root); return app.load([ { 'packagePath': this.root } ]).then(function() { return Q(that); }); }; // Return addons cache resources list this.resources = function() { return ["addon-built.js"].concat(this.infos.client ? (this.infos.client.resources || []) : []); }; // Return addons network resources list this.network = function() { return [].concat(this.infos.client ? (this.infos.client.network || []) : []); }; }; module.exports = Addon;