basic generic post loading
This commit is contained in:
parent
02031f9062
commit
92c9daeb82
|
@ -187,6 +187,17 @@ version = "0.1.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c74d84029116787153e02106bf53e66828452a4b325cc8652b788b5967c0a0b6"
|
||||
dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.1"
|
||||
|
@ -524,6 +535,12 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.2.5"
|
||||
|
@ -759,6 +776,12 @@ version = "0.2.72"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9f8082297d534141b30c8d39e9b1773713ab50fdbe4ff30f750d063b3bfd701"
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.9"
|
||||
|
@ -938,6 +961,25 @@ dependencies = [
|
|||
"version_check 0.9.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611"
|
||||
dependencies = [
|
||||
"autocfg 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
|
@ -1604,6 +1646,18 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae3e2dd40a7cdc18ca80db804b7f461a39bb721160a85c9a1fa30134bf3c02a5"
|
||||
dependencies = [
|
||||
"dtoa",
|
||||
"linked-hash-map",
|
||||
"serde",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.8.2"
|
||||
|
@ -1713,6 +1767,26 @@ dependencies = [
|
|||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thread_local"
|
||||
version = "1.0.1"
|
||||
|
@ -2184,8 +2258,10 @@ name = "xesite"
|
|||
version = "2.0.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"chrono",
|
||||
"comrak",
|
||||
"envy",
|
||||
"glob",
|
||||
"log 0.4.8",
|
||||
"mime 0.3.16",
|
||||
"pretty_env_logger",
|
||||
|
@ -2193,6 +2269,17 @@ dependencies = [
|
|||
"ructe",
|
||||
"serde",
|
||||
"serde_dhall",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"warp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39f0c922f1a334134dc2f7a8b67dc5d25f0735263feec974345ff706bcf20b0d"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
|
|
@ -9,17 +9,21 @@ build = "src/build.rs"
|
|||
|
||||
[dependencies]
|
||||
anyhow = "1"
|
||||
chrono = "0.4"
|
||||
comrak = "0.8"
|
||||
envy = "0.4"
|
||||
glob = "0.3"
|
||||
log = "0"
|
||||
mime = "0.3.0"
|
||||
pretty_env_logger = "0"
|
||||
rand = "0"
|
||||
ructe = "0.11"
|
||||
serde_dhall = "0.5.3"
|
||||
serde_yaml = "0.8"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
tokio = { version = "0.2", features = ["macros"] }
|
||||
warp = "0.2"
|
||||
thiserror = "1"
|
||||
|
||||
[build-dependencies]
|
||||
ructe = { version = "0.11", features = ["warp02"] }
|
||||
|
|
|
@ -4,6 +4,7 @@ use warp::{path, Filter};
|
|||
|
||||
pub mod app;
|
||||
pub mod handlers;
|
||||
pub mod post;
|
||||
pub mod signalboost;
|
||||
|
||||
use app::State;
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/// This code was borrowed from @fasterthanlime.
|
||||
|
||||
use anyhow::{Result};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Eq, PartialEq, Deserialize, Default, Debug, Serialize, Clone)]
|
||||
pub struct Data {
|
||||
pub title: String,
|
||||
pub date: String,
|
||||
pub series: Option<String>,
|
||||
pub tags: Option<Vec<String>>,
|
||||
pub slides_link: Option<String>,
|
||||
pub image: Option<String>,
|
||||
pub thumb: Option<String>,
|
||||
pub show: Option<bool>,
|
||||
}
|
||||
|
||||
enum State {
|
||||
SearchForStart,
|
||||
ReadingMarker { count: usize, end: bool },
|
||||
ReadingFrontMatter { buf: String, line_start: bool },
|
||||
SkipNewline { end: bool },
|
||||
}
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
enum Error {
|
||||
#[error("EOF while parsing frontmatter")]
|
||||
EOF,
|
||||
#[error("Error parsing yaml: {0:?}")]
|
||||
Yaml(#[from] serde_yaml::Error),
|
||||
}
|
||||
|
||||
impl Data {
|
||||
pub fn parse(input: &str) -> Result<(Data, usize)> {
|
||||
let mut state = State::SearchForStart;
|
||||
|
||||
let mut payload = None;
|
||||
let offset;
|
||||
|
||||
let mut chars = input.char_indices();
|
||||
'parse: loop {
|
||||
let (idx, ch) = match chars.next() {
|
||||
Some(x) => x,
|
||||
None => return Err(Error::EOF)?,
|
||||
};
|
||||
match &mut state {
|
||||
State::SearchForStart => match ch {
|
||||
'-' => {
|
||||
state = State::ReadingMarker {
|
||||
count: 1,
|
||||
end: false,
|
||||
};
|
||||
}
|
||||
'\n' | '\t' | ' ' => {
|
||||
// ignore whitespace
|
||||
}
|
||||
_ => {
|
||||
panic!("Start of frontmatter not found");
|
||||
}
|
||||
},
|
||||
State::ReadingMarker { count, end } => match ch {
|
||||
'-' => {
|
||||
*count += 1;
|
||||
if *count == 3 {
|
||||
state = State::SkipNewline { end: *end };
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
panic!("Malformed frontmatter marker");
|
||||
}
|
||||
},
|
||||
State::SkipNewline { end } => match ch {
|
||||
'\n' => {
|
||||
if *end {
|
||||
offset = idx + 1;
|
||||
break 'parse;
|
||||
} else {
|
||||
state = State::ReadingFrontMatter {
|
||||
buf: String::new(),
|
||||
line_start: true,
|
||||
};
|
||||
}
|
||||
}
|
||||
_ => panic!("Expected newline, got {:?}",),
|
||||
},
|
||||
State::ReadingFrontMatter { buf, line_start } => match ch {
|
||||
'-' if *line_start => {
|
||||
let mut state_temp = State::ReadingMarker {
|
||||
count: 1,
|
||||
end: true,
|
||||
};
|
||||
std::mem::swap(&mut state, &mut state_temp);
|
||||
if let State::ReadingFrontMatter { buf, .. } = state_temp {
|
||||
payload = Some(buf);
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
ch => {
|
||||
buf.push(ch);
|
||||
*line_start = ch == '\n';
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// unwrap justification: option set in state machine, Rust can't statically analyze it
|
||||
let payload = payload.unwrap();
|
||||
|
||||
let fm: Self = serde_yaml::from_str(&payload)?;
|
||||
|
||||
Ok((fm, offset))
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use chrono::prelude::*;
|
||||
use glob::glob;
|
||||
use std::{cmp::Ordering, fs};
|
||||
|
||||
pub mod frontmatter;
|
||||
|
||||
#[derive(Eq, PartialEq, Debug)]
|
||||
pub struct Post {
|
||||
pub front_matter: frontmatter::Data,
|
||||
pub link: String,
|
||||
pub body: String,
|
||||
pub body_html: String,
|
||||
pub date: NaiveDate,
|
||||
}
|
||||
|
||||
impl Ord for Post {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(&other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for Post {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.date.cmp(&other.date))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(dir: &str) -> Result<Vec<Post>> {
|
||||
let mut result: Vec<Post> = vec![];
|
||||
|
||||
for path in glob(&format!("{}/*.markdown", dir))?.filter_map(Result::ok) {
|
||||
let body = fs::read_to_string(path.clone())?;
|
||||
let (fm, content_offset) = frontmatter::Data::parse(body.clone().as_str())?;
|
||||
let markup = &body[content_offset..];
|
||||
let date = NaiveDate::parse_from_str(&fm.clone().date, "%Y-%m-%d")?;
|
||||
|
||||
result.push(Post {
|
||||
front_matter: fm,
|
||||
link: format!("{}/{}", dir, path.file_stem().unwrap().to_str().unwrap()),
|
||||
body: markup.to_string(),
|
||||
body_html: crate::app::markdown(&markup),
|
||||
date: date,
|
||||
})
|
||||
}
|
||||
|
||||
if result.len() == 0 {
|
||||
Err(anyhow!("no posts loaded"))
|
||||
} else {
|
||||
result.sort();
|
||||
result.reverse();
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use anyhow::Result;
|
||||
|
||||
#[test]
|
||||
fn blog() -> Result<()> {
|
||||
load("./blog")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue