mirror of
https://github.com/zyllian/zyllian.github.io.git
synced 2025-05-10 02:26:45 -07:00
Add Sass support
This commit is contained in:
parent
e06c4371f4
commit
5e1913c9de
9 changed files with 525 additions and 205 deletions
216
src/builder.rs
Normal file
216
src/builder.rs
Normal file
|
@ -0,0 +1,216 @@
|
|||
//! Module containing the site builder.
|
||||
|
||||
use std::{path::PathBuf, str::FromStr};
|
||||
|
||||
use anyhow::Context;
|
||||
use gray_matter::{engine::YAML, Matter};
|
||||
use handlebars::Handlebars;
|
||||
use lol_html::{element, html_content::ContentType, HtmlRewriter, Settings};
|
||||
use pulldown_cmark::{Options, Parser};
|
||||
use serde::Serialize;
|
||||
use walkdir::WalkDir;
|
||||
use warp::hyper::Uri;
|
||||
|
||||
use crate::{util, PageMetadata, Site, SASS_PATH, STATIC_PATH};
|
||||
|
||||
/// Struct containing data to be sent to templates when rendering them.
|
||||
#[derive(Debug, Serialize)]
|
||||
struct TemplateData<'a> {
|
||||
/// The rendered page.
|
||||
pub page: &'a str,
|
||||
}
|
||||
|
||||
/// Struct used to build the site.
|
||||
pub struct SiteBuilder<'a> {
|
||||
/// The matter instance used to extract front matter.
|
||||
matter: Matter<YAML>,
|
||||
/// The Handlebars registry used to render templates.
|
||||
pub(crate) reg: Handlebars<'a>,
|
||||
/// The site info used to build the site.
|
||||
pub site: Site,
|
||||
/// The path to the build directory.
|
||||
pub build_path: PathBuf,
|
||||
/// Whether the site is going to be served locally with the dev server.
|
||||
serving: bool,
|
||||
}
|
||||
|
||||
impl<'a> SiteBuilder<'a> {
|
||||
/// Creates a new site builder.
|
||||
pub fn new(site: Site, serving: bool) -> Self {
|
||||
let mut build_path = match &site.config.build {
|
||||
Some(build) => site.site_path.join(build),
|
||||
_ => site.site_path.join("build"),
|
||||
};
|
||||
if serving {
|
||||
build_path = site.site_path.join("build");
|
||||
}
|
||||
|
||||
Self {
|
||||
matter: Matter::new(),
|
||||
reg: Handlebars::new(),
|
||||
site,
|
||||
build_path,
|
||||
serving,
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepares the site builder for use.
|
||||
pub fn prepare(mut self) -> anyhow::Result<Self> {
|
||||
let build_static_path = self.build_path.join(STATIC_PATH);
|
||||
if std::fs::try_exists(&self.build_path)
|
||||
.context("Failed check if build directory exists")?
|
||||
{
|
||||
if build_static_path.exists() {
|
||||
std::fs::remove_dir_all(&build_static_path)
|
||||
.context("Failed to remove old static directory")?;
|
||||
}
|
||||
for entry in WalkDir::new(&self.build_path) {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if let Some(ext) = path.extension() {
|
||||
if ext == "html" {
|
||||
std::fs::remove_file(path).with_context(|| {
|
||||
format!("Failed to remove file at {}", path.display())
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::fs::create_dir(&self.build_path).context("Failed to create build directory")?;
|
||||
}
|
||||
|
||||
for (template_name, template_path) in &self.site.template_index {
|
||||
self.reg
|
||||
.register_template_file(template_name, template_path)
|
||||
.context("Failed to register template file")?;
|
||||
}
|
||||
|
||||
let static_path = self.site.site_path.join(STATIC_PATH);
|
||||
if static_path.exists() {
|
||||
fs_extra::copy_items(
|
||||
&[static_path],
|
||||
&self.build_path,
|
||||
&fs_extra::dir::CopyOptions::default(),
|
||||
)
|
||||
.context("Failed to copy static directory")?;
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Builds a page.
|
||||
pub fn build_page(&self, page_name: &str) -> anyhow::Result<()> {
|
||||
let page_path = self.site.page_index.get(page_name).unwrap();
|
||||
|
||||
let input = std::fs::read_to_string(page_path)
|
||||
.with_context(|| format!("Failed to read page at {}", page_path.display()))?;
|
||||
let page = self.matter.parse(&input);
|
||||
let page_metadata = if let Some(data) = page.data {
|
||||
data.deserialize()?
|
||||
} else {
|
||||
PageMetadata::default()
|
||||
};
|
||||
|
||||
let parser = Parser::new_ext(&page.content, Options::all());
|
||||
let mut page_html = String::new();
|
||||
pulldown_cmark::html::push_html(&mut page_html, parser);
|
||||
|
||||
let out = self.reg.render(
|
||||
&page_metadata.template.unwrap_or_else(|| "base".to_string()),
|
||||
&TemplateData { page: &page_html },
|
||||
)?;
|
||||
|
||||
let title = match &page_metadata.title {
|
||||
Some(page_title) => format!("{} / {}", self.site.config.title, page_title),
|
||||
_ => self.site.config.title.clone(),
|
||||
};
|
||||
|
||||
let mut output = Vec::new();
|
||||
let mut rewriter = HtmlRewriter::new(
|
||||
Settings {
|
||||
element_content_handlers: vec![
|
||||
element!("head", |el| {
|
||||
el.prepend(r#"<meta charset="utf-8">"#, ContentType::Html);
|
||||
el.append(&format!("<title>{}</title>", title), ContentType::Html);
|
||||
if self.serving {
|
||||
el.append(
|
||||
&format!(r#"<script src="/{}/_dev.js"></script>"#, STATIC_PATH),
|
||||
ContentType::Html,
|
||||
);
|
||||
} else {
|
||||
el.append(
|
||||
&format!(r#"<base href="{}">"#, &self.site.config.base_url),
|
||||
ContentType::Html,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}),
|
||||
element!("a", |el| {
|
||||
if let Some(href) = el.get_attribute("href") {
|
||||
if let Ok(uri) = Uri::from_str(&href) {
|
||||
if uri.host().is_some() {
|
||||
el.set_attribute("rel", "noopener noreferrer")?;
|
||||
el.set_attribute("target", "_blank")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
|c: &[u8]| output.extend_from_slice(c),
|
||||
);
|
||||
|
||||
rewriter.write(out.as_bytes())?;
|
||||
rewriter.end()?;
|
||||
|
||||
let out = String::from_utf8(output)?;
|
||||
|
||||
let out_path = self.build_path.join(page_name).with_extension("html");
|
||||
std::fs::create_dir_all(out_path.parent().unwrap())
|
||||
.with_context(|| format!("Failed to create directory for page {}", page_name))?;
|
||||
std::fs::write(&out_path, out).with_context(|| {
|
||||
format!(
|
||||
"Failed to create page file at {} for page {}",
|
||||
out_path.display(),
|
||||
page_name
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Builds the Sass styles in the site.
|
||||
pub fn build_sass(&self) -> anyhow::Result<()> {
|
||||
let styles_path = self.build_path.join("styles");
|
||||
if self.serving {
|
||||
util::remove_dir_contents(&styles_path)
|
||||
.context("Failed to remove old contents of styles directory")?;
|
||||
}
|
||||
let sass_path = self.site.site_path.join(SASS_PATH);
|
||||
for sheet in &self.site.config.sass_styles {
|
||||
let sheet_path = sass_path.join(sheet);
|
||||
if let Some(sheet_path) = sheet_path.to_str() {
|
||||
match grass::from_path(sheet_path, &grass::Options::default()) {
|
||||
Ok(css) => {
|
||||
std::fs::write(styles_path.join(sheet).with_extension("css"), css)
|
||||
.with_context(|| {
|
||||
format!("Failed to write new CSS file for Sass: {:?}", sheet)
|
||||
})?;
|
||||
}
|
||||
Err(e) => eprintln!(
|
||||
"Failed to compile Sass stylesheet at {:?}: {}",
|
||||
sheet_path, e
|
||||
),
|
||||
}
|
||||
} else {
|
||||
eprintln!("Sass stylesheet contains invalid UTF-8: {:?}", sheet_path);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
188
src/lib.rs
188
src/lib.rs
|
@ -1,27 +1,26 @@
|
|||
#![feature(path_try_exists)]
|
||||
#![feature(async_closure)]
|
||||
|
||||
mod builder;
|
||||
#[cfg(feature = "serve")]
|
||||
pub mod serving;
|
||||
mod util;
|
||||
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use gray_matter::{engine::yaml::YAML, matter::Matter};
|
||||
use handlebars::Handlebars;
|
||||
use lol_html::{element, html_content::ContentType, HtmlRewriter, Settings};
|
||||
use pulldown_cmark::{Options, Parser};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::Deserialize;
|
||||
use walkdir::WalkDir;
|
||||
use warp::hyper::Uri;
|
||||
|
||||
use builder::SiteBuilder;
|
||||
|
||||
const PAGES_PATH: &str = "pages";
|
||||
const TEMPLATES_PATH: &str = "templates";
|
||||
const STATIC_PATH: &str = "static";
|
||||
const SASS_PATH: &str = "sass";
|
||||
|
||||
/// Struct for the site's configuration.
|
||||
#[derive(Debug, Deserialize)]
|
||||
|
@ -34,19 +33,14 @@ pub struct SiteConfig {
|
|||
pub description: String,
|
||||
/// The site's build directory. Defaults to <site>/build if not specified.
|
||||
pub build: Option<String>,
|
||||
/// A list of Sass stylesheets that will be built.
|
||||
pub sass_styles: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
/// Struct for the front matter in templates. (nothing here yet)
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct TemplateMetadata {}
|
||||
|
||||
/// Struct containing data to be sent to templates when rendering them.
|
||||
#[derive(Debug, Serialize)]
|
||||
struct TemplateData<'a> {
|
||||
/// The rendered page.
|
||||
pub page: &'a str,
|
||||
}
|
||||
|
||||
/// Struct for the front matter in pages.
|
||||
#[derive(Debug, Default, Deserialize)]
|
||||
pub struct PageMetadata {
|
||||
|
@ -131,6 +125,7 @@ impl Site {
|
|||
let builder = SiteBuilder::new(self, false).prepare()?;
|
||||
|
||||
builder.site.build_all_pages(&builder)?;
|
||||
builder.build_sass()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -144,168 +139,3 @@ impl Site {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct used to build the site.
|
||||
struct SiteBuilder<'a> {
|
||||
/// The matter instance used to extract front matter.
|
||||
matter: Matter<YAML>,
|
||||
/// The Handlebars registry used to render templates.
|
||||
reg: Handlebars<'a>,
|
||||
/// The site info used to build the site.
|
||||
site: Site,
|
||||
/// The path to the build directory.
|
||||
build_path: PathBuf,
|
||||
/// Whether the site is going to be served locally with the dev server.
|
||||
serving: bool,
|
||||
}
|
||||
|
||||
impl<'a> SiteBuilder<'a> {
|
||||
/// Creates a new site builder.
|
||||
pub fn new(site: Site, serving: bool) -> Self {
|
||||
let mut build_path = match &site.config.build {
|
||||
Some(build) => site.site_path.join(build),
|
||||
_ => site.site_path.join("build"),
|
||||
};
|
||||
if serving {
|
||||
build_path = site.site_path.join("build");
|
||||
}
|
||||
|
||||
Self {
|
||||
matter: Matter::new(),
|
||||
reg: Handlebars::new(),
|
||||
site,
|
||||
build_path,
|
||||
serving,
|
||||
}
|
||||
}
|
||||
|
||||
/// Prepares the site builder for use.
|
||||
pub fn prepare(mut self) -> anyhow::Result<Self> {
|
||||
if std::fs::try_exists(&self.build_path)
|
||||
.context("Failed check if build directory exists")?
|
||||
{
|
||||
std::fs::remove_dir_all(self.build_path.join(STATIC_PATH))
|
||||
.context("Failed to remove static directory")?;
|
||||
for entry in WalkDir::new(&self.build_path) {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if let Some(ext) = path.extension() {
|
||||
if ext == "html" {
|
||||
std::fs::remove_file(path).with_context(|| {
|
||||
format!("Failed to remove file at {}", path.display())
|
||||
})?;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::fs::create_dir(&self.build_path).context("Failed to create build directory")?;
|
||||
}
|
||||
|
||||
for (template_name, template_path) in &self.site.template_index {
|
||||
self.reg
|
||||
.register_template_file(template_name, template_path)
|
||||
.context("Failed to register template file")?;
|
||||
}
|
||||
|
||||
fs_extra::copy_items(
|
||||
&[self.site.site_path.join(STATIC_PATH)],
|
||||
&self.build_path,
|
||||
&fs_extra::dir::CopyOptions::default(),
|
||||
)
|
||||
.context("Failed to copy static directory")?;
|
||||
|
||||
if self.serving {
|
||||
std::fs::write(
|
||||
self.build_path.join(format!("{}/_dev.js", STATIC_PATH)),
|
||||
include_str!("./refresh_websocket.js"),
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
/// Builds a page.
|
||||
pub fn build_page(&self, page_name: &str) -> anyhow::Result<()> {
|
||||
let page_path = self.site.page_index.get(page_name).unwrap();
|
||||
|
||||
let input = std::fs::read_to_string(page_path)
|
||||
.with_context(|| format!("Failed to read page at {}", page_path.display()))?;
|
||||
let page = self.matter.parse(&input);
|
||||
let page_metadata = if let Some(data) = page.data {
|
||||
data.deserialize()?
|
||||
} else {
|
||||
PageMetadata::default()
|
||||
};
|
||||
|
||||
let parser = Parser::new_ext(&page.content, Options::all());
|
||||
let mut page_html = String::new();
|
||||
pulldown_cmark::html::push_html(&mut page_html, parser);
|
||||
|
||||
let out = self.reg.render(
|
||||
&page_metadata.template.unwrap_or_else(|| "base".to_string()),
|
||||
&TemplateData { page: &page_html },
|
||||
)?;
|
||||
|
||||
let title = match &page_metadata.title {
|
||||
Some(page_title) => format!("{} / {}", self.site.config.title, page_title),
|
||||
_ => self.site.config.title.clone(),
|
||||
};
|
||||
|
||||
let mut output = Vec::new();
|
||||
let mut rewriter = HtmlRewriter::new(
|
||||
Settings {
|
||||
element_content_handlers: vec![
|
||||
element!("head", |el| {
|
||||
el.prepend(r#"<meta charset="utf-8">"#, ContentType::Html);
|
||||
el.append(&format!("<title>{}</title>", title), ContentType::Html);
|
||||
if self.serving {
|
||||
el.append(
|
||||
&format!(r#"<script src="/{}/_dev.js"></script>"#, STATIC_PATH),
|
||||
ContentType::Html,
|
||||
);
|
||||
} else {
|
||||
el.append(
|
||||
&format!(r#"<base href="{}">"#, &self.site.config.base_url),
|
||||
ContentType::Html,
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}),
|
||||
element!("a", |el| {
|
||||
if let Some(href) = el.get_attribute("href") {
|
||||
if let Ok(uri) = Uri::from_str(&href) {
|
||||
if uri.host().is_some() {
|
||||
el.set_attribute("rel", "noopener noreferrer")?;
|
||||
el.set_attribute("target", "_blank")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
|c: &[u8]| output.extend_from_slice(c),
|
||||
);
|
||||
|
||||
rewriter.write(out.as_bytes())?;
|
||||
rewriter.end()?;
|
||||
|
||||
let out = String::from_utf8(output)?;
|
||||
|
||||
let out_path = self.build_path.join(page_name).with_extension("html");
|
||||
std::fs::create_dir_all(out_path.parent().unwrap())
|
||||
.with_context(|| format!("Failed to create directory for page {}", page_name))?;
|
||||
std::fs::write(&out_path, out).with_context(|| {
|
||||
format!(
|
||||
"Failed to create page file at {} for page {}",
|
||||
out_path.display(),
|
||||
page_name
|
||||
)
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::{
|
|||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
use anyhow::Context;
|
||||
use futures::SinkExt;
|
||||
use hotwatch::{Event, Hotwatch};
|
||||
use warp::{
|
||||
|
@ -17,7 +18,7 @@ use warp::{
|
|||
Filter,
|
||||
};
|
||||
|
||||
use crate::{Site, SiteBuilder, PAGES_PATH, STATIC_PATH, TEMPLATES_PATH};
|
||||
use crate::{Site, SiteBuilder, PAGES_PATH, SASS_PATH, STATIC_PATH, TEMPLATES_PATH};
|
||||
|
||||
fn with_build_path(
|
||||
build_path: PathBuf,
|
||||
|
@ -44,6 +45,9 @@ fn create(
|
|||
relative_path: &Path,
|
||||
build: bool,
|
||||
) -> anyhow::Result<()> {
|
||||
if path.is_dir() {
|
||||
return Ok(());
|
||||
}
|
||||
if let Ok(page_path) = relative_path.strip_prefix(PAGES_PATH) {
|
||||
let (_page_name, page_name_str) = get_name(page_path);
|
||||
|
||||
|
@ -66,25 +70,40 @@ fn create(
|
|||
let new_config = serde_yaml::from_str(&std::fs::read_to_string(path)?)?;
|
||||
builder.site.config = new_config;
|
||||
builder.site.build_all_pages(builder)?;
|
||||
} else if let Ok(_sass_path) = relative_path.strip_prefix(SASS_PATH) {
|
||||
if build {
|
||||
builder.build_sass().context("Failed to rebuild Sass")?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Removes an existing resource.
|
||||
fn remove(builder: &mut SiteBuilder, _path: &Path, relative_path: &Path) -> anyhow::Result<()> {
|
||||
fn remove(builder: &mut SiteBuilder, path: &Path, relative_path: &Path) -> anyhow::Result<()> {
|
||||
if path.is_dir() {
|
||||
return Ok(());
|
||||
}
|
||||
if let Ok(page_path) = relative_path.strip_prefix(PAGES_PATH) {
|
||||
let (page_name, page_name_str) = get_name(page_path);
|
||||
|
||||
builder.site.page_index.remove(&page_name_str);
|
||||
std::fs::remove_file(builder.build_path.join(page_name.with_extension("html")))?;
|
||||
std::fs::remove_file(builder.build_path.join(page_name.with_extension("html")))
|
||||
.with_context(|| format!("Failed to remove page at {:?}", path))?;
|
||||
} else if let Ok(template_path) = relative_path.strip_prefix(TEMPLATES_PATH) {
|
||||
let (_template_name, template_name_str) = get_name(template_path);
|
||||
builder.site.template_index.remove(&template_name_str);
|
||||
builder.reg.unregister_template(&template_name_str);
|
||||
builder.site.build_all_pages(builder)?;
|
||||
builder
|
||||
.site
|
||||
.build_all_pages(builder)
|
||||
.context("Failed to rebuild pages")?;
|
||||
} else if let Ok(_static_path) = relative_path.strip_prefix(STATIC_PATH) {
|
||||
std::fs::remove_file(builder.build_path.join(relative_path))?;
|
||||
let to_remove = builder.build_path.join(relative_path);
|
||||
std::fs::remove_file(&to_remove)
|
||||
.with_context(|| format!("Failed to remove file at {:?}", to_remove))?;
|
||||
} else if let Ok(_sass_path) = relative_path.strip_prefix(SASS_PATH) {
|
||||
builder.build_sass().context("Failed to rebuild Sass")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -110,6 +129,7 @@ impl Site {
|
|||
eprintln!("Failed to build page {}: {}", page_name, e);
|
||||
}
|
||||
}
|
||||
builder.build_sass().context("Failed to build Sass")?;
|
||||
|
||||
// Map of websocket connections
|
||||
let peers: Arc<Mutex<HashMap<SocketAddr, WebSocket>>> =
|
||||
|
@ -120,7 +140,6 @@ impl Site {
|
|||
let hw_peers = peers.clone();
|
||||
hotwatch
|
||||
.watch(site.site_path.clone(), move |event| {
|
||||
let site_path = builder.site.site_path.canonicalize().unwrap();
|
||||
let peers = hw_peers.clone();
|
||||
|
||||
match (|| match event {
|
||||
|
@ -128,7 +147,7 @@ impl Site {
|
|||
if skip_path(&builder, &path) {
|
||||
Ok(false)
|
||||
} else {
|
||||
let rel = rel(&path, &site_path)?;
|
||||
let rel = rel(&path, &builder.site.site_path)?;
|
||||
println!("CHANGED - {:?}", rel);
|
||||
create(&mut builder, &path, &rel, true)?;
|
||||
Ok::<_, anyhow::Error>(true)
|
||||
|
@ -138,7 +157,7 @@ impl Site {
|
|||
if skip_path(&builder, &path) {
|
||||
Ok(false)
|
||||
} else {
|
||||
let rel = rel(&path, &site_path)?;
|
||||
let rel = rel(&path, &builder.site.site_path)?;
|
||||
println!("CREATED - {:?}", rel);
|
||||
create(&mut builder, &path, &rel, true)?;
|
||||
Ok(true)
|
||||
|
@ -148,7 +167,7 @@ impl Site {
|
|||
if skip_path(&builder, &path) {
|
||||
Ok(false)
|
||||
} else {
|
||||
let rel = rel(&path, &site_path)?;
|
||||
let rel = rel(&path, &builder.site.site_path)?;
|
||||
println!("REMOVED - {:?}", rel);
|
||||
remove(&mut builder, &path, &rel)?;
|
||||
Ok(true)
|
||||
|
@ -158,8 +177,8 @@ impl Site {
|
|||
if skip_path(&builder, &old) && skip_path(&builder, &new) {
|
||||
Ok(false)
|
||||
} else {
|
||||
let old_rel = rel(&old, &site_path)?;
|
||||
let new_rel = rel(&new, &site_path)?;
|
||||
let old_rel = rel(&old, &builder.site.site_path)?;
|
||||
let new_rel = rel(&new, &builder.site.site_path)?;
|
||||
println!("RENAMED - {:?} -> {:?}", old_rel, new_rel);
|
||||
create(&mut builder, &new, &new_rel, false)?;
|
||||
remove(&mut builder, &old, &old_rel)?;
|
||||
|
@ -218,6 +237,13 @@ impl Site {
|
|||
-> Result<Response, warp::Rejection> {
|
||||
// Serve static files
|
||||
let p = &path.as_str()[1..];
|
||||
|
||||
if p == "static/_dev.js" {
|
||||
let res =
|
||||
Response::new(include_str!("./refresh_websocket.js").into());
|
||||
return Ok(res);
|
||||
}
|
||||
|
||||
let mut p = build_path.join(p);
|
||||
|
||||
if !p.exists() {
|
||||
|
@ -228,8 +254,17 @@ impl Site {
|
|||
}
|
||||
|
||||
if p.exists() {
|
||||
let body = std::fs::read_to_string(&p).unwrap();
|
||||
let res = Response::new(body.into());
|
||||
let mut res = Response::new("".into());
|
||||
match std::fs::read_to_string(&p) {
|
||||
Ok(body) => {
|
||||
*res.body_mut() = body.into();
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("{}", e);
|
||||
*res.body_mut() = format!("Failed to load: {}", e).into();
|
||||
*res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
}
|
||||
return Ok(res);
|
||||
}
|
||||
Err(warp::reject())
|
||||
|
|
22
src/util.rs
Normal file
22
src/util.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
//! Module containing various utilities.
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
/// Simple helper to remove the contents of a directory without removing the directory itself.
|
||||
pub fn remove_dir_contents(path: &Path) -> anyhow::Result<()> {
|
||||
if !path.exists() {
|
||||
std::fs::create_dir_all(path)?;
|
||||
return Ok(());
|
||||
}
|
||||
for entry in path.read_dir()? {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.is_file() {
|
||||
std::fs::remove_file(&path)?;
|
||||
} else {
|
||||
std::fs::remove_dir_all(&path)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue