diff options
author | Samy Pessé <samypesse@gmail.com> | 2015-03-09 10:43:12 +0100 |
---|---|---|
committer | Samy Pessé <samypesse@gmail.com> | 2015-03-09 10:43:12 +0100 |
commit | 34fc2831e0cf0fed01c71cec28d93472d87f455b (patch) | |
tree | a803cc907c20491ba02863b5d3dd5aedf6bfed10 /lib/pluginslist.js | |
parent | e1594cde2c32e4ff48f6c4eff3d3d461743d74e1 (diff) | |
parent | 1bf68a5aa0703b5a1815cfe4ebb731b5fb6ed9d2 (diff) | |
download | gitbook-34fc2831e0cf0fed01c71cec28d93472d87f455b.zip gitbook-34fc2831e0cf0fed01c71cec28d93472d87f455b.tar.gz gitbook-34fc2831e0cf0fed01c71cec28d93472d87f455b.tar.bz2 |
Merge branch 'version/2.0'
Diffstat (limited to 'lib/pluginslist.js')
-rw-r--r-- | lib/pluginslist.js | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/lib/pluginslist.js b/lib/pluginslist.js new file mode 100644 index 0000000..61d52a5 --- /dev/null +++ b/lib/pluginslist.js @@ -0,0 +1,225 @@ +var _ = require("lodash"); +var Q = require("q"); +var npmi = require('npmi'); +var npm = require('npm'); +var semver = require('semver'); + +var Plugin = require("./plugin"); +var pkg = require("../package.json"); + +var initNPM = _.memoize(function() { + return Q.nfcall(npm.load, { silent: true, loglevel: 'silent' }); +}); + + +var PluginsList = function(book, plugins) { + this.book = book; + this.log = this.book.log; + + // List of Plugin objects + this.list = []; + + // List of names of failed plugins + this.failed = []; + + // Namespaces + this.namespaces = _.chain(["website", "ebook"]) + .map(function(namespace) { + return [ + namespace, + { + html: {}, + resources: _.chain(Plugin.RESOURCES) + .map(function(type) { + return [type, []]; + }) + .object() + .value() + } + ]; + }) + .object() + .value(); + + // Bind methods + _.bindAll(this); + + if (plugins) this.load(plugins); +}; + +// return count of plugins +PluginsList.prototype.count = function() { + return this.list.length; +}; + +// Add and load a plugin +PluginsList.prototype.load = function(plugin, options) { + var that = this; + + if (_.isArray(plugin)) { + return _.reduce(plugin, function(prev, p) { + return prev.then(function() { + return that.load(p); + }); + }, Q()); + } + if (_.isObject(plugin) && !(plugin instanceof Plugin)) plugin = plugin.name; + if (_.isString(plugin)) plugin = new Plugin(this.book, plugin); + + that.log.info("load plugin", plugin.name, "...."); + if (!plugin.isValid()) { + that.log.info.fail(); + that.failed.push(plugin.name); + return Q(); + } else { + that.log.info.ok(); + + // Push in the list + that.list.push(plugin); + } + + // Extract filters + _.each(plugin.getFilters(), function(filterFunc, filterName) { + that.book.template.addFilter(filterName, filterFunc); + }); + + // Extract blocks + _.each(plugin.getBlocks(), function(block, blockName) { + that.book.template.addBlock(blockName, block); + }); + + return _.reduce(_.keys(that.namespaces), function(prev, namespaceName) { + return prev.then(function() { + return plugin.getResources(namespaceName) + .then(function(plResources) { + var namespace = that.namespaces[namespaceName]; + + // Extract js and css + _.each(Plugin.RESOURCES, function(resourceType) { + namespace.resources[resourceType] = (namespace.resources[resourceType] || []).concat(plResources[resourceType] || []); + }); + + // Map of html resources by name added by each plugin + _.each(plResources.html || {}, function(value, tag) { + // Turn into function if not one already + if (!_.isFunction(value)) value = _.constant(value); + + namespace.html[tag] = namespace.html[tag] || []; + namespace.html[tag].push(value); + }); + }) + }); + }, Q()); +}; + +// Call a hook +PluginsList.prototype.hook = function(name, data) { + return _.reduce(this.list, function(prev, plugin) { + return prev.then(function(ret) { + return plugin.callHook(name, ret); + }); + }, Q(data)); +}; + +// Return a template from a plugin +PluginsList.prototype.template = function(name) { + var withTpl = _.find(this.list, function(plugin) { + return ( + plugin.infos.templates && + plugin.infos.templates[name] + ); + }); + + if (!withTpl) return null; + return withTpl.resolveFile(withTpl.infos.templates[name]); +}; + +// Return an html snippet +PluginsList.prototype.html = function(namespace, tag, context, options) { + var htmlSnippets = this.namespaces[namespace].html[tag]; + return _.map(htmlSnippets || [], function(code) { + return code.call(context, options); + }).join("\n"); +}; + +// Return a resources map for a namespace +PluginsList.prototype.resources = function(namespace) { + return this.namespaces[namespace].resources; +}; + +// Install plugins from a book +PluginsList.prototype.install = function() { + var that = this; + var defaultsPlugins = _.pluck(that.book.options.defaultsPlugins) + + // Remove defaults (no need to install) + var plugins = _.filter(that.book.options.plugins, function(plugin) { + return !_.contains(defaultsPlugins, plugin.name); + }); + + // Install plugins one by one + that.book.log.info.ln(plugins.length+" plugins to install"); + return _.reduce(plugins, function(prev, plugin) { + return prev.then(function() { + var fullname = "gitbook-plugin-"+plugin.name; + + return Q() + + // Resolve version if needed + .then(function() { + if (plugin.version) return plugin.version; + + that.book.log.info.ln("No version specified, resolve plugin", plugin.name); + return initNPM() + .then(function() { + return Q.nfcall(npm.commands.view, [fullname+"@*", "engines"], true); + }) + .then(function(versions) { + return _.chain(versions) + .pairs() + .map(function(v) { + return { + version: v[0], + gitbook: (v[1].engines || {})["gitbook"] + } + }) + .filter(function(v) { + return v.gitbook && semver.satisfies(pkg.version, v.gitbook); + }) + .sort(function(v1, v2) { + return semver.lt(v1.version, v2.version)? 1 : -1; + }) + .pluck("version") + .first() + .value(); + }); + }) + + // Install the plugin with the resolved version + .then(function(version) { + if (!version) { + throw "Found no satisfactory version for plugin "+plugin.name; + } + + that.book.log.info.ln("install plugin", plugin.name, "from npm ("+fullname+") with version", version); + return Q.nfcall(npmi, { + 'name': fullname, + 'version': version, + 'path': that.book.root, + 'npmLoad': { + 'loglevel': 'silent', + 'loaded': true, + 'prefix': that.book.root + } + }); + }) + .then(function() { + that.book.log.info.ok("plugin", plugin.name, "installed with success"); + }); + }); + }, Q()); +}; + + + +module.exports = PluginsList; |