@@ -18,7 +18,7 @@ dependencies = [ | |||||
"slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | "slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | "staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"syntect 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | "syntect 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"tera 0.8.0 (git+https://github.com/Keats/tera)", | |||||
"tera 0.8.0 (git+https://github.com/Keats/tera?branch=reload)", | |||||
"toml 0.3.1 (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)", | "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"ws 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", | "ws 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
@@ -774,7 +774,7 @@ dependencies = [ | |||||
[[package]] | [[package]] | ||||
name = "tera" | name = "tera" | ||||
version = "0.8.0" | version = "0.8.0" | ||||
source = "git+https://github.com/Keats/tera#2eb55de231e08da50ca32a443499fbce8d9003e0" | |||||
source = "git+https://github.com/Keats/tera?branch=reload#31f8bd8238e3e6bdef9ecf4468079c535609b5eb" | |||||
dependencies = [ | dependencies = [ | ||||
"chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | "chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
"error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", | ||||
@@ -1095,7 +1095,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||||
"checksum syn 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)" = "480c834701caba3548aa991e54677281be3a5414a9d09ddbdf4ed74a569a9d19" | "checksum syn 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)" = "480c834701caba3548aa991e54677281be3a5414a9d09ddbdf4ed74a569a9d19" | ||||
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" | "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" | ||||
"checksum syntect 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f79be04af68d5fa09e71b3274159a955a25f25a5cbfba9a6ff64139b71d848a" | "checksum syntect 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f79be04af68d5fa09e71b3274159a955a25f25a5cbfba9a6ff64139b71d848a" | ||||
"checksum tera 0.8.0 (git+https://github.com/Keats/tera)" = "<none>" | |||||
"checksum tera 0.8.0 (git+https://github.com/Keats/tera?branch=reload)" = "<none>" | |||||
"checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a" | "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-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" | "checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7" | ||||
@@ -20,7 +20,7 @@ glob = "0.2" | |||||
serde = "0.9" | serde = "0.9" | ||||
serde_json = "0.9" | serde_json = "0.9" | ||||
serde_derive = "0.9" | serde_derive = "0.9" | ||||
tera = { git = "https://github.com/Keats/tera", branch = "master" } | |||||
tera = { git = "https://github.com/Keats/tera", branch = "reload" } | |||||
# tera = "0.8" | # tera = "0.8" | ||||
slug = "0.1" | slug = "0.1" | ||||
syntect = "1" | syntect = "1" | ||||
@@ -87,24 +87,29 @@ pub fn serve(interface: &str, port: &str) -> Result<()> { | |||||
println!("Change detected, rebuilding site"); | println!("Change detected, rebuilding site"); | ||||
let what_changed = detect_change_kind(&pwd, &path); | let what_changed = detect_change_kind(&pwd, &path); | ||||
let mut reload_path = String::new(); | |||||
match what_changed { | match what_changed { | ||||
ChangeKind::Content => println!("Content changed {}", path.display()), | |||||
ChangeKind::Templates => println!("Template changed {}", path.display()), | |||||
ChangeKind::StaticFiles => println!("Static file changes detected {}", path.display()), | |||||
(ChangeKind::Content, _) => println!("Content changed {}", path.display()), | |||||
(ChangeKind::Templates, _) => println!("Template changed {}", path.display()), | |||||
(ChangeKind::StaticFiles, p) => { | |||||
reload_path = p; | |||||
println!("Static file changes detected {}", path.display()); | |||||
}, | |||||
}; | }; | ||||
println!("Reloading {}", reload_path); | |||||
let start = Instant::now(); | let start = Instant::now(); | ||||
match site.rebuild() { | match site.rebuild() { | ||||
Ok(_) => { | Ok(_) => { | ||||
println!("Done in {:.1}s.", time_elapsed(start)); | |||||
broadcaster.send(r#" | |||||
{ | |||||
println!("Done in {:.1}s.\n", time_elapsed(start)); | |||||
broadcaster.send(format!(r#" | |||||
{{ | |||||
"command": "reload", | "command": "reload", | ||||
"path": "", | |||||
"path": "{}", | |||||
"originalPath": "", | "originalPath": "", | ||||
"liveCSS": true, | "liveCSS": true, | ||||
"liveImg": true, | "liveImg": true, | ||||
"protocol": ["http://livereload.com/protocols/official-7"] | "protocol": ["http://livereload.com/protocols/official-7"] | ||||
}"#).unwrap(); | |||||
}}"#, reload_path)).unwrap(); | |||||
}, | }, | ||||
Err(e) => { | Err(e) => { | ||||
println!("Failed to build the site"); | println!("Failed to build the site"); | ||||
@@ -160,7 +165,7 @@ fn is_temp_file(path: &Path) -> bool { | |||||
/// Detect what changed from the given path so we have an idea what needs | /// Detect what changed from the given path so we have an idea what needs | ||||
/// to be reloaded | /// to be reloaded | ||||
fn detect_change_kind(pwd: &str, path: &Path) -> ChangeKind { | |||||
fn detect_change_kind(pwd: &str, path: &Path) -> (ChangeKind, String) { | |||||
let path_str = format!("{}", path.display()) | let path_str = format!("{}", path.display()) | ||||
.replace(pwd, "") | .replace(pwd, "") | ||||
.replace("\\", "/"); | .replace("\\", "/"); | ||||
@@ -174,7 +179,7 @@ fn detect_change_kind(pwd: &str, path: &Path) -> ChangeKind { | |||||
panic!("Got a change in an unexpected path: {}", path_str); | panic!("Got a change in an unexpected path: {}", path_str); | ||||
}; | }; | ||||
change_kind | |||||
(change_kind, path_str) | |||||
} | } | ||||
#[cfg(test)] | #[cfg(test)] | ||||
@@ -206,9 +211,18 @@ mod tests { | |||||
#[test] | #[test] | ||||
fn test_can_detect_kind_of_changes() { | fn test_can_detect_kind_of_changes() { | ||||
let testcases = vec![ | let testcases = vec![ | ||||
(ChangeKind::Templates, "/home/vincent/site", Path::new("/home/vincent/site/templates/hello.html")), | |||||
(ChangeKind::StaticFiles, "/home/vincent/site", Path::new("/home/vincent/site/static/site.css")), | |||||
(ChangeKind::Content, "/home/vincent/site", Path::new("/home/vincent/site/content/posts/hello.md")), | |||||
( | |||||
(ChangeKind::Templates, "/templates/hello.html".to_string()), | |||||
"/home/vincent/site", Path::new("/home/vincent/site/templates/hello.html") | |||||
), | |||||
( | |||||
(ChangeKind::StaticFiles, "/static/site.css".to_string()), | |||||
"/home/vincent/site", Path::new("/home/vincent/site/static/site.css") | |||||
), | |||||
( | |||||
(ChangeKind::Content, "/content/posts/hello.md".to_string()), | |||||
"/home/vincent/site", Path::new("/home/vincent/site/content/posts/hello.md") | |||||
), | |||||
]; | ]; | ||||
for (expected, pwd, path) in testcases { | for (expected, pwd, path) in testcases { | ||||
@@ -1,11 +1,12 @@ | |||||
use std::collections::HashMap; | use std::collections::HashMap; | ||||
use std::iter::FromIterator; | use std::iter::FromIterator; | ||||
use std::fs::{create_dir, remove_dir_all}; | |||||
use std::fs::{create_dir, remove_dir_all, copy, remove_file}; | |||||
use std::path::Path; | use std::path::Path; | ||||
use glob::glob; | use glob::glob; | ||||
use tera::{Tera, Context}; | use tera::{Tera, Context}; | ||||
use slug::slugify; | use slug::slugify; | ||||
use walkdir::WalkDir; | |||||
use errors::{Result, ResultExt}; | use errors::{Result, ResultExt}; | ||||
use config::{Config, get_config}; | use config::{Config, get_config}; | ||||
@@ -98,7 +99,32 @@ impl Site { | |||||
} | } | ||||
/// Copy the content of the `static` folder into the `public` folder | /// Copy the content of the `static` folder into the `public` folder | ||||
pub fn copy_static_files(&self) -> Result<()> { | |||||
/// | |||||
/// TODO: only copy one file if possible because that would be a waster | |||||
/// to do re-copy the whole thing | |||||
pub fn copy_static_directory(&self) -> Result<()> { | |||||
let from = Path::new("static"); | |||||
let target = Path::new("public"); | |||||
for entry in WalkDir::new(from).into_iter().filter_map(|e| e.ok()) { | |||||
let relative_path = entry.path().strip_prefix(&from).unwrap(); | |||||
let target_path = { | |||||
let mut target_path = target.to_path_buf(); | |||||
target_path.push(relative_path); | |||||
target_path | |||||
}; | |||||
if entry.path().is_dir() { | |||||
if !target_path.exists() { | |||||
create_dir(&target_path)?; | |||||
} | |||||
} else { | |||||
if target_path.exists() { | |||||
remove_file(&target_path)?; | |||||
} | |||||
copy(entry.path(), &target_path)?; | |||||
} | |||||
} | |||||
Ok(()) | Ok(()) | ||||
} | } | ||||
@@ -106,6 +132,7 @@ impl Site { | |||||
/// Very dumb for now, ideally it would only rebuild what changed | /// Very dumb for now, ideally it would only rebuild what changed | ||||
pub fn rebuild(&mut self) -> Result<()> { | pub fn rebuild(&mut self) -> Result<()> { | ||||
self.parse_site()?; | self.parse_site()?; | ||||
self.templates.full_reload()?; | |||||
self.build() | self.build() | ||||
} | } | ||||
@@ -174,6 +201,7 @@ impl Site { | |||||
let index = self.templates.render("index.html", &context)?; | let index = self.templates.render("index.html", &context)?; | ||||
create_file(public.join("index.html"), &self.inject_livereload(index))?; | create_file(public.join("index.html"), &self.inject_livereload(index))?; | ||||
self.copy_static_directory()?; | |||||
Ok(()) | Ok(()) | ||||
} | } | ||||