summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamy Pesse <samypesse@gmail.com>2016-04-26 15:23:28 +0200
committerSamy Pesse <samypesse@gmail.com>2016-04-26 15:23:28 +0200
commitfa17f1671685a97e88c84fdba6a94744c54a09b8 (patch)
tree63083c0645a1f88bc7e96d891ef9ec9509d7680a
parentce99c8c7061eb9b4a2a5f4ff534d7fbeaf37cad0 (diff)
downloadgitbook-fa17f1671685a97e88c84fdba6a94744c54a09b8.zip
gitbook-fa17f1671685a97e88c84fdba6a94744c54a09b8.tar.gz
gitbook-fa17f1671685a97e88c84fdba6a94744c54a09b8.tar.bz2
Add base for commands
Improve plugins installation
-rw-r--r--book.js2
-rw-r--r--lib/cli/build.js30
-rw-r--r--lib/cli/getBook.js23
-rw-r--r--lib/cli/index.js198
-rw-r--r--lib/cli/indexe.js199
-rw-r--r--lib/cli/install.js21
-rw-r--r--lib/cli/options.js23
-rw-r--r--lib/cli/parse.js68
-rw-r--r--lib/cli/serve.js19
-rw-r--r--lib/cli/watch.js7
-rw-r--r--lib/index.js4
-rw-r--r--lib/models/config.js4
-rw-r--r--lib/output/index.js24
-rw-r--r--lib/plugins/installPlugins.js35
-rw-r--r--lib/plugins/listAll.js4
15 files changed, 451 insertions, 210 deletions
diff --git a/book.js b/book.js
index a1df67c..d6afa1f 100644
--- a/book.js
+++ b/book.js
@@ -9,7 +9,7 @@ module.exports = {
gitbook: '>=3.0.0-pre.0',
// Use the "official" theme
- //plugins: ['theme-official', 'sitemap'],
+ plugins: ['theme-official', 'sitemap'],
variables: {
version: pkg.version
diff --git a/lib/cli/build.js b/lib/cli/build.js
new file mode 100644
index 0000000..49931bd
--- /dev/null
+++ b/lib/cli/build.js
@@ -0,0 +1,30 @@
+var path = require('path');
+
+var options = require('./options');
+var getBook = require('./getBook');
+
+var Parse = require('../parse');
+var Output = require('../output');
+
+module.exports = {
+ name: 'build [book] [output]',
+ description: 'build a book',
+ options: [
+ options.log,
+ options.format
+ ],
+ exec: function(args, kwargs) {
+ var book = getBook(args, kwargs);
+ var Generator = Output.getGenerator(kwargs.format);
+
+ return Parse.parseBook(book)
+ .then(function(resultBook) {
+ var defaultOutputRoot = path.join(resultBook.getRoot(), '_book');
+ var outputFolder = args[1]? path.resolve(process.cwd(), args[1]) : defaultOutputRoot;
+
+ return Output.generate(Generator, resultBook, {
+ root: outputFolder
+ });
+ });
+ }
+};
diff --git a/lib/cli/getBook.js b/lib/cli/getBook.js
new file mode 100644
index 0000000..5c29078
--- /dev/null
+++ b/lib/cli/getBook.js
@@ -0,0 +1,23 @@
+var path = require('path');
+var Book = require('../models/book');
+var createNodeFS = require('../fs/node');
+
+/**
+ Return a book instance to work on from
+ command line args/kwargs
+
+ @param {Array} args
+ @param {Object} kwargs
+ @return {Book}
+*/
+function getBook(args, kwargs) {
+ var input = path.resolve(args[0] || process.cwd());
+ var logLevel = kwargs.log;
+
+ var fs = createNodeFS(input);
+ var book = Book.createForFS(fs);
+
+ return book;
+}
+
+module.exports = getBook;
diff --git a/lib/cli/index.js b/lib/cli/index.js
index eea707f..b93b7b1 100644
--- a/lib/cli/index.js
+++ b/lib/cli/index.js
@@ -1,199 +1,9 @@
-/* eslint-disable no-console */
-
-var _ = require('lodash');
-var path = require('path');
-var tinylr = require('tiny-lr');
-
-var Promise = require('../utils/promise');
-var PluginsManager = require('../plugins');
-var Book = require('../book');
-
-var helper = require('./helper');
-var Server = require('./server');
-var watch = require('./watch');
module.exports = {
commands: [
- {
- name: 'init [book]',
- description: 'setup and create files for chapters',
- options: [
- helper.options.log
- ],
- exec: function(args) {
- var input = path.resolve(args[0] || process.cwd());
- return Book.init(helper.nodeFS, input);
- }
- },
-
- {
- name: 'parse [book]',
- description: 'parse and returns debug information for a book',
- options: [
- helper.options.log
- ],
- exec: helper.bookCmd(function(book) {
- return book.parse()
- .then(function() {
- book.log.info.ln('Book located in:', book.root);
- book.log.info.ln('');
-
- if (book.config.exists()) book.log.info.ln('Configuration:', book.config.path);
-
- if (book.isMultilingual()) {
- book.log.info.ln('Multilingual book detected:', book.langs.path);
- } else {
- book.log.info.ln('Readme:', book.readme.path);
- book.log.info.ln('Summary:', book.summary.path);
- if (book.glossary.exists()) book.log.info.ln('Glossary:', book.glossary.path);
-
- book.log.info.ln('Pages:');
- _.each(book.pages, function(page) {
- book.log.info.ln('\t-', page.path);
- });
- }
- });
- })
- },
-
- {
- name: 'install [book]',
- description: 'install all plugins dependencies',
- options: [
- helper.options.log
- ],
- exec: helper.bookCmd(function(book, args) {
- var plugins = new PluginsManager(book);
-
- return book.config.load()
- .then(function() {
- return plugins.install();
- });
- })
- },
-
- {
- name: 'build [book] [output]',
- description: 'build a book',
- options: [
- helper.options.log,
- helper.options.format
- ],
- exec: helper.outputCmd(function(output, args, kwargs) {
- return output.book.parse()
- .then(function() {
- return output.generate();
- });
- })
- },
-
- helper.ebookCmd('pdf'),
- helper.ebookCmd('epub'),
- helper.ebookCmd('mobi'),
-
- {
- name: 'serve [book]',
- description: 'Build then serve a book from a directory',
- options: [
- {
- name: 'port',
- description: 'Port for server to listen on',
- defaults: 4000
- },
- {
- name: 'lrport',
- description: 'Port for livereload server to listen on',
- defaults: 35729
- },
- {
- name: 'watch',
- description: 'Enable/disable file watcher',
- defaults: true
- },
- helper.options.format,
- helper.options.log
- ],
- exec: function(args, kwargs) {
- var input = path.resolve(args[0] || process.cwd());
- var server = new Server();
-
- // Init livereload server
- var lrServer = tinylr({});
- var port = kwargs.port;
- var lrPath;
-
- var generate = function() {
-
- // Stop server if running
- if (server.isRunning()) console.log('Stopping server');
- return server.stop()
-
- // Generate the book
- .then(function() {
- var book = new Book({
- fs: helper.nodeFS,
- root: input,
- logLevel: kwargs.log
- });
-
- return book.parse()
- .then(function() {
- // Add livereload plugin
- book.config.set('plugins',
- book.config.get('plugins')
- .concat([
- { name: 'livereload' }
- ])
- );
-
- var Out = helper.FORMATS[kwargs.format];
- var output = new Out(book);
-
- return output.generate()
- .thenResolve(output);
- });
- })
-
- // Start server and watch changes
- .then(function(output) {
- console.log();
- console.log('Starting server ...');
- return server.start(output.root(), port)
- .then(function() {
- console.log('Serving book on http://localhost:'+port);
-
- if (lrPath) {
- // trigger livereload
- lrServer.changed({
- body: {
- files: [lrPath]
- }
- });
- }
-
- if (!kwargs.watch) return;
-
- return watch(output.book.root)
- .then(function(filepath) {
- // set livereload path
- lrPath = filepath;
- console.log('Restart after change in file', filepath);
- console.log('');
- return generate();
- });
- });
- });
- };
-
- return Promise.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
- .then(function() {
- console.log('Live reload server started on port:', kwargs.lrport);
- console.log('Press CTRL+C to quit ...');
- console.log('');
- return generate();
- });
- }
- }
-
+ require('./parse'),
+ require('./build'),
+ require('./serve'),
+ require('./install')
]
};
diff --git a/lib/cli/indexe.js b/lib/cli/indexe.js
new file mode 100644
index 0000000..eea707f
--- /dev/null
+++ b/lib/cli/indexe.js
@@ -0,0 +1,199 @@
+/* eslint-disable no-console */
+
+var _ = require('lodash');
+var path = require('path');
+var tinylr = require('tiny-lr');
+
+var Promise = require('../utils/promise');
+var PluginsManager = require('../plugins');
+var Book = require('../book');
+
+var helper = require('./helper');
+var Server = require('./server');
+var watch = require('./watch');
+
+module.exports = {
+ commands: [
+ {
+ name: 'init [book]',
+ description: 'setup and create files for chapters',
+ options: [
+ helper.options.log
+ ],
+ exec: function(args) {
+ var input = path.resolve(args[0] || process.cwd());
+ return Book.init(helper.nodeFS, input);
+ }
+ },
+
+ {
+ name: 'parse [book]',
+ description: 'parse and returns debug information for a book',
+ options: [
+ helper.options.log
+ ],
+ exec: helper.bookCmd(function(book) {
+ return book.parse()
+ .then(function() {
+ book.log.info.ln('Book located in:', book.root);
+ book.log.info.ln('');
+
+ if (book.config.exists()) book.log.info.ln('Configuration:', book.config.path);
+
+ if (book.isMultilingual()) {
+ book.log.info.ln('Multilingual book detected:', book.langs.path);
+ } else {
+ book.log.info.ln('Readme:', book.readme.path);
+ book.log.info.ln('Summary:', book.summary.path);
+ if (book.glossary.exists()) book.log.info.ln('Glossary:', book.glossary.path);
+
+ book.log.info.ln('Pages:');
+ _.each(book.pages, function(page) {
+ book.log.info.ln('\t-', page.path);
+ });
+ }
+ });
+ })
+ },
+
+ {
+ name: 'install [book]',
+ description: 'install all plugins dependencies',
+ options: [
+ helper.options.log
+ ],
+ exec: helper.bookCmd(function(book, args) {
+ var plugins = new PluginsManager(book);
+
+ return book.config.load()
+ .then(function() {
+ return plugins.install();
+ });
+ })
+ },
+
+ {
+ name: 'build [book] [output]',
+ description: 'build a book',
+ options: [
+ helper.options.log,
+ helper.options.format
+ ],
+ exec: helper.outputCmd(function(output, args, kwargs) {
+ return output.book.parse()
+ .then(function() {
+ return output.generate();
+ });
+ })
+ },
+
+ helper.ebookCmd('pdf'),
+ helper.ebookCmd('epub'),
+ helper.ebookCmd('mobi'),
+
+ {
+ name: 'serve [book]',
+ description: 'Build then serve a book from a directory',
+ options: [
+ {
+ name: 'port',
+ description: 'Port for server to listen on',
+ defaults: 4000
+ },
+ {
+ name: 'lrport',
+ description: 'Port for livereload server to listen on',
+ defaults: 35729
+ },
+ {
+ name: 'watch',
+ description: 'Enable/disable file watcher',
+ defaults: true
+ },
+ helper.options.format,
+ helper.options.log
+ ],
+ exec: function(args, kwargs) {
+ var input = path.resolve(args[0] || process.cwd());
+ var server = new Server();
+
+ // Init livereload server
+ var lrServer = tinylr({});
+ var port = kwargs.port;
+ var lrPath;
+
+ var generate = function() {
+
+ // Stop server if running
+ if (server.isRunning()) console.log('Stopping server');
+ return server.stop()
+
+ // Generate the book
+ .then(function() {
+ var book = new Book({
+ fs: helper.nodeFS,
+ root: input,
+ logLevel: kwargs.log
+ });
+
+ return book.parse()
+ .then(function() {
+ // Add livereload plugin
+ book.config.set('plugins',
+ book.config.get('plugins')
+ .concat([
+ { name: 'livereload' }
+ ])
+ );
+
+ var Out = helper.FORMATS[kwargs.format];
+ var output = new Out(book);
+
+ return output.generate()
+ .thenResolve(output);
+ });
+ })
+
+ // Start server and watch changes
+ .then(function(output) {
+ console.log();
+ console.log('Starting server ...');
+ return server.start(output.root(), port)
+ .then(function() {
+ console.log('Serving book on http://localhost:'+port);
+
+ if (lrPath) {
+ // trigger livereload
+ lrServer.changed({
+ body: {
+ files: [lrPath]
+ }
+ });
+ }
+
+ if (!kwargs.watch) return;
+
+ return watch(output.book.root)
+ .then(function(filepath) {
+ // set livereload path
+ lrPath = filepath;
+ console.log('Restart after change in file', filepath);
+ console.log('');
+ return generate();
+ });
+ });
+ });
+ };
+
+ return Promise.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
+ .then(function() {
+ console.log('Live reload server started on port:', kwargs.lrport);
+ console.log('Press CTRL+C to quit ...');
+ console.log('');
+ return generate();
+ });
+ }
+ }
+
+ ]
+};
diff --git a/lib/cli/install.js b/lib/cli/install.js
new file mode 100644
index 0000000..c001711
--- /dev/null
+++ b/lib/cli/install.js
@@ -0,0 +1,21 @@
+var options = require('./options');
+var getBook = require('./getBook');
+
+var Parse = require('../parse');
+var Plugins = require('../plugins');
+
+module.exports = {
+ name: 'install [book]',
+ description: 'install all plugins dependencies',
+ options: [
+ options.log
+ ],
+ exec: function(args, kwargs) {
+ var book = getBook(args, kwargs);
+
+ return Parse.parseConfig(book)
+ .then(function(resultBook) {
+ return Plugins.installPlugins(resultBook);
+ });
+ }
+};
diff --git a/lib/cli/options.js b/lib/cli/options.js
new file mode 100644
index 0000000..26581cb
--- /dev/null
+++ b/lib/cli/options.js
@@ -0,0 +1,23 @@
+var Logger = require('../utils/logger');
+
+var logOptions = {
+ name: 'log',
+ description: 'Minimum log level to display',
+ values: Object.keys(Logger.LEVELS)
+ .map(function(s) {
+ return s.toLowerCase();
+ }),
+ defaults: 'info'
+};
+
+var formatOption = {
+ name: 'format',
+ description: 'Format to build to',
+ values: ['website', 'json', 'ebook'],
+ defaults: 'website'
+};
+
+module.exports = {
+ log: logOptions,
+ format: formatOption
+};
diff --git a/lib/cli/parse.js b/lib/cli/parse.js
new file mode 100644
index 0000000..0421b3e
--- /dev/null
+++ b/lib/cli/parse.js
@@ -0,0 +1,68 @@
+var options = require('./options');
+var getBook = require('./getBook');
+
+var Parse = require('../parse');
+
+function printBook(book) {
+ var logger = book.getLogger();
+
+ var config = book.getConfig();
+ var configFile = config.getFile();
+
+ var summary = book.getSummary();
+ var summaryFile = summary.getFile();
+
+ var readme = book.getReadme();
+ var readmeFile = readme.getFile();
+
+ var glossary = book.getGlossary();
+ var glossaryFile = glossary.getFile();
+
+ if (configFile.exists()) {
+ logger.info.ln('configuration file is', configFile.getPath());
+ }
+
+ if (readmeFile.exists()) {
+ logger.info.ln('Introduction file is', readmeFile.getPath());
+ }
+
+ if (glossaryFile.exists()) {
+ logger.info.ln('Glossary file is', glossaryFile.getPath());
+ }
+
+ if (summaryFile.exists()) {
+ logger.info.ln('Table of Contents file is', summaryFile.getPath());
+ }
+
+ //logger.info.ln('Table of Contents:');
+}
+
+
+module.exports = {
+ name: 'parse [book]',
+ description: 'parse and print debug information about a book',
+ options: [
+ options.log
+ ],
+ exec: function(args, kwargs) {
+ var book = getBook(args, kwargs);
+ var logger = book.getLogger();
+
+ return Parse.parseBook(book)
+ .then(function(resultBook) {
+ var rootFolder = book.getRoot();
+ var contentFolder = book.getContentRoot();
+
+ logger.info.ln('Book located in:', rootFolder);
+ if (contentFolder != rootFolder) {
+ logger.info.ln('Content located in:', contentFolder);
+ }
+
+ if (resultBook.isMultilingual()) {
+
+ } else {
+ printBook(resultBook);
+ }
+ });
+ }
+};
diff --git a/lib/cli/serve.js b/lib/cli/serve.js
new file mode 100644
index 0000000..d97cfed
--- /dev/null
+++ b/lib/cli/serve.js
@@ -0,0 +1,19 @@
+var path = require('path');
+
+var options = require('./options');
+var getBook = require('./getBook');
+
+var Parse = require('../parse');
+var Output = require('../output');
+
+module.exports = {
+ name: 'serve [book] [output]',
+ description: 'serve the book as a website for testing',
+ options: [
+ options.log,
+ options.format
+ ],
+ exec: function(args, kwargs) {
+
+ }
+};
diff --git a/lib/cli/watch.js b/lib/cli/watch.js
index 130b0d4..0d1ab17 100644
--- a/lib/cli/watch.js
+++ b/lib/cli/watch.js
@@ -5,7 +5,12 @@ var chokidar = require('chokidar');
var Promise = require('../utils/promise');
var parsers = require('../parsers');
-// Watch a folder and resolve promise once a file is modified
+/**
+ Watch a folder and resolve promise once a file is modified
+
+ @param {String} dir
+ @return {Promise}
+*/
function watch(dir) {
var d = Promise.defer();
dir = path.resolve(dir);
diff --git a/lib/index.js b/lib/index.js
index 5a3c00e..3a1802a 100644
--- a/lib/index.js
+++ b/lib/index.js
@@ -1,7 +1,9 @@
var Book = require('./models/book');
var Parse = require('./parse');
+var cli = require('./cli');
module.exports = {
Book: Book,
- Parse: Parse
+ Parse: Parse,
+ commands: cli.commands
};
diff --git a/lib/models/config.js b/lib/models/config.js
index 720ac57..547007a 100644
--- a/lib/models/config.js
+++ b/lib/models/config.js
@@ -9,8 +9,8 @@ var Config = Immutable.Record({
values: configDefault
}, 'Config');
-Config.prototype.getPath = function() {
- return this.get('path');
+Config.prototype.getFile = function() {
+ return this.get('file');
};
Config.prototype.getValues = function() {
diff --git a/lib/output/index.js b/lib/output/index.js
index 9112666..9b8ec17 100644
--- a/lib/output/index.js
+++ b/lib/output/index.js
@@ -1,6 +1,24 @@
+var Immutable = require('immutable');
+
+var generators = Immutable.List([
+ require('./json'),
+ require('./website'),
+ require('./ebook')
+]);
+
+/**
+ Return a specific generator by its name
+
+ @param {String}
+ @return {Generator}
+*/
+function getGenerator(name) {
+ return generators.find(function(generator) {
+ return generator.name == name;
+ });
+}
+
module.exports = {
generate: require('./generateBook'),
- JSONGenerator: require('./json'),
- WebsiteGenerator: require('./website'),
- EbookGenerator: require('./ebook')
+ getGenerator: getGenerator
};
diff --git a/lib/plugins/installPlugins.js b/lib/plugins/installPlugins.js
index 77ecfce..05a5316 100644
--- a/lib/plugins/installPlugins.js
+++ b/lib/plugins/installPlugins.js
@@ -3,9 +3,12 @@ var npmi = require('npmi');
var semver = require('semver');
var Immutable = require('immutable');
+var pkg = require('../../package.json');
+var DEFAULT_PLUGINS = require('../constants/defaultPlugins');
var Promise = require('../utils/promise');
var Plugin = require('../models/plugin');
var gitbook = require('../gitbook');
+var listForBook = require('./listForBook');
var npmIsReady;
@@ -42,7 +45,7 @@ function resolveVersion(plugin) {
return Promise.nfcall(npm.commands.view, [npmId + '@' + requiredVersion, 'engines'], true);
})
.then(function(versions) {
- versions = Immutable.Map(versions).entries().toList();
+ versions = Immutable.Map(versions).entrySeq();
var result = versions
.map(function(entry) {
@@ -62,7 +65,7 @@ function resolveVersion(plugin) {
if (!result) {
return undefined;
} else {
- return result.get('version');
+ return result.version;
}
});
}
@@ -82,7 +85,7 @@ function installPlugin(book, plugin) {
var name = plugin.getName();
var requirement = plugin.getVersion();
- logger.info.ln('installing plugin', name);
+ logger.info.ln('installing plugin "' + name + '"');
// Find a version to install
return resolveVersion(plugin)
@@ -91,7 +94,7 @@ function installPlugin(book, plugin) {
throw new Error('Found no satisfactory version for plugin "' + name + '" with requirement "' + requirement + '"');
}
- logger.info.ln('install plugin "' + plugin +'" from NPM with version', requirement);
+ logger.info.ln('install plugin "' + name +'" from NPM with version', requirement);
return Promise.nfcall(npmi, {
'name': plugin.getNpmID(),
'version': version,
@@ -104,7 +107,7 @@ function installPlugin(book, plugin) {
});
})
.then(function() {
- logger.info.ok('plugin "' + plugin + '" installed with success');
+ logger.info.ok('plugin "' + name + '" installed with success');
});
}
@@ -113,10 +116,28 @@ function installPlugin(book, plugin) {
Install plugin requirements for a book
@param {Book}
- @param {OrderedMap<String:Plugin>}
@return {Promise}
*/
-function installPlugins(book, plugins) {
+function installPlugins(book) {
+ var logger = book.getLogger();
+ var plugins = listForBook(book);
+
+ // Remove default plugins
+ // (only if version is same as installed)
+ plugins = plugins.filterNot(function(plugin) {
+ return (
+ DEFAULT_PLUGINS.includes(plugin.getName()) &&
+ plugin.getVersion() === pkg.dependencies[plugin.getNpmID()]
+ );
+ });
+
+ if (plugins.size == 0) {
+ logger.info.ln('nothing to install!');
+ return Promise();
+ }
+
+ logger.info.ln('installing', plugins.size, 'plugins');
+
return Promise.forEach(plugins, function(plugin) {
return installPlugin(book, plugin);
});
diff --git a/lib/plugins/listAll.js b/lib/plugins/listAll.js
index 46eaea0..8a0fc07 100644
--- a/lib/plugins/listAll.js
+++ b/lib/plugins/listAll.js
@@ -2,6 +2,7 @@ var is = require('is');
var Immutable = require('immutable');
var Plugin = require('../models/plugin');
+var pkg = require('../../package.json');
var DEFAULT_PLUGINS = require('../constants/defaultPlugins');
/**
@@ -41,7 +42,8 @@ function listAll(plugins) {
if (plugins.has(pluginName)) return;
plugins = plugins.set(pluginName, new Plugin({
- name: pluginName
+ name: pluginName,
+ version: pkg.dependencies[Plugin.nameToNpmID(pluginName)]
}));
});