generate atom feed in root

This commit is contained in:
xfnw 2024-03-26 18:21:47 -04:00
parent d211935539
commit 9746bc63ef
5 changed files with 164 additions and 8 deletions

91
Cargo.lock generated
View File

@ -70,7 +70,10 @@ dependencies = [
"html-escaper",
"orgize",
"rowan",
"serde",
"serde_derive",
"slugify",
"toml",
]
[[package]]
@ -152,6 +155,12 @@ dependencies = [
"syn",
]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "fnv"
version = "1.0.7"
@ -214,6 +223,16 @@ dependencies = [
"unicode-normalization",
]
[[package]]
name = "indexmap"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "jetscii"
version = "0.5.3"
@ -396,6 +415,35 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "serde"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.197"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_spanned"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
dependencies = [
"serde",
]
[[package]]
name = "slugify"
version = "0.1.0"
@ -443,6 +491,40 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "toml"
version = "0.8.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
dependencies = [
"serde",
"serde_spanned",
"toml_datetime",
"toml_edit",
]
[[package]]
name = "toml_datetime"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
version = "0.22.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
dependencies = [
"indexmap",
"serde",
"serde_spanned",
"toml_datetime",
"winnow",
]
[[package]]
name = "tracing"
version = "0.1.40"
@ -532,3 +614,12 @@ name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "winnow"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dffa400e67ed5a4dd237983829e66475f0a4a26938c4b04c21baede6262215b8"
dependencies = [
"memchr",
]

View File

@ -13,4 +13,7 @@ git2 = { version = "0.18.3", default-features = false }
html-escaper = "0.2.0"
orgize = "=0.10.0-alpha.7"
rowan = "0.15.15"
serde = { version = "1.0.197", default-features = false }
serde_derive = { version = "1.0.197" }
slugify = "0.1.0"
toml = { version = "0.8.12", default-features = false, features = ["parse"] }

View File

@ -1,18 +1,47 @@
use crate::git::ModifyMap;
use chrono::{offset::Utc, DateTime};
use html_escaper::Escape;
use std::{collections::BTreeMap, path::PathBuf};
#[derive(boilerplate::Boilerplate)]
pub struct FeedXml<'a> {
pub title: &'a str,
pub id: &'a str,
pub url: &'a str,
pub updated: DateTime<Utc>,
pub entries: Vec<AtomEntry<'a>>,
pub updated: &'a DateTime<Utc>,
pub entries: &'a [AtomEntry<'a>],
}
pub struct AtomEntry<'a> {
pub title: &'a str,
pub path: String,
pub path: &'a str,
pub author: &'a str,
pub updated: DateTime<Utc>,
}
pub fn entries<'a>(
titles: &'a BTreeMap<PathBuf, (String, PathBuf)>,
mtime: &'a ModifyMap,
) -> Result<Vec<AtomEntry<'a>>, Box<dyn std::error::Error>> {
let mut entries = vec![];
for (path, (title, old)) in titles.iter() {
let path = match path.to_str() {
Some(p) => p,
None => continue,
};
let (updated, author) = mtime.get(old).ok_or("missing modification info")?;
let updated =
DateTime::from_timestamp(updated.seconds(), 0).ok_or("broken modification date")?;
entries.push(AtomEntry {
title,
path,
author,
updated,
});
}
entries.sort_by(|x, y| x.updated.cmp(&y.updated));
Ok(entries)
}

View File

@ -4,7 +4,8 @@ use git2::{Oid, Repository};
use html_escaper::{Escape, Trusted};
use orgize::{ast::Keyword, ParseConfig};
use rowan::ast::{support, AstNode};
use std::{collections::BTreeMap, error::Error, fs, io::Write, path::PathBuf};
use serde_derive::Deserialize;
use std::{cmp::min, collections::BTreeMap, error::Error, fs, io::Write, path::PathBuf};
mod atom;
mod git;
@ -30,6 +31,13 @@ struct PageHtml<'a> {
numdir: usize,
}
#[derive(Deserialize, Debug)]
struct ClamConfig {
title: String,
id: Option<String>,
url: String,
}
fn generate(
org_cfg: &ParseConfig,
repo: &Repository,
@ -46,6 +54,8 @@ fn generate(
f.write_all(include_bytes!("style.css"))?;
}
let mut titles = BTreeMap::new();
for (dir, files) in dir_map.iter() {
fs::create_dir_all(dir)?;
@ -66,7 +76,7 @@ fn generate(
title = keyword.value().trim().to_string();
}
}
};
}
let (created, author) =
ctime.get(&full_path).ok_or("missing creation time")?;
@ -76,7 +86,7 @@ fn generate(
res.traverse(&mut html_export);
let template = PageHtml {
title,
title: title.clone(),
body: html_export.0.finish(),
commit: short_id,
author,
@ -87,7 +97,9 @@ fn generate(
numdir: full_path.iter().count(),
};
let old_path = full_path.clone();
full_path.set_extension("html");
titles.insert(full_path.clone(), (title, old_path));
Some(template.to_string().into_bytes())
}
@ -103,6 +115,27 @@ fn generate(
}
}
if let Ok(config) = fs::read_to_string(".clam.toml") {
let config: ClamConfig = toml::from_str(&config)?;
let feed = atom::entries(&titles, &mtime)?;
let mut f = fs::File::create("feed.xml")?;
f.write_all(
atom::FeedXml {
title: &config.title,
id: config.id.as_ref().unwrap_or(&config.url),
url: &config.url,
updated: &feed.first().ok_or("no entries in feed")?.updated,
entries: &feed[..min(feed.len(), 10)],
}
.to_string()
.as_bytes(),
)?;
} else {
eprintln!("missing config file, skipping feed.xml creation");
}
Ok(())
}
@ -125,7 +158,7 @@ fn main() {
})
.unwrap();
// TODO: get this stuff from clam.toml or something
// TODO: get this stuff from .clam.toml or something
let org_cfg = ParseConfig {
todo_keywords: (
["TODO", "PENDING", "DELAYED", "RERUN"]

View File

@ -4,7 +4,7 @@
<id>{{ self.id }}/feed.xml</id>
<link rel="self" href="{{ self.url }}/feed.xml"/>
<updated>{{ self.updated }}</updated>
%% for entry in &self.entries {
%% for entry in self.entries {
<entry>
<title>{{ entry.title }}</title>
<id>{{ self.id }}/{{ entry.path }}</id>