Merge pull request #42 from GitbookIO/feature/ebook

Fix #10: Add generation to ebook
This commit is contained in:
Samy Pessé
2014-04-06 22:28:17 -07:00
5 changed files with 161 additions and 61 deletions
+1
View File
@@ -46,6 +46,7 @@ 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.
* **PDF**: A complete PDF book with exercise solutions at the end of the book. Generate to this format using: ```gitbook pdf ./myrepo```, you need to have [gitbook-pdf](https://github.com/GitbookIO/gitbook-pdf) installed.
* **eBook**: A complete eBook with exercise solutions at the end of the book. Generate to this format using: ```gitbook ebook ./myrepo```, you need to have [ebook-convert](http://manual.calibre-ebook.com/cli/ebook-convert.html) installed.
* **Single Page**: The book will be stored in a single printable HTML page, this format is used for conversion to PDF or eBook. Generate to this format using: ```gitbook build ./myrepo -f page```.
* **JSON**: This format is used for debugging or extracting metadata from a book. Generate to this format using: ```gitbook build ./myrepo -f json```.
+62 -3
View File
@@ -1,11 +1,13 @@
var path = require('path');
var Q = require('q');
var _ = require('lodash');
var tmp = require('tmp');
var utils = require('./utils');
var generate = require("../lib/generate");
var parse = require("../lib/parse");
var fs = require('../lib/generate/fs');
var generators = require("../lib/generate").generators;
var buildFunc = function(dir, options) {
@@ -34,7 +36,7 @@ var buildFunc = function(dir, options) {
var title = options.title || utils.titleCase(repo);
return generate.folder(
{
_.extend(options.options || {}, {
input: dir,
output: outputDir,
title: title,
@@ -42,7 +44,7 @@ var buildFunc = function(dir, options) {
github: githubID,
generator: options.format,
theme: options.theme
}
})
);
})
.then(function(output) {
@@ -51,4 +53,61 @@ var buildFunc = function(dir, options) {
}, utils.logError);
};
module.exports = buildFunc;
var buildFiles = function(dir, outputFile, options, masterOptions) {
var ext = masterOptions.extension;
outputFile = outputFile || path.resolve(dir, "book."+ext);
Q.nfcall(tmp.dir)
.then(function(tmpDir) {
return buildFunc(
dir,
_.extend(options, {
output: tmpDir,
format: masterOptions.format,
options: masterOptions.options
})
)
.then(function(_options) {
var copyPDF = function(lang) {
var _outputFile = outputFile;
var _tmpDir = tmpDir;
if (lang) {
_outputFile = _outputFile.slice(0, -path.extname(_outputFile).length)+"_"+lang+path.extname(_outputFile);
_tmpDir = path.join(_tmpDir, lang);
}
console.log("Generating in", _outputFile);
return fs.copy(
path.join(_tmpDir, "index."+ext),
_outputFile
);
};
// Multi-langs book
return Q()
.then(function() {
if (_options.langsSummary) {
console.log("Generating for all the languages");
return Q.all(
_.map(_options.langsSummary.list, function(lang) {
return copyPDF(lang.lang);
})
);
} else {
return copyPDF();
}
})
.then(function() {
return fs.remove(tmpDir);
})
.fail(utils.logError);
});
})
};
module.exports = {
folder: buildFunc,
files: buildFiles
};
+27 -58
View File
@@ -4,14 +4,13 @@ var Q = require('q');
var _ = require('lodash');
var path = require('path');
var prog = require('commander');
var tmp = require('tmp');
var pkg = require('../package.json');
var generators = require("../lib/generate").generators;
var fs = require('../lib/generate/fs');
var utils = require('./utils');
var buildFunc = require('./build');
var build = require('./build');
// General options
prog
@@ -29,19 +28,16 @@ var buildCommand = function(command, action) {
.action(action);
}
var buildFunc;
buildCommand(prog
.command('build [source_dir]')
.description('Build a gitbook from a directory'), buildFunc);
.description('Build a gitbook from a directory'), build.folder);
buildCommand(prog
.command('serve [source_dir]')
.description('Build then serve a gitbook from a directory')
.option('-p, --port <port>', 'Port for server to listen on', 4000),
function(dir, options) {
buildFunc(dir, options)
build.folder(dir, options)
.then(function(_options) {
console.log();
console.log('Starting server ...');
@@ -59,59 +55,32 @@ buildCommand(prog
.command('pdf [source_dir] [output_file]')
.description('Build a gitbook as a PDF')
.option('-pf, --paperformat <format>', 'PDF paper format (default is A4): "5in*7.5in", "10cm*20cm", "A4", "Letter"'),
function(dir, outputFile, options) {
outputFile = outputFile || path.resolve(dir, "book.pdf");
Q.nfcall(tmp.dir)
.then(function(tmpDir) {
return buildFunc(
dir,
_.extend(options, {
output: tmpDir,
format: "pdf"
})
)
.then(function(_options) {
var copyPDF = function(lang) {
var _outputFile = outputFile;
var _tmpDir = tmpDir;
if (lang) {
_outputFile = _outputFile.slice(0, -path.extname(_outputFile).length)+"_"+lang+path.extname(_outputFile);
_tmpDir = path.join(_tmpDir, lang);
}
console.log("Generating PDF in", _outputFile);
return fs.copy(
path.join(_tmpDir, "index.pdf"),
_outputFile
);
};
// Multi-langs book
return Q()
.then(function() {
if (_options.langsSummary) {
console.log("Generating PDFs for all the languages");
return Q.all(
_.map(_options.langsSummary.list, function(lang) {
return copyPDF(lang.lang);
})
);
} else {
return copyPDF();
}
})
.then(function() {
return fs.remove(tmpDir);
})
.fail(utils.logError);
});
})
function(dir, output, options) {
build.files(dir, output, options, {
extension: "pdf",
format: "pdf",
options: {
paperformat: options.paperformat
}
});
});
buildCommand(prog
.command('ebook [source_dir] [output_file]')
.description('Build a gitbook as a eBook')
.option('-c, --cover <path>', 'Cover image, default is cover.png if exists'),
function(dir, output, options) {
var ext = output ? path.extname(output) : "epub";
build.files(dir, output, options, {
extension: ext,
format: "ebook",
options: {
extension: ext,
cover: options.cover
}
});
});
// Parse and fallback to help if no args
if(_.isEmpty(prog.parse(process.argv).args) && process.argv.length === 2) {
+70
View File
@@ -0,0 +1,70 @@
var util = require("util");
var path = require("path");
var Q = require("q");
var _ = require("lodash");
var exec = require('child_process').exec;
var fs = require("fs");
var parse = require("../../parse");
var BaseGenerator = require("../page");
/*
* This generator inherits from the single page generator
* and convert the page output to ebook
*/
var Generator = function() {
BaseGenerator.apply(this, arguments);
// Options for eBook generation
this.options = _.defaults(this.options, {
extension: "epub"
});
if (!this.options.cover && fs.existsSync(path.join(this.options.input, "cover.png"))) {
this.options.cover = path.join(this.options.input, "cover.png")
}
};
util.inherits(Generator, BaseGenerator);
Generator.prototype.finish = function() {
var that = this;
return BaseGenerator.prototype.finish.apply(this)
.then(function() {
var d = Q.defer();
var _options = {
"--cover": that.options.cover
};
var command = [
"ebook-convert",
path.join(that.options.output, "index.html"),
path.join(that.options.output, "index."+that.options.extension),
_.chain(_options)
.map(function(value, key) {
if (value == null) return null;
return key+"="+value;
})
.compact()
.value()
.join(" ")
].join(" ");
exec(command, function (error, stdout, stderr) {
if (error) {
if (error.code == 127) {
error.message = "Need to install ebook-convert from Calibre";
} else {
error.message = error.message + " "+stdout;
}
return d.reject(error);
}
d.resolve();
});
return d.promise;
});
};
module.exports = Generator;
+1
View File
@@ -11,6 +11,7 @@ var generators = {
"site": require("./site"),
"page": require("./page"),
"pdf": require("./pdf"),
"ebook": require("./ebook"),
"json": require("./json")
};