diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index b75a8cf5c..df62ae9ed 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -7,7 +7,6 @@ pub mod tpls; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; -use std::fs::{remove_dir_all, remove_file}; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex, RwLock}; @@ -18,13 +17,13 @@ use libs::walkdir::{DirEntry, WalkDir}; use config::{get_config, Config, IndexFormat}; use content::{Library, Page, Paginator, Section, Taxonomy}; -use errors::{anyhow, bail, Context as ErrorContext, Result}; +use errors::{anyhow, bail, Result}; use libs::relative_path::RelativePathBuf; use std::time::Instant; use templates::{load_tera, render_redirect_template}; use utils::fs::{ - copy_directory, copy_file_if_needed, create_directory, create_file, ensure_directory_exists, - is_dotfile, + clean_site_output_folder, copy_directory, copy_file_if_needed, create_directory, create_file, + ensure_directory_exists, }; use utils::net::{get_available_port, is_external_link}; use utils::templates::{render_template, ShortcodeDefinition}; @@ -613,34 +612,7 @@ impl Site { /// Deletes the `public` directory if it exists and the `preserve_dotfiles_in_output` option is set to false, /// or if set to true: its contents except for the dotfiles at the root level. pub fn clean(&self) -> Result<()> { - if self.output_path.exists() { - if !self.config.preserve_dotfiles_in_output { - return remove_dir_all(&self.output_path) - .context("Couldn't delete output directory"); - } - - for entry in self.output_path.read_dir().context(format!( - "Couldn't read output directory `{}`", - self.output_path.display() - ))? { - let entry = entry.context("Couldn't read entry in output directory")?.path(); - - // Skip dotfiles if the preserve_dotfiles_in_output configuration option is set - if is_dotfile(&entry) { - continue; - } - - if entry.is_dir() { - remove_dir_all(entry) - .context("Couldn't delete folder while cleaning the output directory")?; - } else { - remove_file(entry) - .context("Couldn't delete file while cleaning the output directory")?; - } - } - } - - Ok(()) + clean_site_output_folder(&self.output_path, self.config.preserve_dotfiles_in_output) } /// Handles whether to write to disk or to memory diff --git a/components/utils/src/fs.rs b/components/utils/src/fs.rs index 17fc5e746..8a53df148 100644 --- a/components/utils/src/fs.rs +++ b/components/utils/src/fs.rs @@ -1,6 +1,6 @@ use libs::filetime::{set_file_mtime, FileTime}; use libs::walkdir::WalkDir; -use std::fs::{copy, create_dir_all, metadata, File}; +use std::fs::{copy, create_dir_all, metadata, remove_dir_all, remove_file, File}; use std::io::prelude::*; use std::path::Path; use std::time::SystemTime; @@ -201,6 +201,41 @@ pub fn is_temp_file(path: &Path) -> bool { } } +/// Deletes the `output_path` directory if it exists and `preserve_dotfiles_in_output` is set to false, +/// or if set to true: its contents except for the dotfiles at the root level. +pub fn clean_site_output_folder( + output_path: &Path, + preserve_dotfiles_in_output: bool, +) -> Result<()> { + if output_path.exists() { + if !preserve_dotfiles_in_output { + return remove_dir_all(output_path).context("Couldn't delete output directory"); + } + + for entry in output_path + .read_dir() + .context(format!("Couldn't read output directory `{}`", output_path.display()))? + { + let entry = entry.context("Couldn't read entry in output directory")?.path(); + + // Skip dotfiles if the preserve_dotfiles_in_output configuration option is set + if is_dotfile(&entry) { + continue; + } + + if entry.is_dir() { + remove_dir_all(entry) + .context("Couldn't delete folder while cleaning the output directory")?; + } else { + remove_file(entry) + .context("Couldn't delete file while cleaning the output directory")?; + } + } + } + + Ok(()) +} + #[cfg(test)] mod tests { use std::fs::{metadata, read_to_string, File}; diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 0ec4321dc..52b1d585b 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -21,7 +21,7 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -use std::fs::{read_dir, remove_dir_all}; +use std::fs::read_dir; use std::net::{SocketAddrV4, TcpListener}; use std::path::{Path, PathBuf, MAIN_SEPARATOR}; use std::sync::mpsc::channel; @@ -47,7 +47,7 @@ use errors::{anyhow, Context, Result}; use pathdiff::diff_paths; use site::sass::compile_sass; use site::{Site, SITE_CONTENT}; -use utils::fs::{copy_file, is_temp_file}; +use utils::fs::{clean_site_output_folder, copy_file, is_temp_file}; use crate::messages; use std::ffi::OsStr; @@ -441,12 +441,14 @@ pub fn serve( watchers.join(",") ); + let preserve_dotfiles_in_output = site.config.preserve_dotfiles_in_output; + println!("Press Ctrl+C to stop\n"); - // Delete the output folder on ctrl+C + // Clean the output folder on ctrl+C ctrlc::set_handler(move || { - match remove_dir_all(&output_path) { + match clean_site_output_folder(&output_path, preserve_dotfiles_in_output) { Ok(()) => (), - Err(e) => println!("Errored while deleting output folder: {}", e), + Err(e) => println!("Errored while cleaning output folder: {}", e), } ::std::process::exit(0); })