Compare commits

...

16 Commits

Author SHA1 Message Date
Samy Pessé 44a3bfe296 Bump version to 1.4.0 2014-11-30 14:59:08 +01:00
Samy Pessé a9ce6f808d Add doc about gitbook install 2014-11-30 14:54:34 +01:00
Samy Pessé e5c667e0fa Add test for parsing of plugins list with version 2014-11-30 14:50:47 +01:00
Samy Pessé e36f274dbe Handle specific version for plugins 2014-11-30 14:46:21 +01:00
Samy Pessé 2a88427e74 Improve error message when plugins not found 2014-11-30 13:13:00 +01:00
Samy Pessé ed48f5f3ee Add command "install" to install plugins from book.json 2014-11-30 13:04:38 +01:00
Samy Pessé 7b4accb117 Bump version to 1.3.4 2014-11-25 18:55:33 +01:00
Samy Pessé d6437d31d4 Omit "generator" when building file with config file 2014-11-25 18:53:02 +01:00
Samy Pessé 3dd33f1f3c Merge pull request #502 from tonka3000/X-UA-Compatible-tag
add X-UA-Compatible meta tag for IE
2014-11-25 15:20:14 +01:00
Samy Pessé 3a0f00411b Fix #505: add glossary to ebook file 2014-11-24 22:08:19 +01:00
Samy Pessé 5b655bb29a Fx typo 2014-11-24 21:56:33 +01:00
Samy Pessé faf10605e8 Add hook finish:before 2014-11-24 21:41:50 +01:00
Samy Pessé 5c98b3350b Merge pull request #503 from jr0cket/ebook-command-fix
updated eBook generation commands - resolves #432
2014-11-22 16:41:19 +01:00
John Stevenson 6f4e1d10c1 made commands clearer by seperating output filename option 2014-11-22 14:47:12 +00:00
John Stevenson 870886599a updated eBook generation commands 2014-11-22 11:26:08 +00:00
Michael Aigner 1b9801b8a4 add X-UA-Compatible meta tag for IE (https://github.com/GitbookIO/gitbook/issues/501) 2014-11-20 10:16:40 +01:00
12 changed files with 178 additions and 44 deletions
+9
View File
@@ -1,5 +1,14 @@
# Release notes
## 1.4.0
- Add command `gitbook install` to install plugins from book.json
- `package.json` is no longer necessary
## 1.3.4
- Add glossary to ebooks
- Fix autocover with new hook "finish:before"
- Add X-UA-Compatible meta tag for IE
## 1.3.3
- Fix parsing of lexed content using the client library
+6 -1
View File
@@ -132,7 +132,10 @@ You can publish your books to our index by visiting [GitBook.io](http://www.gitb
GitBook can generate your book in the following formats:
* **Static Website**: This is the default format. It generates a complete interactive static website that can be, for example, hosted on GitHub Pages.
* **eBook**: A complete eBook with exercise solutions at the end of the book. Generate this format using: ```gitbook ebook ./myrepo```. You need to have [ebook-convert](http://manual.calibre-ebook.com/cli/ebook-convert.html) installed. The output format could be **PDF**, **ePub** or **MOBI**.
* **eBook**: A complete eBook with exercise solutions at the end of the book. You need to have [ebook-convert](http://manual.calibre-ebook.com/cli/ebook-convert.html) installed. You can specify the eBook filename with the `-o` option, otherwise `book` will be used.
* Generate a **PDF** using: `gitbook pdf ./myrepo`
* Generate a **ePub** using: `gitbook epub ./myrepo`
* Generate a **MOBI** using: `gitbook mobi ./myrepo`
* **JSON**: This format is used for debugging or extracting metadata from a book. Generate this format using: ```gitbook build ./myrepo -f json```.
## Book Format
@@ -211,6 +214,8 @@ The platform [GitBook.io](https://www.gitbook.io/) is like an "Heroku for books"
Plugins can be used to extend your book's functionality. Read [GitbookIO/plugin](https://github.com/GitbookIO/plugin) for more information about how to build a plugin for GitBook.
Plugins needed to build a book can be installed using: `gitbook install ./`.
##### Official plugins:
| Name | Description |
+23 -1
View File
@@ -7,7 +7,7 @@ var prog = require('commander');
var tinylr = require('tiny-lr-fork');
var pkg = require('../package.json');
var generators = require("../lib/generate").generators;
var genbook = require("../lib/generate");
var initDir = require("../lib/generate/init");
var fs = require('../lib/generate/fs');
@@ -80,6 +80,28 @@ build.command(prog.command('serve [source_dir]'))
generate();
});
build.commandEbook(prog.command('install [source_dir]'))
.description('Install plugins for a book')
.action(function(dir, options) {
console.log("Install plugins in", dir);
genbook.config.read({
input: dir
})
.then(function(options) {
return genbook.Plugin.install(options);
})
.then(function() {
console.log("Successfully installed plugins!");
})
.fail(function(err) {
// Log error
utils.logError(err);
// Exit process with failure code
process.exit(-1);
});
});
build.commandEbook(prog.command('pdf [source_dir]'))
.description('Build a gitbook as a PDF')
.action(function(dir, options) {
+26 -3
View File
@@ -1,3 +1,4 @@
var Q = require('q');
var _ = require('lodash');
var path = require('path');
@@ -96,10 +97,32 @@ var CONFIG = {
}
};
// Return complete configuration
var defaultsConfig = function(options) {
return _.merge(options || {}, CONFIG, _.defaults);
};
// Read configuration from book.json
var readConfig = function(options) {
options = defaultsConfig(options);
return Q()
.then(function() {
try {
var _config = require(path.resolve(options.input, options.configFile));
options = _.merge(options, _.omit(_config, 'input', 'configFile', 'defaultsPlugins', 'generator'));
}
catch(err) {
// No config file: not a big deal
return Q();
}
})
.thenResolve(options);
};
module.exports = {
CONFIG: CONFIG,
defaults: function(options) {
return _.merge(options || {}, CONFIG, _.defaults);
}
defaults: defaultsConfig,
read: readConfig
}
+16 -20
View File
@@ -48,28 +48,18 @@ var loadGenerator = function(options) {
var generate = function(options) {
// Set defaults to options
options = defaultConfig.defaults(options);
// Validate options
if (!options.input) {
return Q.reject(new Error("Need option input (book input directory)"));
}
// Check files to get folder type (book, multilanguage book or neither)
return checkGenerator(options)
// Read config file
.then(function() {
try {
var _config = require(path.resolve(options.input, options.configFile));
return defaultConfig.read(options)
.then(function(_options) {
options = _options;
options = _.merge(options, _.omit(_config, 'input', 'configFile', 'defaultsPlugins'));
}
catch(err) {
// No config file: not a big deal
return Q();
// Validate options
if (!options.input) {
return Q.reject(new Error("Need option input (book input directory)"));
}
// Check files to get folder type (book, multilanguage book or neither)
return checkGenerator(options);
})
// Read readme
@@ -99,7 +89,9 @@ var generate = function(options) {
});
};
/*
* Generate a multilanguage book by generating a book for each folder.
*/
var generateMultiLang = function(options) {
var langsSummary;
options.output = options.output || path.join(options.input, "_book");
@@ -297,6 +289,9 @@ var generateBook = function(options) {
})
// Finish generation
.then(function() {
return generator.callHook("finish:before");
})
.then(function() {
return generator.finish();
})
@@ -375,4 +370,5 @@ module.exports = {
file: generateFile,
book: generateBook,
Plugin: Plugin,
config: defaultConfig
};
+9 -1
View File
@@ -26,6 +26,9 @@ Generator.prototype.loadTemplates = function() {
this.summaryTemplate = swig.compileFile(
this.plugins.template("ebook:sumary") || path.resolve(this.options.theme, 'templates/ebook/summary.html')
);
this.glossaryTemplate = swig.compileFile(
this.plugins.template("ebook:glossary") || path.resolve(this.options.theme, 'templates/ebook/glossary.html')
);
};
// Generate table of contents
@@ -46,7 +49,7 @@ Generator.prototype.finish = function() {
var output = path.join(this.options.output, "index.html");
var progress = parse.progress(this.options.navigation, "README.md");
return Q()
// Write table of contents
@@ -54,6 +57,11 @@ Generator.prototype.finish = function() {
return that.writeToc();
})
// Write glossary
.then(function() {
return that.writeGlossary();
})
// Copy cover
.then(function() {
return that.copyCover();
+57 -16
View File
@@ -4,6 +4,7 @@ var semver = require("semver");
var path = require("path");
var url = require("url");
var fs = require("./fs");
var npmi = require('npmi');
var resolve = require('resolve');
var pkg = require("../../package.json");
@@ -152,33 +153,73 @@ Plugin.prototype.copyAssets = function(out, options) {
};
// Normalize a list of plugin name to use
Plugin.normalizeNames = function(names) {
// Install a list of plugin
Plugin.install = function(options) {
// Normalize list of plugins
var plugins = Plugin.normalizeList(options.plugins);
// Install plugins one by one
return _.reduce(plugins, function(prev, plugin) {
return prev.then(function() {
var fullname = "gitbook-plugin-"+plugin.name;
console.log("Install plugin", plugin.name, "from npm ("+fullname+") with version", (plugin.version || "*"));
return Q.nfcall(npmi, {
'name': fullname,
'version': plugin.version,
'path': options.input,
'npmLoad': {
'loglevel': 'silent',
'loaded': false,
'prefix': options.input
}
});
});
}, Q());
};
// Normalize a list of plugins to use
Plugin.normalizeList = function(plugins) {
// Normalize list to an array
names = _.isString(names) ? names.split(",") : (names || []);
plugins = _.isString(plugins) ? plugins.split(",") : (plugins || []);
// Divide as {name, version} to handle format like "myplugin@1.0.0"
plugins = _.map(plugins, function(plugin) {
var parts = plugin.split("@");
return {
'name': parts[0],
'version': parts[1] // optional
}
});
// List plugins to remove
var toremove = _.chain(names)
.filter(function(name) {
return name.length > 0 && name[0] == "-";
var toremove = _.chain(plugins)
.filter(function(plugin) {
return plugin.name.length > 0 && plugin.name[0] == "-";
})
.map(function(name) {
return name.slice(1);
.map(function(plugin) {
return plugin.name.slice(1);
})
.value();
// Merge with defaults
names = _.chain(names)
.concat(Plugin.defaults)
plugins = _.chain(plugins)
.concat(_.map(Plugin.defaults, function(plugin) {
return { 'name': plugin }
}))
.uniq()
.value();
// Remove plugins starting with
names = _.filter(names, function(name) {
return !_.contains(toremove, name) && !(name.length > 0 && name[0] == "-");
// Build final list
plugins = _.filter(plugins, function(plugin) {
return !_.contains(toremove, plugin.name) && !(plugin.name.length > 0 && plugin.name[0] == "-");
});
return names;
return plugins;
};
// Normalize a list of plugin name to use
Plugin.normalizeNames = function(plugins) {
return _.pluck(Plugin.normalizeList(plugins), "name");
};
// Extract data from a list of plugin
@@ -196,7 +237,7 @@ Plugin.fromList = function(names, root, generator, options) {
return plugin;
});
if (_.size(failed) > 0) return Q.reject(new Error("Error loading plugins: "+failed.join(",")));
if (_.size(failed) > 0) return Q.reject(new Error("Error loading plugins: "+failed.join(",")+". Run 'gitbook install' to install plugins from NPM."));
// The raw resources extracted from each plugin
var pluginResources;
@@ -276,7 +317,7 @@ Plugin.fromList = function(names, root, generator, options) {
});
};
// Default plugins
// Default plugins added to each books
Plugin.defaults = [
"mathjax"
];
+2 -1
View File
@@ -1,6 +1,6 @@
{
"name": "gitbook",
"version": "1.3.3",
"version": "1.4.0",
"homepage": "http://www.gitbook.io/",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",
@@ -19,6 +19,7 @@
"highlight.js": "8.3.0",
"tmp": "0.0.23",
"semver": "2.2.1",
"npmi": "0.1.1",
"gaze": "~0.5.1",
"resolve": "0.6.3",
"tiny-lr-fork": "0.0.5",
+10 -1
View File
@@ -12,7 +12,7 @@ describe('Plugin validation', function () {
});
});
describe('Plugin list of names', function () {
describe('Plugins list', function () {
var firstDefault = _.first(Plugin.defaults);
it('should convert string to array', function() {
@@ -27,6 +27,15 @@ describe('Plugin list of names', function () {
it('should remove name starting with -', function() {
assert(!_.contains(Plugin.normalizeNames(["-"+firstDefault]), firstDefault));
});
it('should accept version', function() {
var _name = "test@0.3.0,exercises@1.2.0,test2";
var plugins = Plugin.normalizeList(_name);
assert(_.find(plugins, {'name': "test"}).version = "0.3.0");
assert(_.find(plugins, {'name': "exercises"}).version = "1.2.0");
assert(!_.find(plugins, {'name': "test2"}).version);
});
});
describe('Plugin defaults loading', function () {
+15
View File
@@ -0,0 +1,15 @@
{% extends "./layout.html" %}
{% block title %}Glossary | {{ title }}{% endblock %}
{% block content %}
<div class="page page-toc">
<h1>Glossary</h1>
{% for item in glossaryIndex %}
<section class="normal glossary" id="{{ item.id }}">
<h2><a href="#{{ item.id }}">{{ item.name }}</a></h2>
<p>{{ item.description }}</p>
</section>
{% endfor %}
</div>
{% endblock %}
+4
View File
@@ -40,6 +40,10 @@
<h1>Table of Contents</h1>
<ol>
{{ articles(summary.chapters) }}
{% if glossary.length > 0 %}
<li><a href="{{ basePath }}/GLOSSARY.html">Glossary</a></li>
{% endif %}
</ol>
</div>
{% endblock %}
+1
View File
@@ -4,6 +4,7 @@
<head>
{{ htmlSnippet("head:start")|default("") }}
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=11; IE=10; IE=9; IE=8; IE=7; IE=EDGE" />
<title>{% block title %}{% endblock %}</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="{% block description %}{% endblock %}">