diff --git a/CHANGELOG.md b/CHANGELOG.md index f0e909e0..c55f68c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -42,6 +42,7 @@ sections up to the index to be used with the `get_section` Tera function - Add `transparent` sections, for when you want to separate content by sections but want to group them at a higher level (think a `posts` folder with years that want to use pagination on the index). - Add `page_template` to section front-matter for when you want to specify the template to use for every page under it +- Improves to `zola serve`: now handles files/directories renaming ## 0.4.2 (2018-09-03) diff --git a/Cargo.lock b/Cargo.lock index 8c2c73f8..5d161699 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,7 +86,7 @@ dependencies = [ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -506,7 +506,7 @@ dependencies = [ "rust-stemmers 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "strum 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "strum_macros 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1140,7 +1140,7 @@ dependencies = [ "phf_codegen 0.7.23 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1385,7 +1385,7 @@ dependencies = [ [[package]] name = "onig" -version = "4.2.0" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1751,7 +1751,7 @@ dependencies = [ "mime_guess 2.0.0-alpha.6 (registry+https://github.com/rust-lang/crates.io-index)", "native-tls 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "serde_urlencoded 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1907,7 +1907,7 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2119,12 +2119,12 @@ dependencies = [ "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "onig 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "onig 4.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "plist 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2156,7 +2156,7 @@ dependencies = [ "library 0.1.0", "pulldown-cmark 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "reqwest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "tera 0.11.19 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2187,7 +2187,7 @@ dependencies = [ "pest_derive 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", "slug 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "unic-segment 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2946,7 +2946,7 @@ dependencies = [ "checksum num-rational 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4e96f040177bb3da242b5b1ecf3f54b5d5af3efbbfb18608977a5d2767b22f10" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum onig 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f0d9dac9b8a5211103d75f3ce8d0c799e6f4f3f22608eeaefb4419786e4b258" +"checksum onig 4.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3febe8cb22362af9e662c9c35e4d8a675de50b1b119823aa556892ac967fb776" "checksum onig_sys 69.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "78c04019a39ebac42dfd8c7822af0a009043720845a812ddbb95e403298b0183" "checksum openssl 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "5e1309181cdcbdb51bc3b6bedb33dfac2a83b3d585033d3f6d9e22e8c1928613" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" @@ -3001,7 +3001,7 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef" "checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c" -"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce" +"checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811" "checksum serde_urlencoded 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aaed41d9fb1e2f587201b863356590c90c1157495d811430a0c0325fe8169650" "checksum sha-1 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "51b9d1f3b5de8a167ab06834a7c883bd197f2191e1dda1a22d9ccfeedbf9aded" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" diff --git a/components/library/src/library.rs b/components/library/src/library.rs index 8fccb3fa..a5ed97f1 100644 --- a/components/library/src/library.rs +++ b/components/library/src/library.rs @@ -277,8 +277,8 @@ impl Library { .collect() } - pub fn find_parent_section(&self, path: &Path) -> Option<&Section> { - let page_key = self.paths_to_pages[path]; + pub fn find_parent_section>(&self, path: P) -> Option<&Section> { + let page_key = self.paths_to_pages[path.as_ref()]; for s in self.sections.values() { if s.pages.contains(&page_key) { return Some(s); @@ -289,16 +289,16 @@ impl Library { } /// Only used in tests - pub fn get_section_key(&self, path: &PathBuf) -> Option<&Key> { - self.paths_to_sections.get(path) + pub fn get_section_key>(&self, path: P) -> Option<&Key> { + self.paths_to_sections.get(path.as_ref()) } - pub fn get_section(&self, path: &PathBuf) -> Option<&Section> { - self.sections.get(self.paths_to_sections.get(path).cloned().unwrap_or_default()) + pub fn get_section>(&self, path: P) -> Option<&Section> { + self.sections.get(self.paths_to_sections.get(path.as_ref()).cloned().unwrap_or_default()) } - pub fn get_section_mut(&mut self, path: &PathBuf) -> Option<&mut Section> { - self.sections.get_mut(self.paths_to_sections.get(path).cloned().unwrap_or_default()) + pub fn get_section_mut>(&mut self, path: P) -> Option<&mut Section> { + self.sections.get_mut(self.paths_to_sections.get(path.as_ref()).cloned().unwrap_or_default()) } pub fn get_section_by_key(&self, key: Key) -> &Section { @@ -313,8 +313,8 @@ impl Library { &self.get_section_by_key(key).file.relative } - pub fn get_page(&self, path: &PathBuf) -> Option<&Page> { - self.pages.get(self.paths_to_pages.get(path).cloned().unwrap_or_default()) + pub fn get_page>(&self, path: P) -> Option<&Page> { + self.pages.get(self.paths_to_pages.get(path.as_ref()).cloned().unwrap_or_default()) } pub fn get_page_by_key(&self, key: Key) -> &Page { @@ -325,16 +325,16 @@ impl Library { self.pages.get_mut(key).unwrap() } - pub fn remove_section(&mut self, path: &PathBuf) -> Option
{ - if let Some(k) = self.paths_to_sections.remove(path) { + pub fn remove_section>(&mut self, path: P) -> Option
{ + if let Some(k) = self.paths_to_sections.remove(path.as_ref()) { self.sections.remove(k) } else { None } } - pub fn remove_page(&mut self, path: &PathBuf) -> Option { - if let Some(k) = self.paths_to_pages.remove(path) { + pub fn remove_page>(&mut self, path: P) -> Option { + if let Some(k) = self.paths_to_pages.remove(path.as_ref()) { self.pages.remove(k) } else { None @@ -342,12 +342,12 @@ impl Library { } /// Used in rebuild, to check if we know it already - pub fn contains_section(&self, path: &PathBuf) -> bool { - self.paths_to_sections.contains_key(path) + pub fn contains_section>(&self, path: P) -> bool { + self.paths_to_sections.contains_key(path.as_ref()) } /// Used in rebuild, to check if we know it already - pub fn contains_page(&self, path: &PathBuf) -> bool { - self.paths_to_pages.contains_key(path) + pub fn contains_page>(&self, path: P) -> bool { + self.paths_to_pages.contains_key(path.as_ref()) } } diff --git a/components/rebuild/src/lib.rs b/components/rebuild/src/lib.rs index 4a6f5f98..ac4c96c2 100644 --- a/components/rebuild/src/lib.rs +++ b/components/rebuild/src/lib.rs @@ -240,7 +240,53 @@ fn handle_page_editing(site: &mut Site, path: &Path) -> Result<()> { } } -/// What happens when a section or a page is changed + +/// What happens when we rename a file/folder in the content directory. +/// Note that this is only called for folders when it isn't empty +pub fn after_content_rename(site: &mut Site, old: &Path, new: &Path) -> Result<()> { + let new_path = if new.is_dir() { + if new.join("_index.md").exists() { + // This is a section keep the dir folder to differentiate from renaming _index.md + // which doesn't do the same thing + new.to_path_buf() + } else if new.join("index.md").exists() { + new.join("index.md") + } else { + bail!("Got unexpected folder {:?} while handling renaming that was not expected", new); + } + } else { + new.to_path_buf() + }; + + // A section folder has been renamed: just reload the whole site and rebuild it as we + // do not really know what needs to be rendered + if new_path.is_dir() { + site.load()?; + return site.build(); + } + + // Renaming a file to _index.md, let the section editing do something and hope for the best + if new_path.file_name().unwrap() == "_index.md" { + // We aren't entirely sure where the original thing was so just try to delete whatever was + // at the old path + site.library.remove_page(&old.to_path_buf()); + site.library.remove_section(&old.to_path_buf()); + return handle_section_editing(site, &new_path); + } + + // If it is a page, just delete what was there before and + // fake it's a new page + let old_path = if new_path.file_name().unwrap() == "index.md" { + old.join("index.md") + } else { + old.to_path_buf() + }; + site.library.remove_page(&old_path); + return handle_page_editing(site, &new_path); +} + + +/// What happens when a section or a page is created/edited pub fn after_content_change(site: &mut Site, path: &Path) -> Result<()> { let is_section = path.file_name().unwrap() == "_index.md"; let is_md = path.extension().unwrap() == "md"; diff --git a/components/rebuild/tests/rebuild.rs b/components/rebuild/tests/rebuild.rs index 561c2b18..ad53570c 100644 --- a/components/rebuild/tests/rebuild.rs +++ b/components/rebuild/tests/rebuild.rs @@ -4,14 +4,14 @@ extern crate site; extern crate tempfile; use std::env; -use std::fs::{remove_dir_all, File}; +use std::fs::{self, File}; use std::io::prelude::*; use fs_extra::dir; use site::Site; use tempfile::tempdir; -use rebuild::after_content_change; +use rebuild::{after_content_change, after_content_rename}; // Loads the test_site in a tempdir and build it there // Returns (site_path_in_tempdir, site) @@ -25,10 +25,6 @@ macro_rules! load_and_build_site { dir::copy(&path, &$tmp_dir, &options).unwrap(); let site_path = $tmp_dir.path().join("test_site"); - // delete useless sections for those tests - remove_dir_all(site_path.join("content").join("paginated")).unwrap(); - remove_dir_all(site_path.join("content").join("posts")).unwrap(); - let mut site = Site::new(&site_path, "config.toml").unwrap(); site.load().unwrap(); let public = &site_path.join("public"); @@ -67,6 +63,22 @@ macro_rules! file_contains { }}; } +/// Rename a file or a folder to the new given name +macro_rules! rename { + ($site_path: expr, $path: expr, $new_name: expr) => {{ + let mut t = $site_path.clone(); + for c in $path.split('/') { + t.push(c); + } + let mut new_path = t.parent().unwrap().to_path_buf(); + new_path.push($new_name); + fs::rename(&t, &new_path).unwrap(); + println!("Renamed {:?} to {:?}", t, new_path); + (t, new_path) + }}; +} + + #[test] fn can_rebuild_after_simple_change_to_page_content() { let tmp_dir = tempdir().expect("create temp dir"); @@ -135,3 +147,87 @@ template = "rebuild.html" "

first

second

" )); } + +#[test] +fn can_rebuild_after_transparent_change() { + let tmp_dir = tempdir().expect("create temp dir"); + let (site_path, mut site) = load_and_build_site!(tmp_dir); + let file_path = edit_file!( + site_path, + "content/posts/2018/_index.md", + br#" ++++ +transparent = false +render = false ++++ +"# + ); + // Also remove pagination from posts section so we check whether the transparent page title + // is there or not without dealing with pagination + edit_file!( + site_path, + "content/posts/_index.md", + br#" ++++ +template = "section.html" +insert_anchor_links = "left" ++++ +"# + ); + + let res = after_content_change(&mut site, &file_path); + assert!(res.is_ok()); + assert!(!file_contains!( + site_path, + "public/posts/index.html", + "A transparent page" + )); +} + +#[test] +fn can_rebuild_after_renaming_page() { + let tmp_dir = tempdir().expect("create temp dir"); + let (site_path, mut site) = load_and_build_site!(tmp_dir); + let (old_path, new_path) = rename!(site_path, "content/posts/simple.md", "hard.md"); + + let res = after_content_rename(&mut site, &old_path, &new_path); + println!("{:?}", res); + assert!(res.is_ok()); + assert!(file_contains!( + site_path, + "public/posts/hard/index.html", + "A simple page" + )); +} + +// https://github.com/Keats/gutenberg/issues/385 +#[test] +fn can_rebuild_after_renaming_colocated_asset_folder() { + let tmp_dir = tempdir().expect("create temp dir"); + let (site_path, mut site) = load_and_build_site!(tmp_dir); + let (old_path, new_path) = rename!(site_path, "content/posts/with-assets", "with-assets-updated"); + assert!(file_contains!(site_path, "content/posts/with-assets-updated/index.md", "Hello")); + + let res = after_content_rename(&mut site, &old_path, &new_path); + println!("{:?}", res); + assert!(res.is_ok()); + assert!(file_contains!( + site_path, + "public/posts/with-assets-updated/index.html", + "Hello world" + )); +} + +// https://github.com/Keats/gutenberg/issues/385 +#[test] +fn can_rebuild_after_renaming_section_folder() { + let tmp_dir = tempdir().expect("create temp dir"); + let (site_path, mut site) = load_and_build_site!(tmp_dir); + let (old_path, new_path) = rename!(site_path, "content/posts", "new-posts"); + assert!(file_contains!(site_path, "content/new-posts/simple.md", "simple")); + + let res = after_content_rename(&mut site, &old_path, &new_path); + assert!(res.is_ok()); + + assert!(file_contains!(site_path, "public/new-posts/simple/index.html", "simple")); +} diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index cd00ab91..60118efb 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -22,7 +22,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. use std::env; -use std::fs::{remove_dir_all, File}; +use std::fs::{remove_dir_all, File, read_dir}; use std::io::{self, Read}; use std::path::{Path, PathBuf, MAIN_SEPARATOR}; use std::sync::mpsc::channel; @@ -225,7 +225,7 @@ pub fn serve( .bind(&address) .expect("Can't start the webserver") .shutdown_timeout(20); - println!("Web server is available at http://{}", &address); + println!("Web server is available at http://{}\n", &address); s.run(); }); // The websocket for livereload @@ -286,11 +286,122 @@ pub fn serve( use notify::DebouncedEvent::*; + let reload_templates = |site: &mut Site, path: &Path| { + let msg = if path.is_dir() { + format!("-> Directory in `templates` folder changed {}", path.display()) + } else { + format!("-> Template changed {}", path.display()) + }; + console::info(&msg); + if let Some(ref broadcaster) = broadcaster { + // Force refresh + rebuild_done_handling( + broadcaster, + rebuild::after_template_change(site, &path), + "/x.js", + ); + } + }; + + let reload_sass = |site: &Site, path: &Path, partial_path: &Path| { + let msg = if path.is_dir() { + format!("-> Directory in `sass` folder changed {}", path.display()) + } else { + format!("-> Sass file changed {}", path.display()) + }; + console::info(&msg); + if let Some(ref broadcaster) = broadcaster { + rebuild_done_handling( + &broadcaster, + site.compile_sass(&site.base_path), + &partial_path.to_string_lossy(), + ); + } + }; + + let copy_static = |site: &Site, path: &Path, partial_path: &Path| { + // Do nothing if the file/dir was deleted + if !path.exists() { + return; + } + + let msg = if path.is_dir() { + format!("-> Directory in `static` folder changed {}", path.display()) + } else { + format!("-> Static file changed {}", path.display()) + }; + + console::info(&msg); + if let Some(ref broadcaster) = broadcaster { + if path.is_dir() { + rebuild_done_handling( + broadcaster, + site.copy_static_directories(), + &path.to_string_lossy(), + ); + } else { + rebuild_done_handling( + broadcaster, + copy_file(&path, &site.output_path, &site.static_path), + &partial_path.to_string_lossy(), + ); + } + } + }; + loop { match rx.recv() { Ok(event) => { match event { - Create(path) | Write(path) | Remove(path) | Rename(_, path) => { + Rename(old_path, path) => { + if path.is_file() && is_temp_file(&path) { + continue; + } + let (change_kind, partial_path) = detect_change_kind(&pwd, &path); + + // We only care about changes in non-empty folders + if path.is_dir() && is_folder_empty(&path) { + continue; + } + + println!( + "Change detected @ {}", + Local::now().format("%Y-%m-%d %H:%M:%S").to_string() + ); + + let start = Instant::now(); + match change_kind { + ChangeKind::Content => { + console::info(&format!("-> Content renamed {}", path.display())); + if let Some(ref broadcaster) = broadcaster { + // Force refresh + rebuild_done_handling( + broadcaster, + rebuild::after_content_rename(&mut site, &old_path, &path), + "/x.js", + ); + } + } + ChangeKind::Templates => reload_templates(&mut site, &path), + ChangeKind::StaticFiles => copy_static(&site, &path, &partial_path), + ChangeKind::Sass => reload_sass(&site, &path, &partial_path), + ChangeKind::Config => { + console::info("-> Config changed. The whole site will be reloaded. The browser needs to be refreshed to make the changes visible."); + site = create_new_site( + interface, + port, + output_dir, + base_url, + config_file, + ) + .unwrap() + .0; + } + } + console::report_elapsed_time(start); + + } + Create(path) | Write(path) | Remove(path) => { if is_temp_file(&path) || path.is_dir() { continue; } @@ -299,6 +410,7 @@ pub fn serve( "Change detected @ {}", Local::now().format("%Y-%m-%d %H:%M:%S").to_string() ); + let start = Instant::now(); match detect_change_kind(&pwd, &path) { (ChangeKind::Content, _) => { @@ -312,42 +424,9 @@ pub fn serve( ); } } - (ChangeKind::Templates, _) => { - console::info(&format!("-> Template changed {}", path.display())); - if let Some(ref broadcaster) = broadcaster { - // Force refresh - rebuild_done_handling( - broadcaster, - rebuild::after_template_change(&mut site, &path), - "/x.js", - ); - } - } - (ChangeKind::StaticFiles, p) => { - if path.is_file() { - console::info(&format!( - "-> Static file changes detected {}", - path.display() - )); - if let Some(ref broadcaster) = broadcaster { - rebuild_done_handling( - broadcaster, - copy_file(&path, &site.output_path, &site.static_path), - &p.to_string_lossy(), - ); - } - } - } - (ChangeKind::Sass, p) => { - console::info(&format!("-> Sass file changed {}", path.display())); - if let Some(ref broadcaster) = broadcaster { - rebuild_done_handling( - &broadcaster, - site.compile_sass(&site.base_path), - &p.to_string_lossy(), - ); - } - } + (ChangeKind::Templates, _) => reload_templates(&mut site, &path), + (ChangeKind::StaticFiles, p) => copy_static(&site, &path, &p), + (ChangeKind::Sass, p) => reload_sass(&site, &path, &p), (ChangeKind::Config, _) => { console::info("-> Config changed. The whole site will be reloaded. The browser needs to be refreshed to make the changes visible."); site = create_new_site( @@ -421,6 +500,18 @@ fn detect_change_kind(pwd: &Path, path: &Path) -> (ChangeKind, PathBuf) { (change_kind, partial_path) } +/// Check if the directory at path contains any file +fn is_folder_empty(dir: &Path) -> bool { + // Can panic if we don't have the rights I guess? + for _ in read_dir(dir).expect("Failed to read a directory to see if it was empty") { + // If we get there, that means we have a file + return false; + } + + true +} + + #[cfg(test)] mod tests { use std::path::{Path, PathBuf};