diff options
-rw-r--r-- | lib/plugins/registry.js | 81 | ||||
-rw-r--r-- | test/all.js | 1 | ||||
-rw-r--r-- | test/plugins.js | 37 |
3 files changed, 117 insertions, 2 deletions
diff --git a/lib/plugins/registry.js b/lib/plugins/registry.js index 6b1cddb..3fa532c 100644 --- a/lib/plugins/registry.js +++ b/lib/plugins/registry.js @@ -1,4 +1,10 @@ var npm = require('npm'); +var npmi = require('npmi'); +var semver = require('semver'); +var _ = require('lodash'); + +var Promise = require('../utils/promise'); +var gitbook = require('../gitbook'); var PLUGIN_PREFIX = 'gitbook-plugin-'; @@ -18,14 +24,84 @@ function validateId(name) { return name.indexOf(PLUGIN_PREFIX) === 0; } +// Initialize NPM for operations +var initNPM = _.memoize(function() { + return Promise.nfcall(npm.load, { + silent: true, + loglevel: 'silent' + }); +}); + // Link a plugin for use in a specific book function linkPlugin(book, pluginPath) { book.log('linking', pluginPath); } +// Resolve the latest version for a plugin +function resolveVersion(plugin) { + var npnName = npmId(plugin); + + return initNPM() + .then(function() { + return Promise.nfcall(npm.commands.view, [npnName+'@*', '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 && gitbook.satisfies(v.gitbook); + }) + .sort(function(v1, v2) { + return semver.lt(v1.version, v2.version)? 1 : -1; + }) + .pluck('version') + .first() + .value(); + }); +} + + // Install a plugin in a book -function installPlugin(book, pluginId) { - book.log('installing plugin', pluginId); +function installPlugin(book, plugin, version) { + book.log.info.ln('installing plugin', plugin); + + var npnName = npmId(plugin); + + return Promise() + .then(function() { + if (version) return version; + + book.log.info.ln('No version specified, resolve plugin "' + plugin + '"'); + return resolveVersion(plugin); + }) + + // Install the plugin with the resolved version + .then(function(version) { + if (!version) { + throw new Error('Found no satisfactory version for plugin "' + plugin + '"'); + } + + book.log.info.ln('install plugin' + plugin +'" from npm ('+npnName+') with version', version); + return Promise.nfcall(npmi, { + 'name': npnName, + 'version': version, + 'path': book.root, + 'npmLoad': { + 'loglevel': 'silent', + 'loaded': true, + 'prefix': book.root + } + }); + }) + .then(function() { + book.log.info.ok('plugin "' + plugin.name + '" installed with success'); + }); } module.exports = { @@ -33,6 +109,7 @@ module.exports = { pluginId: pluginId, validateId: validateId, + resolve: resolveVersion, link: linkPlugin, install: installPlugin }; diff --git a/test/all.js b/test/all.js index fed3f61..c7c2bf7 100644 --- a/test/all.js +++ b/test/all.js @@ -10,6 +10,7 @@ require('./parse'); require('./git'); require('./template'); require('./conrefs'); +require('./plugins'); // Page and HTML generation require('./page'); diff --git a/test/plugins.js b/test/plugins.js new file mode 100644 index 0000000..123a194 --- /dev/null +++ b/test/plugins.js @@ -0,0 +1,37 @@ +var mock = require('./mock'); +var registry = require('../lib/plugins/registry'); + +describe('Plugins', function() { + var book; + + before(function() { + return mock.setupBook({}) + .then(function(_book) { + book = _book; + }); + }); + + describe('Resolve Version', function() { + + it('should resolve a plugin version', function() { + return registry.resolve('ga') + .should.be.fulfilled(); + }); + + }); + + describe('Installation', function() { + + it('should install a plugin from NPM without a specific version', function() { + return registry.install(book, 'ga') + .should.be.fulfilled(); + }); + + it('should install a plugin from NPM with a specific version', function() { + return registry.install(book, 'ga', '1.0.0') + .should.be.fulfilled(); + }); + + }); +}); + |