Browse Source

Handle file/dir renaming

Closes #385
index-subcmd
Vincent Prouillet 5 years ago
parent
commit
afc30543cc
6 changed files with 307 additions and 73 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +12
    -12
      Cargo.lock
  3. +18
    -18
      components/library/src/library.rs
  4. +47
    -1
      components/rebuild/src/lib.rs
  5. +102
    -6
      components/rebuild/tests/rebuild.rs
  6. +127
    -36
      src/cmd/serve.rs

+ 1
- 0
CHANGELOG.md View File

@@ -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)



+ 12
- 12
Cargo.lock View File

@@ -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"


+ 18
- 18
components/library/src/library.rs View File

@@ -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<P: AsRef<Path>>(&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<P: AsRef<Path>>(&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<P: AsRef<Path>>(&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<P: AsRef<Path>>(&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<P: AsRef<Path>>(&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<Section> {
if let Some(k) = self.paths_to_sections.remove(path) {
pub fn remove_section<P: AsRef<Path>>(&mut self, path: P) -> Option<Section> {
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<Page> {
if let Some(k) = self.paths_to_pages.remove(path) {
pub fn remove_page<P: AsRef<Path>>(&mut self, path: P) -> Option<Page> {
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<P: AsRef<Path>>(&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<P: AsRef<Path>>(&self, path: P) -> bool {
self.paths_to_pages.contains_key(path.as_ref())
}
}

+ 47
- 1
components/rebuild/src/lib.rs View File

@@ -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";


+ 102
- 6
components/rebuild/tests/rebuild.rs View File

@@ -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"
"<h1>first</h1><h1>second</h1>"
));
}

#[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"));
}

+ 127
- 36
src/cmd/serve.rs View File

@@ -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,12 +286,81 @@ 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) => {
if is_temp_file(&path) || path.is_dir() {
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;
}

@@ -299,55 +368,65 @@ 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, _) => {
console::info(&format!("-> Content changed {}", path.display()));
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_change(&mut site, &path),
rebuild::after_content_rename(&mut site, &old_path, &path),
"/x.js",
);
}
}
(ChangeKind::Templates, _) => {
console::info(&format!("-> Template changed {}", path.display()));
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;
}

println!(
"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, _) => {
console::info(&format!("-> Content changed {}", path.display()));
if let Some(ref broadcaster) = broadcaster {
// Force refresh
rebuild_done_handling(
broadcaster,
rebuild::after_template_change(&mut site, &path),
rebuild::after_content_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};


Loading…
Cancel
Save