Compare commits

...

11 Commits

Author SHA1 Message Date
Aaron O'Mullan d46bd14678 0.4.1 2014-04-29 10:23:54 -07:00
Samy Pessé b3e5b3d106 Fix #183: normalize hooks and transformation of page (content, progress, ..° 2014-04-29 17:45:54 +02:00
Samy Pessé b830ef5dca Merge pull request #179 from erixtekila/master
Update README.md
2014-04-29 08:23:33 +02:00
Eric Priou 45326c4ad2 Update README.md 2014-04-29 03:45:03 +02:00
Aaron O'Mullan 603b61e8c8 Bump version to 0.4.0 2014-04-28 13:26:40 -07:00
Samy Pessé efb066c8e3 Update doc about how to configure gitbook 2014-04-28 20:45:10 +02:00
Samy Pessé c30db427b1 Remove some options from command line (moved to book.json) 2014-04-28 20:33:25 +02:00
Samy Pessé 23056fc85d Use a global configuration file for a book (default to book.json) 2014-04-28 20:29:36 +02:00
Samy Pessé 5f1bfc0280 Fix #163: Move logic of git infos extraction to lib 2014-04-28 20:16:30 +02:00
Samy Pessé b715901f92 Add hooks "page:before" and "page:after" 2014-04-28 19:56:40 +02:00
Samy Pessé 38fea06cf9 Use hook to allow plugins to edit page content during generation (Fixes #176) 2014-04-28 17:21:06 +02:00
10 changed files with 177 additions and 115 deletions
+30 -7
View File
@@ -30,14 +30,37 @@ $ gitbook build ./repository --output=./outputFolder
Options for commands `build` and `serve` are:
```
-t, --title <name> Name of the book to generate, defaults to repo name
-i, --intro <intro> Description of the book to generate
-g, --github <repo_path> ID of github repo like : username/repo
-o, --output <directory> Path to output directory, defaults to ./_book
-f, --format <name> Change generation format, defaults to site, availables are: site, page, pdf, json
--githubHost <url> The url of the github host (defaults to https://github.com/)
--plugins <plugins> List of plugins to use separated by ","
--pluginsConfig <json file> JSON File containing plugins configuration
--config <config file> Configuration file to use, defualt to book.json
```
GitBook load the default configuration from a `book.json` file in the repository if it exists.
Here are the options that can be stored in this file:
```
{
// Folders to use for output (caution: it override the value from the command line)
output: null,
// Generator to use for building (caution: it override the value from the command line)
generator: "site",
// Book title and description (defaults are extracted from the README)
title: null,
description: null,
// GitHub informations (defaults are extracted using git)
github: null,
githubHost: 'https://github.com/',
// Plugins list, can contain "-name" for removing default plugins
plugins: [],
// Global configuration for plugins
pluginsConfig: {}
}
```
You can publish your books to our index by visiting [GitBook.io](http://www.gitbook.io)
@@ -148,5 +171,5 @@ Plugins can used to extend your book functionnalities. Read [GitbookIO/plugin](h
* [Google Analytics](https://github.com/GitbookIO/plugin-ga): Google Analytics tracking for your book
* [Disqus](https://github.com/GitbookIO/plugin-disqus): Disqus comments integration in your book
* [Transform comments to notes](https://github.com/erixtekila/gitbook-plugin-comments): Allow markdown comments to be inserted in HTML output
* [Transform annoted quotes to notes](https://github.com/erixtekila/gitbook-plugin-richquotes): Allow extra markdown markup to render blockquotes as nice notes
* [Send code to console](https://github.com/erixtekila/gitbook-plugin-toconsole): Evaluate javascript blockin the browser inspector's console
+9 -36
View File
@@ -12,12 +12,7 @@ var buildCommand = function(command) {
return command
.option('-o, --output <directory>', 'Path to output directory, defaults to ./_book')
.option('-f, --format <name>', 'Change generation format, defaults to site, availables are: '+_.keys(generators).join(", "))
.option('-t, --title <name>', 'Name of the book to generate, default is extracted from readme')
.option('-i, --intro <intro>', 'Description of the book to generate, default is extracted from readme')
.option('--plugins <plugins>', 'List of plugins to use separated by ","')
.option('--pluginsConfig <json file>', 'JSON File containing plugins configuration')
.option('-g, --github <repo_path>', 'ID of github repo like : username/repo')
.option('--githubHost <url>', 'The url of the github host (defaults to https://github.com/');
.option('--config <config file>', 'Configuration file to use, defualt to book.json')
};
@@ -26,37 +21,15 @@ var makeBuildFunc = function(converter) {
dir = dir || process.cwd();
outputDir = options.output;
// Read plugins config
var pluginsConfig = {};
if (options.pluginsConfig) {
pluginsConfig = JSON.parse(fs.readFileSync(options.pluginsConfig))
}
console.log('Starting build ...');
// Get repo's URL
return utils.gitURL(dir)
.then(function(url) {
// Get ID of repo
return utils.githubID(url);
}, function(err) {
return null;
})
.then(function(repoID) {
return converter(
_.extend({}, options || {}, {
input: dir,
output: outputDir,
title: options.title,
description: options.intro,
github: options.github || repoID,
githubHost: options.githubHost,
generator: options.format,
plugins: options.plugins,
pluginsConfig: pluginsConfig
})
);
})
return converter(
_.extend({}, options || {}, {
input: dir,
output: outputDir,
generator: options.format,
configFile: options.config
})
)
.then(function(output) {
console.log("Successfuly built !");
return output;
-54
View File
@@ -4,60 +4,9 @@ var _ = require('lodash');
var http = require('http');
var send = require('send');
var cp = require('child_process');
var path = require('path');
var url = require('url');
var Gaze = require('gaze').Gaze;
// Get the remote of a given repo
function gitURL(path) {
var d = Q.defer();
cp.exec("git config --get remote.origin.url", {
cwd: path,
env: process.env,
}, function(err, stdout, stderr) {
if(err) {
return d.reject(err);
}
return d.resolve(stdout);
});
return d.promise
.then(function(output) {
return output.replace(/(\r\n|\n|\r)/gm, "");
});
}
// Poorman's parsing
// Parse a git URL to a github ID : username/reponame
function githubID(_url) {
// Remove .git if it's in _url
var sliceEnd = _url.slice(-4) === '.git' ? -4 : _url.length;
// Detect HTTPS repos
var parsed = url.parse(_url);
if(parsed.protocol === 'https:' && parsed.host === 'github.com') {
return parsed.path.slice(1, sliceEnd);
}
// Detect SSH repos
if(_url.indexOf('git@') === 0) {
return _url.split(':', 2)[1].slice(0, sliceEnd);
}
// None found
return null;
}
function titleCase(str)
{
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}
function watch(dir) {
var d = Q.defer();
dir = path.resolve(dir);
@@ -88,9 +37,6 @@ function logError(err) {
// Exports
module.exports = {
gitURL: gitURL,
githubID: githubID,
titleCase: titleCase,
watch: watch,
logError: logError
};
+2 -2
View File
@@ -12,8 +12,8 @@ var BaseGenerator = function(options) {
this.plugins = [];
};
BaseGenerator.prototype.callHook = function(name) {
return this.plugins.hook(name, this);
BaseGenerator.prototype.callHook = function(name, data) {
return this.plugins.hook(name, this, data);
};
BaseGenerator.prototype.loadPlugins = function() {
+32
View File
@@ -31,6 +31,9 @@ var generate = function(options) {
input: null,
output: null,
// Config file (relative to input)
configFile: "book.json",
// Output generator
generator: "site",
@@ -63,6 +66,35 @@ var generate = function(options) {
// Clean output folder
return fs.remove(options.output)
// Read config file
.then(function() {
return fs.readFile(path.resolve(options.input, options.configFile))
.then(function(_config) {
// Extend current config
_config = JSON.parse(_config);
_config = _.omit(_config, 'input', 'configFile');
_.extend(options, _config);
}, function() {
// No config file: not a big deal
return Q();
})
})
// Get repo's URL
.then(function() {
return parse.git.url(options.input)
.then(function(_url) {
// Get ID of repo
return parse.git.githubID(_url);
}, function(err) {
return null;
})
.then(function(repoId) {
options.github = options.github || repoId;
});
})
.then(function() {
return fs.mkdirp(options.output);
})
+8 -8
View File
@@ -74,15 +74,15 @@ Plugin.prototype.resolveFile = function(filename) {
};
// Resolve file path
Plugin.prototype.callHook = function(name, args) {
Plugin.prototype.callHook = function(name, context, data) {
var hookFunc = this.infos.hooks? this.infos.hooks[name] : null;
args = _.isArray(args) ? args : [args];
data = data || {};
if (!hookFunc) return Q();
if (!hookFunc) return Q(data);
return Q()
.then(function() {
return hookFunc.apply(null, args);
return hookFunc.apply(context, [data]);
});
};
@@ -159,12 +159,12 @@ Plugin.fromList = function(names, root) {
return Q({
'list': plugins,
'resources': resources,
'hook': function(name, args) {
'hook': function(name, context, data) {
return _.reduce(plugins, function(prev, plugin) {
return prev.then(function() {
return plugin.callHook(name, args);
return prev.then(function(ret) {
return plugin.callHook(name, context, ret);
})
}, Q());
}, Q(data));
},
'template': function(name) {
var withTpl = _.find(plugins, function(plugin) {
+37 -6
View File
@@ -59,8 +59,11 @@ Generator.prototype.loadPlugins = function() {
};
// Generate a template
Generator.prototype._writeTemplate = function(tpl, options, output) {
Generator.prototype._writeTemplate = function(tpl, options, output, interpolate) {
var that = this;
interpolate = interpolate || _.identity;
return Q()
.then(function(sections) {
return tpl(_.extend({
@@ -80,6 +83,7 @@ Generator.prototype._writeTemplate = function(tpl, options, output) {
pluginsConfig: JSON.stringify(that.options.pluginsConfig)
}, options));
})
.then(interpolate)
.then(function(html) {
return fs.writeFile(
output,
@@ -96,7 +100,6 @@ Generator.prototype.indexPage = function(lexed, pagePath) {
// Convert a markdown file to html
Generator.prototype.convertFile = function(content, _input) {
var that = this;
var progress = parse.progress(this.options.navigation, _input);
_output = _input.replace(".md", ".html");
if (_output == "README.html") _output = "index.html";
@@ -105,10 +108,28 @@ Generator.prototype.convertFile = function(content, _input) {
var output = path.join(this.options.output, _output);
var basePath = path.relative(path.dirname(output), this.options.output) || ".";
var page = {
path: _input,
content: content,
progress: parse.progress(this.options.navigation, _input)
};
var _callHook = function(name) {
return that.callHook("page:before", page)
.then(function(_page) {
page = _page;
return page;
});
};
return Q()
.then(function() {
// Send content to plugins
return _callHook("page:before");
})
.then(function() {
// Lex page
return parse.lex(content);
return parse.lex(page.content);
})
.then(function(lexed) {
// Index page in search
@@ -124,17 +145,27 @@ Generator.prototype.convertFile = function(content, _input) {
});
})
.then(function(sections) {
page.sections = sections;
// Use plugin hook
return _callHook("page");
})
.then(function() {
that.manifest.add("CACHE", _output);
return that._writeTemplate(that.template, {
progress: progress,
progress: page.progress,
_input: _input,
content: sections,
content: page.sections,
basePath: basePath,
staticBase: path.join(basePath, "gitbook"),
}, output);
}, output, function(html) {
page.content = html;
return _callHook("page:after").get("content")
});
});
};
+56
View File
@@ -0,0 +1,56 @@
var Q = require('q');
var _ = require('lodash');
var cp = require('child_process');
var url = require('url');
// Get the remote of a given repo
function gitURL(path) {
var d = Q.defer();
cp.exec("git config --get remote.origin.url", {
cwd: path,
env: process.env,
}, function(err, stdout, stderr) {
if(err) {
return d.reject(err);
}
return d.resolve(stdout);
});
return d.promise
.then(function(output) {
return output.replace(/(\r\n|\n|\r)/gm, "");
});
}
// Poorman's parsing
// Parse a git URL to a github ID : username/reponame
function githubID(_url) {
// Remove .git if it's in _url
var sliceEnd = _url.slice(-4) === '.git' ? -4 : _url.length;
// Detect HTTPS repos
var parsed = url.parse(_url);
if(parsed.protocol === 'https:' && parsed.host === 'github.com') {
return parsed.path.slice(1, sliceEnd);
}
// Detect SSH repos
if(_url.indexOf('git@') === 0) {
return _url.split(':', 2)[1].slice(0, sliceEnd);
}
// None found
return null;
}
function titleCase(str) {
return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
}
module.exports = {
url: gitURL,
githubID: githubID,
titleCase: titleCase
};
+2 -1
View File
@@ -5,5 +5,6 @@ module.exports = {
lex: require('./lex'),
progress: require('./progress'),
navigation: require('./navigation'),
readme: require('./readme')
readme: require('./readme'),
git: require('./git')
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "gitbook",
"version": "0.3.2",
"version": "0.4.1",
"homepage": "http://www.gitbook.io/",
"description": "Library and cmd utility to generate GitBooks",
"main": "lib/index.js",