From 5401674797d35d8f95a37a62b2858a3673bf1261 Mon Sep 17 00:00:00 2001 From: gennyble Date: Wed, 18 Dec 2024 00:28:11 -0600 Subject: Stack overflow? Cat, help --- TODO | 4 ++++ readme.md | 7 +++++++ src/fs.rs | 19 +++++++++++++++++-- src/main.rs | 55 +++++++++++++++++++++++++++++++++++++++++++++++-------- src/templated.rs | 7 ++++++- src/timeparse.rs | 36 +++++++++++++++++++++++++++++++++++- 6 files changed, 116 insertions(+), 12 deletions(-) create mode 100644 TODO diff --git a/TODO b/TODO new file mode 100644 index 0000000..5ee90f8 --- /dev/null +++ b/TODO @@ -0,0 +1,4 @@ +(1) Using incorrect daylight savings offset for date should warn + Like using CDT when we are not in dalyight savings. CST would be + correct, but maybe it was on purpose? We should not hard-error, + just print somewhere so we see it Someday. \ No newline at end of file diff --git a/readme.md b/readme.md index ebb7350..648b984 100755 --- a/readme.md +++ b/readme.md @@ -89,11 +89,18 @@ a one or two sentence description of the page. remove a path component from the end of tree when displaying with the **path** pattern +**published** +use this with the `published` pattern to insert the publish date. + ### patterns **path** use this pattern with `path_link` and `path_name` to insert links to the directories below a page. +**published** +use this pattern with `published_human` and `published_machine` to fill in +the publish time of a post. use this with the `published` frontmatter. + ## Page content uses a weird kind of markup language It's mostly just HTML, but I'm tired of writing `

` so damn much. diff --git a/src/fs.rs b/src/fs.rs index e47889b..8266053 100755 --- a/src/fs.rs +++ b/src/fs.rs @@ -1,6 +1,5 @@ use camino::{Utf8Path, Utf8PathBuf}; -use core::fmt; -use std::{fmt, io, ops::Deref, str::FromStr}; +use std::{fmt, io, ops::Deref, path::Display, str::FromStr}; use crate::RuntimeError; @@ -105,6 +104,20 @@ pub struct PathResolution { pub is_dirfile: bool, } +impl Deref for PathResolution { + type Target = Utf8Path; + + fn deref(&self) -> &Self::Target { + self.filepath.as_path() + } +} + +impl fmt::Display for PathResolution { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", *self) + } +} + #[derive(Clone, Debug)] pub struct Filesystem { webroot: Utf8PathBuf, @@ -213,6 +226,8 @@ impl Filesystem { } pub async fn read_to_string>(path: P) -> Result { + tracing::trace!("read_to_string {}", path.as_ref()); + tokio::fs::read_to_string(path.as_ref()) .await .map_err(|ioe| RuntimeError::from_io(ioe, path.as_ref().to_owned())) diff --git a/src/main.rs b/src/main.rs index 5784588..acf0dc5 100755 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ mod templated; mod timeparse; mod util; -use std::{os::unix::fs::MetadataExt, str::FromStr}; +use std::{io::Write, os::unix::fs::MetadataExt, str::FromStr}; use axum::{ body::Body, @@ -25,7 +25,7 @@ pub use error::RuntimeError; use fs::Filesystem; use settings::Settings; use tokio_util::io::ReaderStream; -use tracing_subscriber::{prelude::*, EnvFilter}; +use tracing_subscriber::{fmt::time, prelude::*, EnvFilter}; use util::{Referer, RemoteIp, SessionId}; use crate::{ @@ -130,12 +130,27 @@ async fn falible_handler( send_file(resolve.filepath).await } else { let content = Filesystem::read_to_string(&resolve.filepath).await?; - match Templated::from_str(&content) { - Ok(templated) => send_template(templated, resolve, webpath, settings).await, - Err(_) => Ok(Response::builder() - .header(header::CONTENT_TYPE, "text/html") - .body(Body::from(content)) - .unwrap()), + + let result = Templated::from_str(&content); + tracing::trace!("full return from Templated::from_str"); + + match result { + Ok(templated) => { + //tracing::trace!("sending template for {resolve}"); + + std::io::stdout().write_all(b"meow meow meow!!").unwrap(); + std::io::stdout().flush().unwrap(); + + send_template(templated, resolve, webpath, settings).await + } + Err(e) => { + tracing::warn!("error sending template {e}"); + + Ok(Response::builder() + .header(header::CONTENT_TYPE, "text/html") + .body(Body::from(content)) + .unwrap()) + } } } } @@ -297,6 +312,30 @@ async fn send_template( } } + 'published: { + if let Some(mut published_pattern) = template.get_pattern("published") { + let publish_date_result = templated + .frontmatter + .get("published") + .map(|ts| timeparse::parse(ts)); + + match publish_date_result { + None => break 'published, + Some(Err(_e)) => { + tracing::warn!("template {resolve} has malformed `published` frontmatter"); + break 'published; + } + Some(Ok(datetime)) => { + let published_human = timeparse::format_long(&datetime); + let published_machine = timeparse::iso8601(&datetime); + + variables!(published_pattern, published_human, published_machine); + template.set_pattern(published_pattern); + } + } + } + } + // insert the page content itself let markedup = markup::process(&templated.content); template.set("main", markedup); diff --git a/src/templated.rs b/src/templated.rs index c6daac8..4598ecc 100755 --- a/src/templated.rs +++ b/src/templated.rs @@ -10,6 +10,8 @@ impl FromStr for Templated { type Err = TemplateError; fn from_str(raw: &str) -> Result { + tracing::trace!("parsing Templated"); + let (front, content) = match raw.strip_prefix("---\n") { None => return Err(TemplateError::MissingFrontmatter), Some(no_start) => match no_start.split_once("\n---\n") { @@ -18,6 +20,8 @@ impl FromStr for Templated { }, }; + tracing::trace!("isolated frontmatter"); + Ok(Self { frontmatter: front.parse()?, content: content.to_owned(), @@ -51,7 +55,8 @@ impl FromStr for Frontmatter { Some(tup) => tup, }; - entries.push((key.trim().to_owned(), value.trim().to_owned())) + entries.push((key.trim().to_owned(), value.trim().to_owned())); + tracing::trace!("pushed frontmatter entry {} successfully", key.trim()); } Ok(Self { entries }) diff --git a/src/timeparse.rs b/src/timeparse.rs index f4eaca5..830253b 100755 --- a/src/timeparse.rs +++ b/src/timeparse.rs @@ -1,6 +1,6 @@ use time::{ error::{Parse, TryFromParsed}, - format_description::FormatItem, + format_description::{well_known, FormatItem}, macros::{format_description, offset, time}, Date, OffsetDateTime, PrimitiveDateTime, Time, UtcOffset, Weekday, }; @@ -17,6 +17,25 @@ const OFFSET: &[FormatItem<'_>] = const CST: UtcOffset = offset!(-06:00); const CDT: UtcOffset = offset!(-05:00); +// Ripped from infica with the month of Sol removed. I just want the 3 letter months +/// Capitalized months (long, short) and lowercase months (long, short). +// it seems useful to have the lowercase here so we don't have to always call +// to_lowercase +const MONTHS: [[&str; 4]; 12] = [ + ["January", "Jan", "january", "jan"], + ["February", "Feb", "february", "feb"], + ["March", "Mar", "march", "mar"], + ["April", "Apr", "april", "apr"], + ["May", "May", "may", "may"], + ["June", "Jun", "june", "jun"], + ["July", "Jul", "july", "jul"], + ["August", "Aug", "august", "aug"], + ["September", "Sep", "september", "sep"], + ["October", "Oct", "october", "oct"], + ["November", "Nov", "november", "nov"], + ["December", "Dec", "december", "dec"], +]; + /// Offset for the united states in Central Time. Accounts for DST /// DST starts the 2nd sunday in March and ends the 1st sunday in November. /// https://www.nist.gov/pml/time-and-frequency-division/popular-links/daylight-saving-time-dst @@ -103,6 +122,21 @@ pub fn parse(raw: &str) -> Result { Ok(OffsetDateTime::new_in_offset(date, time, offset)) } +pub fn format_long(datetime: &OffsetDateTime) -> String { + let year = datetime.year(); + let month = MONTHS[datetime.month() as usize][1]; + let day = datetime.day(); + let weekday = datetime.weekday(); + + format!("{weekday} {day}, {month} {year}") +} + +pub fn iso8601(datetime: &OffsetDateTime) -> String { + datetime + .format(&well_known::Iso8601::DATE_TIME_OFFSET) + .unwrap() +} + #[cfg(test)] mod test { use time::{ -- cgit 1.4.1-3-g733a5