summaryrefslogtreecommitdiffstats
path: root/lib/cli
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cli')
-rw-r--r--lib/cli/build.js34
-rw-r--r--lib/cli/buildEbook.js76
-rw-r--r--lib/cli/getBook.js23
-rw-r--r--lib/cli/getOutputFolder.js17
-rw-r--r--lib/cli/helper.js140
-rw-r--r--lib/cli/index.js211
-rw-r--r--lib/cli/init.js17
-rw-r--r--lib/cli/install.js21
-rw-r--r--lib/cli/options.js30
-rw-r--r--lib/cli/parse.js79
-rw-r--r--lib/cli/serve.js93
-rw-r--r--lib/cli/server.js21
-rw-r--r--lib/cli/watch.js7
13 files changed, 425 insertions, 344 deletions
diff --git a/lib/cli/build.js b/lib/cli/build.js
new file mode 100644
index 0000000..023901e
--- /dev/null
+++ b/lib/cli/build.js
@@ -0,0 +1,34 @@
+var Parse = require('../parse');
+var Output = require('../output');
+var timing = require('../utils/timing');
+
+var options = require('./options');
+var getBook = require('./getBook');
+var getOutputFolder = require('./getOutputFolder');
+
+
+module.exports = {
+ name: 'build [book] [output]',
+ description: 'build a book',
+ options: [
+ options.log,
+ options.format,
+ options.timing
+ ],
+ exec: function(args, kwargs) {
+ var book = getBook(args, kwargs);
+ var outputFolder = getOutputFolder(args);
+
+ var Generator = Output.getGenerator(kwargs.format);
+
+ return Parse.parseBook(book)
+ .then(function(resultBook) {
+ return Output.generate(Generator, resultBook, {
+ root: outputFolder
+ });
+ })
+ .fin(function() {
+ if (kwargs.timing) timing.dump(book.getLogger());
+ });
+ }
+};
diff --git a/lib/cli/buildEbook.js b/lib/cli/buildEbook.js
new file mode 100644
index 0000000..405d838
--- /dev/null
+++ b/lib/cli/buildEbook.js
@@ -0,0 +1,76 @@
+var path = require('path');
+var tmp = require('tmp');
+
+var Promise = require('../utils/promise');
+var fs = require('../utils/fs');
+var Parse = require('../parse');
+var Output = require('../output');
+
+var options = require('./options');
+var getBook = require('./getBook');
+
+
+module.exports = function(format) {
+ return {
+ name: (format + ' [book] [output]'),
+ description: 'build a book into an ebook file',
+ options: [
+ options.log
+ ],
+ exec: function(args, kwargs) {
+ // Output file will be stored in
+ var outputFile = args[1] || ('book.' + format);
+
+ // Create temporary directory
+ var outputFolder = tmp.dirSync().name;
+
+ var book = getBook(args, kwargs);
+ var logger = book.getLogger();
+ var Generator = Output.getGenerator('ebook');
+
+ return Parse.parseBook(book)
+ .then(function(resultBook) {
+ return Output.generate(Generator, resultBook, {
+ root: outputFolder,
+ format: format
+ });
+ })
+
+ // Extract ebook file
+ .then(function(output) {
+ var book = output.getBook();
+ var languages = book.getLanguages();
+
+ if (book.isMultilingual()) {
+ return Promise.ForEach(languages, function(lang) {
+ var langID = lang.getID();
+
+ var langOutputFile = path.join(
+ path.dirname(outputFile),
+ path.basename(outputFile, format) + '_' + langID + '.' + format
+ );
+
+ return fs.copy(
+ path.resolve(outputFolder, langID, 'index.' + format),
+ langOutputFile
+ );
+ })
+ .thenResolve(languages.getCount());
+ } else {
+ return fs.copy(
+ path.resolve(outputFolder, 'index.' + format),
+ outputFile
+ ).thenResolve(1);
+ }
+ })
+
+ // Log end
+ .then(function(count) {
+ logger.info.ok(count + ' file(s) generated');
+
+ logger.debug('cleaning up... ');
+ return logger.debug.promise(fs.rmDir(outputFolder));
+ });
+ }
+ };
+};
diff --git a/lib/cli/getBook.js b/lib/cli/getBook.js
new file mode 100644
index 0000000..ac82187
--- /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.setLogLevel(logLevel);
+}
+
+module.exports = getBook;
diff --git a/lib/cli/getOutputFolder.js b/lib/cli/getOutputFolder.js
new file mode 100644
index 0000000..272dff9
--- /dev/null
+++ b/lib/cli/getOutputFolder.js
@@ -0,0 +1,17 @@
+var path = require('path');
+
+/**
+ Return path to output folder
+
+ @param {Array} args
+ @return {String}
+*/
+function getOutputFolder(args) {
+ var bookRoot = path.resolve(args[0] || process.cwd());
+ var defaultOutputRoot = path.join(bookRoot, '_book');
+ var outputFolder = args[1]? path.resolve(process.cwd(), args[1]) : defaultOutputRoot;
+
+ return outputFolder;
+}
+
+module.exports = getOutputFolder;
diff --git a/lib/cli/helper.js b/lib/cli/helper.js
deleted file mode 100644
index 02cede6..0000000
--- a/lib/cli/helper.js
+++ /dev/null
@@ -1,140 +0,0 @@
-var _ = require('lodash');
-var path = require('path');
-
-var Book = require('../book');
-var NodeFS = require('../fs/node');
-var Logger = require('../utils/logger');
-var Promise = require('../utils/promise');
-var fs = require('../utils/fs');
-var JSONOutput = require('../output/json');
-var WebsiteOutput = require('../output/website');
-var EBookOutput = require('../output/ebook');
-
-var nodeFS = new NodeFS();
-
-var LOG_OPTION = {
- name: 'log',
- description: 'Minimum log level to display',
- values: _.chain(Logger.LEVELS)
- .keys()
- .map(function(s) {
- return s.toLowerCase();
- })
- .value(),
- defaults: 'info'
-};
-
-var FORMAT_OPTION = {
- name: 'format',
- description: 'Format to build to',
- values: ['website', 'json', 'ebook'],
- defaults: 'website'
-};
-
-var FORMATS = {
- json: JSONOutput,
- website: WebsiteOutput,
- ebook: EBookOutput
-};
-
-// Commands which is processing a book
-// the root of the book is the first argument (or current directory)
-function bookCmd(fn) {
- return function(args, kwargs) {
- var input = path.resolve(args[0] || process.cwd());
- var book = new Book({
- fs: nodeFS,
- root: input,
- logLevel: kwargs.log
- });
-
- return fn(book, args.slice(1), kwargs);
- };
-}
-
-// Commands which is working on a Output instance
-function outputCmd(fn) {
- return bookCmd(function(book, args, kwargs) {
- var Out = FORMATS[kwargs.format];
- var outputFolder = undefined;
-
- // Set output folder
- if (args[0]) {
- outputFolder = path.resolve(process.cwd(), args[0]);
- }
-
- return fn(new Out(book, {
- root: outputFolder
- }), args);
- });
-}
-
-// Command to generate an ebook
-function ebookCmd(format) {
- return {
- name: format + ' [book] [output] [file]',
- description: 'generates ebook '+format,
- options: [
- LOG_OPTION
- ],
- exec: bookCmd(function(book, args, kwargs) {
- return fs.tmpDir()
- .then(function(dir) {
- var ext = '.'+format;
- var outputFile = path.resolve(process.cwd(), args[0] || ('book' + ext));
- var output = new EBookOutput(book, {
- root: dir,
- format: format
- });
-
- return output.book.parse()
- .then(function() {
- return output.generate();
- })
-
- // Copy the ebook files
- .then(function() {
- if (output.book.isMultilingual()) {
- return Promise.serie(output.book.langs.list(), function(lang) {
- var _outputFile = path.join(
- path.dirname(outputFile),
- path.basename(outputFile, ext) + '_' + lang.id + ext
- );
-
- return fs.copy(
- path.resolve(dir, lang.id, 'index' + ext),
- _outputFile
- );
- })
- .thenResolve(output.book.langs.count());
- } else {
- return fs.copy(
- path.resolve(dir, 'index' + ext),
- outputFile
- ).thenResolve(1);
- }
- })
- .then(function(n) {
- output.book.log.info.ok(n+' file(s) generated');
-
- output.book.log.info('cleaning up... ');
- return output.book.log.info.promise(fs.rmDir(dir));
- });
- });
- })
- };
-}
-
-module.exports = {
- nodeFS: nodeFS,
- bookCmd: bookCmd,
- outputCmd: outputCmd,
- ebookCmd: ebookCmd,
-
- options: {
- log: LOG_OPTION,
- format: FORMAT_OPTION
- },
-
- FORMATS: FORMATS
-};
diff --git a/lib/cli/index.js b/lib/cli/index.js
index eea707f..f1fca1d 100644
--- a/lib/cli/index.js
+++ b/lib/cli/index.js
@@ -1,199 +1,12 @@
-/* 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();
- });
- }
- }
-
- ]
-};
+var buildEbook = require('./buildEbook');
+
+module.exports = [
+ require('./build'),
+ require('./serve'),
+ require('./install'),
+ require('./parse'),
+ require('./init'),
+ buildEbook('pdf'),
+ buildEbook('epub'),
+ buildEbook('mobi')
+];
diff --git a/lib/cli/init.js b/lib/cli/init.js
new file mode 100644
index 0000000..9a1bff8
--- /dev/null
+++ b/lib/cli/init.js
@@ -0,0 +1,17 @@
+var path = require('path');
+
+var options = require('./options');
+var initBook = require('../init');
+
+module.exports = {
+ name: 'install [book]',
+ description: 'setup and create files for chapters',
+ options: [
+ options.log
+ ],
+ exec: function(args, kwargs) {
+ var bookRoot = path.resolve(process.cwd(), args[0] || './');
+
+ return initBook(bookRoot);
+ }
+};
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..ddcb5c5
--- /dev/null
+++ b/lib/cli/options.js
@@ -0,0 +1,30 @@
+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'
+};
+
+var timingOption = {
+ name: 'timing',
+ description: 'Print timing debug information',
+ defaults: false
+};
+
+module.exports = {
+ log: logOptions,
+ format: formatOption,
+ timing: timingOption
+};
diff --git a/lib/cli/parse.js b/lib/cli/parse.js
new file mode 100644
index 0000000..0fa509a
--- /dev/null
+++ b/lib/cli/parse.js
@@ -0,0 +1,79 @@
+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());
+ }
+}
+
+function printMultingualBook(book) {
+ var logger = book.getLogger();
+ var languages = book.getLanguages();
+ var books = book.getBooks();
+
+ logger.info.ln(languages.size + ' languages');
+
+ languages.forEach(function(lang) {
+ logger.info.ln('Language:', lang.getTitle());
+ printBook(books.get(lang.getID()));
+ logger.info.ln('');
+ });
+}
+
+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()) {
+ printMultingualBook(resultBook);
+ } else {
+ printBook(resultBook);
+ }
+ });
+ }
+};
diff --git a/lib/cli/serve.js b/lib/cli/serve.js
new file mode 100644
index 0000000..628f591
--- /dev/null
+++ b/lib/cli/serve.js
@@ -0,0 +1,93 @@
+/* eslint-disable no-console */
+
+var tinylr = require('tiny-lr');
+
+var Parse = require('../parse');
+var Output = require('../output');
+
+var options = require('./options');
+var getBook = require('./getBook');
+var getOutputFolder = require('./getOutputFolder');
+var Server = require('./server');
+var watch = require('./watch');
+
+var server, lrServer, lrPath;
+
+function generateBook(args, kwargs) {
+ var port = kwargs.port;
+ var outputFolder = getOutputFolder(args);
+ var book = getBook(args, kwargs);
+ var Generator = Output.getGenerator(kwargs.format);
+
+ // Stop server if running
+ if (server.isRunning()) console.log('Stopping server');
+
+ return server.stop()
+ .then(function() {
+ return Parse.parseBook(book)
+ .then(function(resultBook) {
+ return Output.generate(Generator, resultBook, {
+ root: outputFolder
+ });
+ });
+ })
+ .then(function() {
+ console.log();
+ console.log('Starting server ...');
+ return server.start(outputFolder, port);
+ })
+ .then(function() {
+ console.log('Serving book on http://localhost:'+port);
+
+ if (lrPath) {
+ // trigger livereload
+ lrServer.changed({
+ body: {
+ files: [lrPath]
+ }
+ });
+ }
+ })
+ .then(function() {
+ if (!kwargs.watch) return;
+
+ return watch(book.getRoot())
+ .then(function(filepath) {
+ // set livereload path
+ lrPath = filepath;
+ console.log('Restart after change in file', filepath);
+ console.log('');
+ return generateBook(args, kwargs);
+ });
+ });
+}
+
+module.exports = {
+ name: 'serve [book] [output]',
+ description: 'serve the book as a website for testing',
+ 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
+ },
+ options.log,
+ options.format
+ ],
+ exec: function(args, kwargs) {
+ server = new Server();
+ lrServer = tinylr({});
+
+ return generateBook(args, kwargs);
+ }
+};
diff --git a/lib/cli/server.js b/lib/cli/server.js
index 8d3d7ce..555bbb7 100644
--- a/lib/cli/server.js
+++ b/lib/cli/server.js
@@ -6,20 +6,28 @@ var url = require('url');
var Promise = require('../utils/promise');
-var Server = function() {
+function Server() {
this.running = null;
this.dir = null;
this.port = 0;
this.sockets = [];
-};
+}
util.inherits(Server, events.EventEmitter);
-// Return true if the server is running
+/**
+ Return true if the server is running
+
+ @return {Boolean}
+*/
Server.prototype.isRunning = function() {
return !!this.running;
};
-// Stop the server
+/**
+ Stop the server
+
+ @return {Promise}
+*/
Server.prototype.stop = function() {
var that = this;
if (!this.isRunning()) return Promise();
@@ -40,6 +48,11 @@ Server.prototype.stop = function() {
return d.promise;
};
+/**
+ Start the server
+
+ @return {Promise}
+*/
Server.prototype.start = function(dir, port) {
var that = this, pre = Promise();
port = port || 8004;
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);