Made `mdbook watch` and `mdbook serve` rebuild the book again (#508)
Made `mdbook watch` and `mdbook serve` rebuild the book again
This commit is contained in:
parent
d69bc9c7c3
commit
396426662d
|
@ -3,12 +3,11 @@ extern crate staticfile;
|
|||
extern crate ws;
|
||||
|
||||
use std;
|
||||
use std::path::PathBuf;
|
||||
use self::iron::{status, AfterMiddleware, Chain, Iron, IronError, IronResult, Request, Response,
|
||||
Set};
|
||||
use clap::{App, ArgMatches, SubCommand};
|
||||
use mdbook::MDBook;
|
||||
use mdbook::errors::Result;
|
||||
use mdbook::errors::*;
|
||||
use {get_book_dir, open};
|
||||
#[cfg(feature = "watch")]
|
||||
use watch;
|
||||
|
@ -18,28 +17,21 @@ struct ErrorRecover;
|
|||
// Create clap subcommand arguments
|
||||
pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
||||
SubCommand::with_name("serve")
|
||||
.about(
|
||||
"Serve the book at http://localhost:3000. Rebuild and reload on change.",
|
||||
)
|
||||
.about("Serve the book at http://localhost:3000. Rebuild and reload on change.")
|
||||
.arg_from_usage(
|
||||
"[dir] 'A directory for your book{n}(Defaults to \
|
||||
Current Directory when omitted)'",
|
||||
)
|
||||
.arg_from_usage(
|
||||
"-d, --dest-dir=[dest-dir] 'The output directory for \
|
||||
your book{n}(Defaults to ./book when omitted)'",
|
||||
"[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'",
|
||||
)
|
||||
.arg_from_usage("-p, --port=[port] 'Use another port{n}(Defaults to 3000)'")
|
||||
.arg_from_usage(
|
||||
"-w, --websocket-port=[ws-port] 'Use another port for the \
|
||||
websocket connection (livereload){n}(Defaults to 3001)'",
|
||||
"-w, --websocket-port=[ws-port] 'Use another port for the websocket connection \
|
||||
(livereload){n}(Defaults to 3001)'",
|
||||
)
|
||||
.arg_from_usage(
|
||||
"-i, --interface=[interface] 'Interface to listen on{n}(Defaults to localhost)'",
|
||||
)
|
||||
.arg_from_usage(
|
||||
"-a, --address=[address] 'Address that the browser can reach the \
|
||||
websocket server from{n}(Defaults to the interface address)'",
|
||||
"-a, --address=[address] 'Address that the browser can reach the websocket server \
|
||||
from{n}(Defaults to the interface address)'",
|
||||
)
|
||||
.arg_from_usage("-o, --open 'Open the book server in a web browser'")
|
||||
}
|
||||
|
@ -51,10 +43,6 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
|
|||
let book_dir = get_book_dir(args);
|
||||
let mut book = MDBook::load(&book_dir)?;
|
||||
|
||||
if let Some(dest_dir) = args.value_of("dest-dir") {
|
||||
book.config.build.build_dir = PathBuf::from(dest_dir);
|
||||
}
|
||||
|
||||
let port = args.value_of("port").unwrap_or("3000");
|
||||
let ws_port = args.value_of("websocket-port").unwrap_or("3001");
|
||||
let interface = args.value_of("interface").unwrap_or("localhost");
|
||||
|
@ -80,18 +68,19 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
|
|||
}}
|
||||
</script>
|
||||
"#,
|
||||
public_address,
|
||||
ws_port,
|
||||
RELOAD_COMMAND
|
||||
public_address, ws_port, RELOAD_COMMAND
|
||||
));
|
||||
|
||||
book.build()?;
|
||||
|
||||
let mut chain = Chain::new(staticfile::Static::new(book.get_destination()));
|
||||
chain.link_after(ErrorRecover);
|
||||
let _iron = Iron::new(chain).http(&*address).unwrap();
|
||||
let _iron = Iron::new(chain)
|
||||
.http(&*address)
|
||||
.chain_err(|| "Unable to launch the server")?;
|
||||
|
||||
let ws_server = ws::WebSocket::new(|_| |_| Ok(())).unwrap();
|
||||
let ws_server =
|
||||
ws::WebSocket::new(|_| |_| Ok(())).chain_err(|| "Unable to start the websocket")?;
|
||||
|
||||
let broadcaster = ws_server.broadcaster();
|
||||
|
||||
|
@ -107,9 +96,9 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
|
|||
}
|
||||
|
||||
#[cfg(feature = "watch")]
|
||||
watch::trigger_on_change(&mut book, move |path, book| {
|
||||
watch::trigger_on_change(&mut book, move |path, book_dir| {
|
||||
println!("File changed: {:?}\nBuilding book...\n", path);
|
||||
match book.build() {
|
||||
match MDBook::load(&book_dir).and_then(|mut b| b.build()) {
|
||||
Err(e) => println!("Error while building: {:?}", e),
|
||||
_ => broadcaster.send(RELOAD_COMMAND).unwrap(),
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
extern crate notify;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::Path;
|
||||
use self::notify::Watcher;
|
||||
use std::time::Duration;
|
||||
use std::sync::mpsc::channel;
|
||||
|
@ -15,12 +15,7 @@ pub fn make_subcommand<'a, 'b>() -> App<'a, 'b> {
|
|||
.about("Watch the files for changes")
|
||||
.arg_from_usage("-o, --open 'Open the compiled book in a web browser'")
|
||||
.arg_from_usage(
|
||||
"-d, --dest-dir=[dest-dir] 'The output directory for \
|
||||
your book{n}(Defaults to ./book when omitted)'",
|
||||
)
|
||||
.arg_from_usage(
|
||||
"[dir] 'A directory for your book{n}(Defaults to \
|
||||
Current Directory when omitted)'",
|
||||
"[dir] 'A directory for your book{n}(Defaults to Current Directory when omitted)'",
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -29,30 +24,28 @@ pub fn execute(args: &ArgMatches) -> Result<()> {
|
|||
let book_dir = get_book_dir(args);
|
||||
let mut book = MDBook::load(&book_dir)?;
|
||||
|
||||
if let Some(dest_dir) = args.value_of("dest-dir") {
|
||||
book.config.build.build_dir = PathBuf::from(dest_dir);
|
||||
}
|
||||
|
||||
if args.is_present("open") {
|
||||
book.build()?;
|
||||
open(book.get_destination().join("index.html"));
|
||||
}
|
||||
|
||||
trigger_on_change(&mut book, |path, book| {
|
||||
trigger_on_change(&book, |path, book_dir| {
|
||||
println!("File changed: {:?}\nBuilding book...\n", path);
|
||||
if let Err(e) = book.build() {
|
||||
println!("Error while building: {:?}", e);
|
||||
let result = MDBook::load(&book_dir).and_then(|mut b| b.build());
|
||||
|
||||
if let Err(e) = result {
|
||||
println!("Error while building: {}", e);
|
||||
}
|
||||
println!("");
|
||||
println!();
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Calls the closure when a book source file is changed. This is blocking!
|
||||
pub fn trigger_on_change<F>(book: &mut MDBook, closure: F) -> ()
|
||||
/// Calls the closure when a book source file is changed, blocking indefinitely.
|
||||
pub fn trigger_on_change<F>(book: &MDBook, closure: F)
|
||||
where
|
||||
F: Fn(&Path, &mut MDBook) -> (),
|
||||
F: Fn(&Path, &Path),
|
||||
{
|
||||
use self::notify::RecursiveMode::*;
|
||||
use self::notify::DebouncedEvent::*;
|
||||
|
@ -64,48 +57,29 @@ where
|
|||
Ok(w) => w,
|
||||
Err(e) => {
|
||||
println!("Error while trying to watch the files:\n\n\t{:?}", e);
|
||||
::std::process::exit(0)
|
||||
::std::process::exit(1)
|
||||
}
|
||||
};
|
||||
|
||||
// Add the source directory to the watcher
|
||||
if let Err(e) = watcher.watch(book.source_dir(), Recursive) {
|
||||
println!("Error while watching {:?}:\n {:?}", book.source_dir(), e);
|
||||
::std::process::exit(0);
|
||||
::std::process::exit(1);
|
||||
};
|
||||
|
||||
// Add the theme directory to the watcher
|
||||
watcher.watch(book.theme_dir(), Recursive)
|
||||
.unwrap_or_default();
|
||||
let _ = watcher.watch(book.theme_dir(), Recursive);
|
||||
|
||||
// Add the book.{json,toml} file to the watcher if it exists, because it's not
|
||||
// located in the source directory
|
||||
if watcher.watch(book.root.join("book.json"), NonRecursive)
|
||||
.is_err()
|
||||
{
|
||||
// do nothing if book.json is not found
|
||||
}
|
||||
if watcher.watch(book.root.join("book.toml"), NonRecursive)
|
||||
.is_err()
|
||||
{
|
||||
// do nothing if book.toml is not found
|
||||
}
|
||||
// Add the book.toml file to the watcher if it exists
|
||||
let _ = watcher.watch(book.root.join("book.toml"), NonRecursive);
|
||||
|
||||
println!("\nListening for changes...\n");
|
||||
|
||||
loop {
|
||||
match rx.recv() {
|
||||
Ok(event) => {
|
||||
for event in rx.recv() {
|
||||
match event {
|
||||
Create(path) | Write(path) | Remove(path) | Rename(_, path) => {
|
||||
closure(&path, book);
|
||||
closure(&path, &book.root);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
println!("An error occured: {:?}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue