From b003a47d549c92a7210965df8095e1a6dc4b32db Mon Sep 17 00:00:00 2001 From: southerntofu <52931252+southerntofu@users.noreply.github.com> Date: Wed, 29 Jul 2020 18:08:25 +0000 Subject: [PATCH] Support relative links for root directory (fix #1028) (#1106) * serve command works from another working directory * Root dir path is expanded (canonicalized) for relative links (#1028) * Simplify watchers code * Only watch sass/themes folders when they are enabled in config Co-authored-by: southerntofu --- src/cmd/serve.rs | 96 +++++++++++++++++++++--------------------------- src/main.rs | 2 +- 2 files changed, 43 insertions(+), 55 deletions(-) diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 8675746b..5637c08d 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -22,9 +22,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. use std::collections::HashMap; -use std::env; use std::fs::{read_dir, remove_dir_all}; -use std::path::{Path, PathBuf, MAIN_SEPARATOR}; +use std::path::{Path, PathBuf}; use std::sync::mpsc::channel; use std::thread; use std::time::{Duration, Instant}; @@ -58,6 +57,13 @@ enum ChangeKind { Config, } +#[derive(Debug, PartialEq)] +enum WatchMode { + Required, + Optional, + Condition(bool) +} + static INTERNAL_SERVER_ERROR_TEXT: &[u8] = b"Internal Server Error"; static METHOD_NOT_ALLOWED_TEXT: &[u8] = b"Method Not Allowed"; static NOT_FOUND_TEXT: &[u8] = b"Not Found"; @@ -234,43 +240,42 @@ pub fn serve( )?; console::report_elapsed_time(start); + // An array of (path, bool, bool) where the path should be watched for changes, and the boolean value + // indicates whether this file/folder must exist for zola serve to operate + let watch_this = vec!( + ("config.toml", WatchMode::Required), + ("content", WatchMode::Required), + ("sass", WatchMode::Condition(site.config.compile_sass)), + ("static", WatchMode::Optional), + ("templates", WatchMode::Optional), + ("themes", WatchMode::Condition(site.config.theme.is_some())) + ); + // Setup watchers - let mut watching_static = false; - let mut watching_templates = false; - let mut watching_themes = false; let (tx, rx) = channel(); let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); - watcher - .watch("content/", RecursiveMode::Recursive) - .map_err(|e| ZolaError::chain("Can't watch the `content` folder. Does it exist?", e))?; - watcher - .watch(config_file, RecursiveMode::Recursive) - .map_err(|e| ZolaError::chain("Can't watch the `config` file. Does it exist?", e))?; - if Path::new("static").exists() { - watching_static = true; - watcher - .watch("static/", RecursiveMode::Recursive) - .map_err(|e| ZolaError::chain("Can't watch the `static` folder.", e))?; + // We watch for changes on the filesystem for every entry in watch_this + // Will fail if either: + // - the path is mandatory but does not exist (eg. config.toml) + // - the path exists but has incorrect permissions + // watchers will contain the paths we're actually watching + let mut watchers = Vec::new(); + for (entry, mode) in watch_this { + let watch_path = root_dir.join(entry); + let should_watch = match mode { + WatchMode::Required => true, + WatchMode::Optional => watch_path.exists(), + WatchMode::Condition(b) => b + }; + if should_watch { + watcher + .watch(root_dir.join(entry), RecursiveMode::Recursive) + .map_err(|e| ZolaError::chain(format!("Can't watch `{}` for changes in folder `{}`. Do you have correct permissions?", entry, root_dir.display()), e))?; + watchers.push(entry.to_string()); + } } - if Path::new("templates").exists() { - watching_templates = true; - watcher - .watch("templates/", RecursiveMode::Recursive) - .map_err(|e| ZolaError::chain("Can't watch the `templates` folder.", e))?; - } - - if Path::new("themes").exists() { - watching_themes = true; - watcher - .watch("themes/", RecursiveMode::Recursive) - .map_err(|e| ZolaError::chain("Can't watch the `themes` folder.", e))?; - } - - // Sass support is optional so don't make it an error to no have a sass folder - let _ = watcher.watch("sass/", RecursiveMode::Recursive); - let ws_address = format!("{}:{}", interface, site.live_reload.unwrap()); let output_path = Path::new(output_dir).to_path_buf(); @@ -339,26 +344,9 @@ pub fn serve( None }; - let pwd = env::current_dir().unwrap(); - - let mut watchers = vec!["content", "config.toml"]; - if watching_static { - watchers.push("static"); - } - if watching_templates { - watchers.push("templates"); - } - if watching_themes { - watchers.push("themes"); - } - if site.config.compile_sass { - watchers.push("sass"); - } - println!( - "Listening for changes in {}{}{{{}}}", - pwd.display(), - MAIN_SEPARATOR, + "Listening for changes in {}{{{}}}", + root_dir.display(), watchers.join(", ") ); @@ -460,7 +448,7 @@ pub fn serve( if path.is_file() && is_temp_file(&path) { continue; } - let (change_kind, partial_path) = detect_change_kind(&pwd, &path); + let (change_kind, partial_path) = detect_change_kind(&root_dir, &path); // We only care about changes in non-empty folders if path.is_dir() && is_folder_empty(&path) { @@ -522,7 +510,7 @@ pub fn serve( ); let start = Instant::now(); - match detect_change_kind(&pwd, &path) { + match detect_change_kind(&root_dir, &path) { (ChangeKind::Content, _) => { console::info(&format!("-> Content changed {}", path.display())); // Force refresh diff --git a/src/main.rs b/src/main.rs index 8676db6a..7d60b7a5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ fn main() { let root_dir = match matches.value_of("root").unwrap() { "." => env::current_dir().unwrap(), - path => PathBuf::from(path), + path => PathBuf::from(path).canonicalize().expect(&format!("Cannot find root directory: {}", path)), }; let config_file = match matches.value_of("config") { Some(path) => PathBuf::from(path),