diff --git a/Cargo.lock b/Cargo.lock index 78eab5e..a03f1e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,7 @@ dependencies = [ "syntect 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "tera 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "term-painter 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "ws 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -820,6 +821,23 @@ dependencies = [ "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "term" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "term-painter" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "term_size" version = "0.2.3" @@ -1131,6 +1149,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syntect 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6728e7e9bbd971751d17d39b0e38e3558c10b9fb32125441bb17c434a2754e7c" "checksum tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" "checksum tera 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6f2ff83a1773a0482ddc961d0030b514f1848f592ae9612afb241e5eb455df75" +"checksum term 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d168af3930b369cfe245132550579d47dfd873d69470755a19c2c6568dbbd989" +"checksum term-painter 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ab900bf2f05175932b13d4fc12f8ff09ef777715b04998791ab2c930841e496b" "checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a" "checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a" "checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" diff --git a/Cargo.toml b/Cargo.toml index fa679ba..b9dabd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ slug = "0.1" syntect = "1" chrono = "0.3" toml = { version = "0.3", default-features = false, features = ["serde"]} +term-painter = "0.2" # Below is for the serve cmd staticfile = "0.4" diff --git a/appveyor.yml b/appveyor.yml index ed01ed9..dad60de 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -23,9 +23,9 @@ environment: install: - ps: >- If ($Env:TARGET -eq 'x86_64-pc-windows-gnu') { - $Env:PATH += ';C:\msys64\mingw64\bin' + $Env:PATH += ';C:\msys64\mingw64\bin;C:\Program Files\Git\mingw64\bin' } ElseIf ($Env:TARGET -eq 'i686-pc-windows-gnu') { - $Env:PATH += ';C:\msys64\mingw32\bin' + $Env:PATH += ';C:\msys64\mingw32\bin;C:\Program Files\Git\mingw64\bin' } - curl -sSf -o rustup-init.exe https://win.rustup.rs/ - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_VERSION% diff --git a/benches/gutenberg.rs b/benches/gutenberg.rs index 2086576..704e404 100644 --- a/benches/gutenberg.rs +++ b/benches/gutenberg.rs @@ -14,7 +14,7 @@ use gutenberg::{Site, populate_previous_and_next_pages}; fn bench_loading_test_site(b: &mut test::Bencher) { let mut path = env::current_dir().unwrap().to_path_buf(); path.push("test_site"); - let mut site = Site::new(&path).unwrap(); + let mut site = Site::new(&path, "config.toml").unwrap(); b.iter(|| site.load().unwrap()); @@ -25,7 +25,7 @@ fn bench_loading_test_site(b: &mut test::Bencher) { fn bench_building_test_site(b: &mut test::Bencher) { let mut path = env::current_dir().unwrap().to_path_buf(); path.push("test_site"); - let mut site = Site::new(&path).unwrap(); + let mut site = Site::new(&path, "config.toml").unwrap(); site.load().unwrap(); let tmp_dir = TempDir::new("example").expect("create temp dir"); let public = &tmp_dir.path().join("public"); @@ -39,9 +39,9 @@ fn bench_building_test_site(b: &mut test::Bencher) { fn bench_populate_previous_and_next_pages(b: &mut test::Bencher) { let mut path = env::current_dir().unwrap().to_path_buf(); path.push("test_site"); - let mut site = Site::new(&path).unwrap(); + let mut site = Site::new(&path, "config.toml").unwrap(); site.load().unwrap(); - let mut pages = site.pages.values().map(|p| p.clone()).collect::>(); + let mut pages = site.pages.values().cloned().collect::>(); pages.sort_by(|a, b| a.partial_cmp(b).unwrap()); b.iter(|| populate_previous_and_next_pages(pages.as_slice(), false)); diff --git a/src/cmd/build.rs b/src/cmd/build.rs index bb3aaeb..580439e 100644 --- a/src/cmd/build.rs +++ b/src/cmd/build.rs @@ -7,5 +7,6 @@ use gutenberg::Site; pub fn build(config_file: &str) -> Result<()> { let mut site = Site::new(env::current_dir().unwrap(), config_file)?; site.load()?; + println!("-> Creating {} pages and {} sections", site.pages.len(), site.sections.len()); site.build() } diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 4fa2111..606858f 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -14,7 +14,8 @@ use gutenberg::Site; use gutenberg::errors::{Result}; -use ::report_elapsed_time; +use ::{report_elapsed_time, unravel_errors}; +use console; #[derive(Debug, PartialEq)] @@ -46,22 +47,16 @@ fn rebuild_done_handling(broadcaster: &Sender, res: Result<()>, reload_path: &st }}"#, reload_path) ).unwrap(); }, - Err(e) => { - println!("Failed to build the site"); - println!("Error: {}", e); - for e in e.iter().skip(1) { - println!("Reason: {}", e) - } - } + Err(e) => unravel_errors("Failed to build the site", &e, false) } } // Most of it taken from mdbook pub fn serve(interface: &str, port: &str, config_file: &str) -> Result<()> { - println!("Building site..."); let start = Instant::now(); let mut site = Site::new(env::current_dir().unwrap(), config_file)?; + let address = format!("{}:{}", interface, port); // Override the base url so links work in localhost site.config.base_url = if site.config.base_url.ends_with('/') { @@ -72,6 +67,7 @@ pub fn serve(interface: &str, port: &str, config_file: &str) -> Result<()> { site.load()?; site.enable_live_reload(); + println!("-> Creating {} pages and {} sections", site.pages.len(), site.sections.len()); site.build()?; report_elapsed_time(start); @@ -84,7 +80,6 @@ pub fn serve(interface: &str, port: &str, config_file: &str) -> Result<()> { // Starts with a _ to not trigger the unused lint // we need to assign to a variable otherwise it will block let _iron = Iron::new(mount).http(address.as_str()).unwrap(); - println!("Web server is available at http://{}", address); // The websocket for livereload let ws_server = WebSocket::new(|_| { @@ -104,8 +99,10 @@ pub fn serve(interface: &str, port: &str, config_file: &str) -> Result<()> { watcher.watch("static/", RecursiveMode::Recursive).unwrap(); watcher.watch("templates/", RecursiveMode::Recursive).unwrap(); let pwd = format!("{}", env::current_dir().unwrap().display()); + println!("Listening for changes in {}/{{content, static, templates}}", pwd); - println!("Press CTRL+C to stop\n"); + println!("Web server is available at http://{}", address); + println!("Press Ctrl+C to stop\n"); use notify::DebouncedEvent::*; @@ -127,17 +124,17 @@ pub fn serve(interface: &str, port: &str, config_file: &str) -> Result<()> { let start = Instant::now(); match detect_change_kind(&pwd, &path) { (ChangeKind::Content, _) => { - println!("-> Content changed {}", path.display()); + console::info(&format!("-> Content changed {}", path.display())); // Force refresh rebuild_done_handling(&broadcaster, site.rebuild_after_content_change(&path), "/x.js"); }, (ChangeKind::Templates, _) => { - println!("-> Template changed {}", path.display()); + console::info(&format!("-> Template changed {}", path.display())); // Force refresh rebuild_done_handling(&broadcaster, site.rebuild_after_template_change(), "/x.js"); }, (ChangeKind::StaticFiles, p) => { - println!("-> Static file changes detected {}", path.display()); + console::info(&format!("-> Static file changes detected {}", path.display())); rebuild_done_handling(&broadcaster, site.copy_static_directory(), &p); }, }; @@ -146,14 +143,14 @@ pub fn serve(interface: &str, port: &str, config_file: &str) -> Result<()> { _ => {} } }, - Err(e) => println!("Watch error: {:?}", e), + Err(e) => console::error(&format!("Watch error: {:?}", e)), }; } } -/// Returns whether the path we received corresponds to a temp file create -/// by an editor +/// Returns whether the path we received corresponds to a temp file created +/// by an editor or the OS fn is_temp_file(path: &Path) -> bool { let ext = path.extension(); match ext { @@ -194,7 +191,7 @@ fn detect_change_kind(pwd: &str, path: &Path) -> (ChangeKind, String) { } else if path_str.starts_with("/static") { ChangeKind::StaticFiles } else { - panic!("Got a change in an unexpected path: {}", path_str); + unreachable!("Got a change in an unexpected path: {}", path_str); }; (change_kind, path_str) @@ -221,7 +218,6 @@ mod tests { ]; for t in testcases { - println!("{:?}", t.display()); assert!(is_temp_file(&t)); } } @@ -244,7 +240,6 @@ mod tests { ]; for (expected, pwd, path) in testcases { - println!("{:?}", path.display()); assert_eq!(expected, detect_change_kind(&pwd, &path)); } } diff --git a/src/console.rs b/src/console.rs new file mode 100644 index 0000000..4132971 --- /dev/null +++ b/src/console.rs @@ -0,0 +1,15 @@ +use term_painter::ToStyle; +use term_painter::Color::*; + + +pub fn info(message: &str) { + println!("{}", NotSet.bold().paint(message)); +} + +pub fn success(message: &str) { + println!("{}", Green.bold().paint(message)); +} + +pub fn error(message: &str) { + println!("{}", Red.bold().paint(message)); +} diff --git a/src/main.rs b/src/main.rs index 185ad5b..73308b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate clap; extern crate error_chain; extern crate gutenberg; extern crate chrono; +extern crate term_painter; extern crate staticfile; extern crate iron; @@ -13,23 +14,38 @@ extern crate ws; use std::time::Instant; + use chrono::Duration; +use gutenberg::errors::Error; mod cmd; +mod console; -// Print the time elapsed rounded to 1 decimal +/// Print the time elapsed rounded to 1 decimal fn report_elapsed_time(instant: Instant) { let duration_ms = Duration::from_std(instant.elapsed()).unwrap().num_milliseconds() as f64; if duration_ms < 1000.0 { - println!("Done in {}ms.\n", duration_ms); + console::success(&format!("Done in {}ms.\n", duration_ms)); } else { let duration_sec = duration_ms / 1000.0; - println!("Done in {:.1}s.\n", ((duration_sec * 10.0).round() / 10.0)); + console::success(&format!("Done in {:.1}s.\n", ((duration_sec * 10.0).round() / 10.0))); } } +////Display an error message, the actual error and then exits if requested +fn unravel_errors(message: &str, error: &Error, exit: bool) { + console::error(message); + console::error(&format!("Error: {}", error)); + for e in error.iter().skip(1) { + console::error(&format!("Reason: {}", e)); + } + if exit { + ::std::process::exit(1); + } +} + fn main() { let matches = clap_app!(Gutenberg => @@ -57,44 +73,25 @@ fn main() { match matches.subcommand() { ("init", Some(matches)) => { match cmd::create_new_project(matches.value_of("name").unwrap()) { - Ok(()) => { - println!("Project created"); - }, - Err(e) => { - println!("Error: {}", e); - ::std::process::exit(1); - }, + Ok(()) => console::success("Project created"), + Err(e) => unravel_errors("Failed to create the project", &e, true), }; }, ("build", Some(_)) => { - println!("Building site"); + console::info("Building site..."); let start = Instant::now(); - match cmd::build(&config_file) { - Ok(()) => { - report_elapsed_time(start); - }, - Err(e) => { - println!("Failed to build the site"); - println!("Error: {}", e); - for e in e.iter().skip(1) { - println!("Reason: {}", e) - } - ::std::process::exit(1); - }, + match cmd::build(config_file) { + Ok(()) => report_elapsed_time(start), + Err(e) => unravel_errors("Failed to build the site", &e, true), }; }, ("serve", Some(matches)) => { let interface = matches.value_of("interface").unwrap_or("127.0.0.1"); let port = matches.value_of("port").unwrap_or("1111"); - match cmd::serve(interface, port, &config_file) { + console::info("Building site..."); + match cmd::serve(interface, port, config_file) { Ok(()) => (), - Err(e) => { - println!("Error: {}", e); - for e in e.iter().skip(1) { - println!("Reason: {}", e) - } - ::std::process::exit(1); - }, + Err(e) => unravel_errors("Failed to build the site", &e, true), }; }, _ => unreachable!(), diff --git a/src/page.rs b/src/page.rs index 71c1281..c80ff8e 100644 --- a/src/page.rs +++ b/src/page.rs @@ -206,7 +206,7 @@ impl Page { context.add("page", self); tera.render(&tpl_name, &context) - .chain_err(|| format!("Failed to render page '{}'", self.file_name)) + .chain_err(|| format!("Failed to render page '{}'", self.file_path.display())) } }