|
22 | 22 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
23 | 23 |
|
24 | 24 | use std::collections::HashMap;
|
25 |
| -use std::env; |
26 | 25 | use std::fs::{read_dir, remove_dir_all};
|
27 |
| -use std::path::{Path, PathBuf, MAIN_SEPARATOR}; |
| 26 | +use std::path::{Path, PathBuf}; |
28 | 27 | use std::sync::mpsc::channel;
|
29 | 28 | use std::thread;
|
30 | 29 | use std::time::{Duration, Instant};
|
@@ -58,6 +57,13 @@ enum ChangeKind {
|
58 | 57 | Config,
|
59 | 58 | }
|
60 | 59 |
|
| 60 | +#[derive(Debug, PartialEq)] |
| 61 | +enum WatchMode { |
| 62 | + Required, |
| 63 | + Optional, |
| 64 | + Condition(bool) |
| 65 | +} |
| 66 | + |
61 | 67 | static INTERNAL_SERVER_ERROR_TEXT: &[u8] = b"Internal Server Error";
|
62 | 68 | static METHOD_NOT_ALLOWED_TEXT: &[u8] = b"Method Not Allowed";
|
63 | 69 | static NOT_FOUND_TEXT: &[u8] = b"Not Found";
|
@@ -234,43 +240,42 @@ pub fn serve(
|
234 | 240 | )?;
|
235 | 241 | console::report_elapsed_time(start);
|
236 | 242 |
|
| 243 | + // An array of (path, bool, bool) where the path should be watched for changes, and the boolean value |
| 244 | + // indicates whether this file/folder must exist for zola serve to operate |
| 245 | + let watch_this = vec!( |
| 246 | + ("config.toml", WatchMode::Required), |
| 247 | + ("content", WatchMode::Required), |
| 248 | + ("sass", WatchMode::Condition(site.config.compile_sass)), |
| 249 | + ("static", WatchMode::Optional), |
| 250 | + ("templates", WatchMode::Optional), |
| 251 | + ("themes", WatchMode::Condition(site.config.theme.is_some())) |
| 252 | + ); |
| 253 | + |
237 | 254 | // Setup watchers
|
238 |
| - let mut watching_static = false; |
239 |
| - let mut watching_templates = false; |
240 |
| - let mut watching_themes = false; |
241 | 255 | let (tx, rx) = channel();
|
242 | 256 | let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap();
|
243 |
| - watcher |
244 |
| - .watch("content/", RecursiveMode::Recursive) |
245 |
| - .map_err(|e| ZolaError::chain("Can't watch the `content` folder. Does it exist?", e))?; |
246 |
| - watcher |
247 |
| - .watch(config_file, RecursiveMode::Recursive) |
248 |
| - .map_err(|e| ZolaError::chain("Can't watch the `config` file. Does it exist?", e))?; |
249 |
| - |
250 |
| - if Path::new("static").exists() { |
251 |
| - watching_static = true; |
252 |
| - watcher |
253 |
| - .watch("static/", RecursiveMode::Recursive) |
254 |
| - .map_err(|e| ZolaError::chain("Can't watch the `static` folder.", e))?; |
255 |
| - } |
256 |
| - |
257 |
| - if Path::new("templates").exists() { |
258 |
| - watching_templates = true; |
259 |
| - watcher |
260 |
| - .watch("templates/", RecursiveMode::Recursive) |
261 |
| - .map_err(|e| ZolaError::chain("Can't watch the `templates` folder.", e))?; |
262 |
| - } |
263 | 257 |
|
264 |
| - if Path::new("themes").exists() { |
265 |
| - watching_themes = true; |
266 |
| - watcher |
267 |
| - .watch("themes/", RecursiveMode::Recursive) |
268 |
| - .map_err(|e| ZolaError::chain("Can't watch the `themes` folder.", e))?; |
| 258 | + // We watch for changes on the filesystem for every entry in watch_this |
| 259 | + // Will fail if either: |
| 260 | + // - the path is mandatory but does not exist (eg. config.toml) |
| 261 | + // - the path exists but has incorrect permissions |
| 262 | + // watchers will contain the paths we're actually watching |
| 263 | + let mut watchers = Vec::new(); |
| 264 | + for (entry, mode) in watch_this { |
| 265 | + let watch_path = root_dir.join(entry); |
| 266 | + let should_watch = match mode { |
| 267 | + WatchMode::Required => true, |
| 268 | + WatchMode::Optional => watch_path.exists(), |
| 269 | + WatchMode::Condition(b) => b |
| 270 | + }; |
| 271 | + if should_watch { |
| 272 | + watcher |
| 273 | + .watch(root_dir.join(entry), RecursiveMode::Recursive) |
| 274 | + .map_err(|e| ZolaError::chain(format!("Can't watch `{}` for changes in folder `{}`. Do you have correct permissions?", entry, root_dir.display()), e))?; |
| 275 | + watchers.push(entry.to_string()); |
| 276 | + } |
269 | 277 | }
|
270 | 278 |
|
271 |
| - // Sass support is optional so don't make it an error to no have a sass folder |
272 |
| - let _ = watcher.watch("sass/", RecursiveMode::Recursive); |
273 |
| - |
274 | 279 | let ws_address = format!("{}:{}", interface, site.live_reload.unwrap());
|
275 | 280 | let output_path = Path::new(output_dir).to_path_buf();
|
276 | 281 |
|
@@ -339,26 +344,9 @@ pub fn serve(
|
339 | 344 | None
|
340 | 345 | };
|
341 | 346 |
|
342 |
| - let pwd = env::current_dir().unwrap(); |
343 |
| - |
344 |
| - let mut watchers = vec!["content", "config.toml"]; |
345 |
| - if watching_static { |
346 |
| - watchers.push("static"); |
347 |
| - } |
348 |
| - if watching_templates { |
349 |
| - watchers.push("templates"); |
350 |
| - } |
351 |
| - if watching_themes { |
352 |
| - watchers.push("themes"); |
353 |
| - } |
354 |
| - if site.config.compile_sass { |
355 |
| - watchers.push("sass"); |
356 |
| - } |
357 |
| - |
358 | 347 | println!(
|
359 |
| - "Listening for changes in {}{}{{{}}}", |
360 |
| - pwd.display(), |
361 |
| - MAIN_SEPARATOR, |
| 348 | + "Listening for changes in {}{{{}}}", |
| 349 | + root_dir.display(), |
362 | 350 | watchers.join(", ")
|
363 | 351 | );
|
364 | 352 |
|
@@ -460,7 +448,7 @@ pub fn serve(
|
460 | 448 | if path.is_file() && is_temp_file(&path) {
|
461 | 449 | continue;
|
462 | 450 | }
|
463 |
| - let (change_kind, partial_path) = detect_change_kind(&pwd, &path); |
| 451 | + let (change_kind, partial_path) = detect_change_kind(&root_dir, &path); |
464 | 452 |
|
465 | 453 | // We only care about changes in non-empty folders
|
466 | 454 | if path.is_dir() && is_folder_empty(&path) {
|
@@ -522,7 +510,7 @@ pub fn serve(
|
522 | 510 | );
|
523 | 511 |
|
524 | 512 | let start = Instant::now();
|
525 |
| - match detect_change_kind(&pwd, &path) { |
| 513 | + match detect_change_kind(&root_dir, &path) { |
526 | 514 | (ChangeKind::Content, _) => {
|
527 | 515 | console::info(&format!("-> Content changed {}", path.display()));
|
528 | 516 | // Force refresh
|
|
0 commit comments