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 <southerntofu@thunix.net>
This commit is contained in:
southerntofu 2020-07-29 18:08:25 +00:00 committed by GitHub
parent 7e7bf2bcd3
commit b003a47d54
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 55 deletions

View file

@ -22,9 +22,8 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
use std::collections::HashMap; use std::collections::HashMap;
use std::env;
use std::fs::{read_dir, remove_dir_all}; 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::sync::mpsc::channel;
use std::thread; use std::thread;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
@ -58,6 +57,13 @@ enum ChangeKind {
Config, Config,
} }
#[derive(Debug, PartialEq)]
enum WatchMode {
Required,
Optional,
Condition(bool)
}
static INTERNAL_SERVER_ERROR_TEXT: &[u8] = b"Internal Server Error"; static INTERNAL_SERVER_ERROR_TEXT: &[u8] = b"Internal Server Error";
static METHOD_NOT_ALLOWED_TEXT: &[u8] = b"Method Not Allowed"; static METHOD_NOT_ALLOWED_TEXT: &[u8] = b"Method Not Allowed";
static NOT_FOUND_TEXT: &[u8] = b"Not Found"; static NOT_FOUND_TEXT: &[u8] = b"Not Found";
@ -234,43 +240,42 @@ pub fn serve(
)?; )?;
console::report_elapsed_time(start); 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 // Setup watchers
let mut watching_static = false;
let mut watching_templates = false;
let mut watching_themes = false;
let (tx, rx) = channel(); let (tx, rx) = channel();
let mut watcher = watcher(tx, Duration::from_secs(1)).unwrap(); 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() { // We watch for changes on the filesystem for every entry in watch_this
watching_static = true; // 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 watcher
.watch("static/", RecursiveMode::Recursive) .watch(root_dir.join(entry), RecursiveMode::Recursive)
.map_err(|e| ZolaError::chain("Can't watch the `static` folder.", e))?; .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 ws_address = format!("{}:{}", interface, site.live_reload.unwrap());
let output_path = Path::new(output_dir).to_path_buf(); let output_path = Path::new(output_dir).to_path_buf();
@ -339,26 +344,9 @@ pub fn serve(
None 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!( println!(
"Listening for changes in {}{}{{{}}}", "Listening for changes in {}{{{}}}",
pwd.display(), root_dir.display(),
MAIN_SEPARATOR,
watchers.join(", ") watchers.join(", ")
); );
@ -460,7 +448,7 @@ pub fn serve(
if path.is_file() && is_temp_file(&path) { if path.is_file() && is_temp_file(&path) {
continue; 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 // We only care about changes in non-empty folders
if path.is_dir() && is_folder_empty(&path) { if path.is_dir() && is_folder_empty(&path) {
@ -522,7 +510,7 @@ pub fn serve(
); );
let start = Instant::now(); let start = Instant::now();
match detect_change_kind(&pwd, &path) { match detect_change_kind(&root_dir, &path) {
(ChangeKind::Content, _) => { (ChangeKind::Content, _) => {
console::info(&format!("-> Content changed {}", path.display())); console::info(&format!("-> Content changed {}", path.display()));
// Force refresh // Force refresh

View file

@ -14,7 +14,7 @@ fn main() {
let root_dir = match matches.value_of("root").unwrap() { let root_dir = match matches.value_of("root").unwrap() {
"." => env::current_dir().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") { let config_file = match matches.value_of("config") {
Some(path) => PathBuf::from(path), Some(path) => PathBuf::from(path),