first implementation of the watch sub-command. #61 Needs refining, bug in notify made me use recursion, afraid of hitting the max recursion limit...

This commit is contained in:
Mathieu David 2015-09-27 14:38:37 +02:00
parent c1c1074292
commit 522eef9296
3 changed files with 65 additions and 4 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "mdbook" name = "mdbook"
version = "0.0.1" version = "0.0.2"
authors = ["Mathieu David <mathieudavid@mathieudavid.org>"] authors = ["Mathieu David <mathieudavid@mathieudavid.org>"]
description = "create books from markdown files (like Gitbook)" description = "create books from markdown files (like Gitbook)"
documentation = "http://azerupi.github.io/mdBook/index.html" documentation = "http://azerupi.github.io/mdBook/index.html"
@ -11,6 +11,7 @@ readme = "README.md"
build = "build.rs" build = "build.rs"
exclude = [ exclude = [
"book-example/*", "book-example/*",
"src/theme/stylus",
] ]
[dependencies] [dependencies]
@ -22,11 +23,16 @@ pulldown-cmark = "*"
[dev-dependencies] [dev-dependencies]
tempdir = "*" tempdir = "*"
[dependencies.notify]
notify = "*"
optional = true
[features] [features]
default = ["output"] default = ["output", "watch"]
debug = [] debug = []
output = [] output = []
regenerate-css = [] regenerate-css = []
watch = ["notify"]
[[bin]] [[bin]]
doc = false doc = false

View File

@ -4,6 +4,7 @@
- [Command Line Tool](cli/cli-tool.md) - [Command Line Tool](cli/cli-tool.md)
- [init](cli/init.md) - [init](cli/init.md)
- [build](cli/build.md) - [build](cli/build.md)
- [watch]()
- [Format](format/format.md) - [Format](format/format.md)
- [SUMMARY.md](format/summary.md) - [SUMMARY.md](format/summary.md)
- [Configuration](format/config.md) - [Configuration](format/config.md)

View File

@ -1,6 +1,8 @@
extern crate mdbook; extern crate mdbook;
#[macro_use] #[macro_use]
extern crate clap; extern crate clap;
#[cfg(feature = "watch")]
extern crate notify;
use std::env; use std::env;
use std::error::Error; use std::error::Error;
@ -9,6 +11,11 @@ use std::path::{Path, PathBuf};
use clap::{App, ArgMatches, SubCommand}; use clap::{App, ArgMatches, SubCommand};
#[cfg(feature = "watch")]
use notify::Watcher;
#[cfg(feature = "watch")]
use std::sync::mpsc::channel;
use mdbook::MDBook; use mdbook::MDBook;
const NAME: &'static str = "mdbook"; const NAME: &'static str = "mdbook";
@ -32,14 +39,16 @@ fn main() {
.about("Build the book from the markdown files") .about("Build the book from the markdown files")
.arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'")) .arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
.subcommand(SubCommand::with_name("watch") .subcommand(SubCommand::with_name("watch")
.about("Watch the files for changes")) .about("Watch the files for changes")
.arg_from_usage("[dir] 'A directory for your book{n}(Defaults to Current Directory when ommitted)'"))
.get_matches(); .get_matches();
// Check which subcomamnd the user ran... // Check which subcomamnd the user ran...
let res = match matches.subcommand() { let res = match matches.subcommand() {
("init", Some(sub_matches)) => init(sub_matches), ("init", Some(sub_matches)) => init(sub_matches),
("build", Some(sub_matches)) => build(sub_matches), ("build", Some(sub_matches)) => build(sub_matches),
("watch", _) => unimplemented!(), #[cfg(feature = "watch")]
("watch", Some(sub_matches)) => watch(sub_matches),
(_, _) => unreachable!() (_, _) => unreachable!()
}; };
@ -104,6 +113,51 @@ fn build(args: &ArgMatches) -> Result<(), Box<Error>> {
Ok(()) Ok(())
} }
#[cfg(feature = "watch")]
fn watch(args: &ArgMatches) -> Result<(), Box<Error>> {
let book_dir = get_book_dir(args);
let book = MDBook::new(&book_dir).read_config();
// Create a channel to receive the events.
let (tx, rx) = channel();
let w: Result<notify::RecommendedWatcher, notify::Error> = notify::Watcher::new(tx);
match w {
Ok(mut watcher) => {
watcher.watch(book.get_src()).unwrap();
loop {
match rx.recv() {
Ok(event) => {
if let Some(path) = event.path {
println!("File changed: {:?}\nBuilding book...\n", path);
try!(build(args));
println!("");
// Hack to prevent receiving the event 4 times, probably a bug in notify
return watch(args);
} else {
continue;
}
},
Err(e) => {
println!("An error occured: {:?}", e);
}
}
}
},
Err(e) => {
println!("Error while trying to watch the files:\n\n\t{:?}", e);
::std::process::exit(0);
}
}
Ok(())
}
fn get_book_dir(args: &ArgMatches) -> PathBuf { fn get_book_dir(args: &ArgMatches) -> PathBuf {
if let Some(dir) = args.value_of("dir") { if let Some(dir) = args.value_of("dir") {
// Check if path is relative from current dir, or absolute... // Check if path is relative from current dir, or absolute...