diff options
author | Samy Pessé <samypesse@gmail.com> | 2014-04-25 16:23:13 +0200 |
---|---|---|
committer | Samy Pessé <samypesse@gmail.com> | 2014-04-25 16:23:13 +0200 |
commit | 83d8c16853a056ef34360150a805b2a7ac52dd4f (patch) | |
tree | 740c72fc044d30750b0a127250bd55d6f6dbdb68 | |
parent | 47e9506397afb37fea8f164e1fc41b625fdcd1bc (diff) | |
download | gitbook-83d8c16853a056ef34360150a805b2a7ac52dd4f.zip gitbook-83d8c16853a056ef34360150a805b2a7ac52dd4f.tar.gz gitbook-83d8c16853a056ef34360150a805b2a7ac52dd4f.tar.bz2 |
Add file watcher in "gitbook serve" command (Fix #47, #89, #140)
-rw-r--r-- | bin/build.js | 2 | ||||
-rwxr-xr-x | bin/gitbook.js | 43 | ||||
-rw-r--r-- | bin/server.js | 96 | ||||
-rw-r--r-- | bin/utils.js | 41 | ||||
-rw-r--r-- | package.json | 1 |
5 files changed, 148 insertions, 35 deletions
diff --git a/bin/build.js b/bin/build.js index 6f90e1d..37415bd 100644 --- a/bin/build.js +++ b/bin/build.js @@ -44,7 +44,7 @@ var makeBuildFunc = function(converter) { }) .then(function(repoID) { return converter( - _.extend(options || {}, { + _.extend({}, options || {}, { input: dir, output: outputDir, title: options.title, diff --git a/bin/gitbook.js b/bin/gitbook.js index 88ba5e2..c2f0ed1 100755 --- a/bin/gitbook.js +++ b/bin/gitbook.js @@ -12,6 +12,7 @@ var fs = require('../lib/generate/fs'); var utils = require('./utils'); var build = require('./build'); +var Server = require('./server'); // General options prog @@ -24,19 +25,39 @@ build.command(prog.command('build [source_dir]')) build.command(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) +.option('--no-watch', 'Disable restart with file watching') .action(function(dir, options) { - build.folder(dir, options || {}) - .then(function(_options) { - console.log(); - console.log('Starting server ...'); - return utils.serveDir(_options.output, options.port) + var server = new Server(); + + var generate = function() { + if (server.isRunning()) console.log("Stopping server"); + + server.stop() + .then(function() { + return build.folder(dir, options); + }) + .then(function(_options) { + console.log(); + console.log('Starting server ...'); + return server.start(_options.output, options.port) + .then(function() { + console.log('Serving book on http://localhost:'+options.port); + + if (!options.watch) return; + return utils.watch(_options.input) + .then(function(filepath) { + console.log("Restart after change in "+path.relative(dir, filepath)); + console.log(''); + return generate(); + }) + }) + }) .fail(utils.logError); - }) - .then(function() { - console.log('Serving book on http://localhost:'+options.port); - console.log(); - console.log('Press CTRL+C to quit ...'); - }); + }; + + console.log('Press CTRL+C to quit ...'); + console.log('') + generate(); }); build.command(prog.command('pdf [source_dir]')) diff --git a/bin/server.js b/bin/server.js new file mode 100644 index 0000000..2b97fe8 --- /dev/null +++ b/bin/server.js @@ -0,0 +1,96 @@ +var Q = require('q'); +var _ = require('lodash'); + +var events = require('events'); +var http = require('http'); +var send = require('send'); +var util = require('util'); +var url = require('url'); + +var Server = function() { + this.running = null; + this.dir = null; + this.port = 0; + this.sockets = []; +}; +util.inherits(Server, events.EventEmitter); + +// Return true if the server is running +Server.prototype.isRunning = function() { + return this.running != null; +}; + +// Stop the server +Server.prototype.stop = function() { + var that = this; + if (!this.isRunning()) return Q(); + + var d = Q.defer(); + this.running.close(function(err) { + that.running = null; + that.emit("state", false); + + if (err) d.reject(err); + else d.resolve(); + }); + + for (var i = 0; i < this.sockets.length; i++) { + this.sockets[i].destroy(); + } + + return d.promise; +}; + +Server.prototype.start = function(dir, port) { + var that = this, pre = Q(); + port = port || 8004; + + if (that.isRunning()) pre = this.stop(); + return pre + .then(function() { + var d = Q.defer(); + + that.running = http.createServer(function(req, res){ + // Render error + function error(err) { + res.statusCode = err.status || 500; + res.end(err.message); + } + + // Redirect to directory's index.html + function redirect() { + res.statusCode = 301; + res.setHeader('Location', req.url + '/'); + res.end('Redirecting to ' + req.url + '/'); + } + + // Send file + send(req, url.parse(req.url).pathname) + .root(dir) + .on('error', error) + .on('directory', redirect) + .pipe(res); + }); + + that.running.on('connection', function (socket) { + that.sockets.push(socket); + socket.setTimeout(4000); + socket.on('close', function () { + that.sockets.splice(that.sockets.indexOf(socket), 1); + }); + }); + + that.running.listen(port, function(err) { + if (err) return d.reject(err); + + that.port = port; + that.dir = dir; + that.emit("state", true); + d.resolve(); + }); + + return d.promise; + }); +} + +module.exports = Server; diff --git a/bin/utils.js b/bin/utils.js index 4d45e29..45bc7d5 100644 --- a/bin/utils.js +++ b/bin/utils.js @@ -4,8 +4,11 @@ var _ = require('lodash'); var http = require('http'); var send = require('send'); -var url = require('url'); 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 @@ -55,32 +58,24 @@ function titleCase(str) return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();}); } -function serveDir(dir, port) { +function watch(dir) { var d = Q.defer(); + dir = path.resolve(dir); - var server = http.createServer(function(req, res){ - // Render error - function error(err) { - res.statusCode = err.status || 500; - res.end(err.message); - } + var gaze = new Gaze("**/*.md", { + cwd: dir + }); - // Redirect to directory's index.html - function redirect() { - res.statusCode = 301; - res.setHeader('Location', req.url + '/'); - res.end('Redirecting to ' + req.url + '/'); - } + gaze.once("all", function(e, filepath) { + gaze.close(); - // Send file - send(req, url.parse(req.url).pathname) - .root(dir) - .on('error', error) - .on('directory', redirect) - .pipe(res); - }).listen(port); + d.resolve(filepath); + }); + gaze.once("error", function(err) { + gaze.close(); - d.resolve(server); + d.reject(err); + }); return d.promise; } @@ -96,6 +91,6 @@ module.exports = { gitURL: gitURL, githubID: githubID, titleCase: titleCase, - serveDir: serveDir, + watch: watch, logError: logError }; diff --git a/package.json b/package.json index 0ba9156..4eaae38 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "highlight.js": "8.0.0", "tmp": "0.0.23", "semver": "2.2.1", + "gaze": "0.6.4", "gitbook-plugin": "0.0.2", "gitbook-plugin-mixpanel": "0.0.2", |