RSS feed generation

This commit is contained in:
Vincent Prouillet 2017-03-07 16:43:27 +09:00
parent fa7fc6e49b
commit d43d738a4f
5 changed files with 90 additions and 20 deletions

26
Cargo.lock generated
View file

@ -18,7 +18,7 @@ dependencies = [
"slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syntect 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tera 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tera 0.8.0 (git+https://github.com/Keats/tera)",
"toml 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
"ws 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -388,7 +388,7 @@ dependencies = [
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -405,7 +405,7 @@ dependencies = [
"libc 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -416,7 +416,7 @@ version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -427,7 +427,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)",
"net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -448,7 +448,7 @@ dependencies = [
[[package]]
name = "net2"
version = "0.2.26"
version = "0.2.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -672,7 +672,7 @@ name = "serde_codegen_internals"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -682,7 +682,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_codegen_internals 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -737,7 +737,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.11.8"
version = "0.11.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
@ -774,7 +774,7 @@ dependencies = [
[[package]]
name = "tera"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
source = "git+https://github.com/Keats/tera#2eb55de231e08da50ca32a443499fbce8d9003e0"
dependencies = [
"chrono 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1055,7 +1055,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum miow 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a78d2605eb97302c10cf944b8d96b0a2a890c52957caf92fcd1f24f69049579"
"checksum modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "41f5c9112cb662acd3b204077e0de5bc66305fa8df65c8019d5adb10e9ab6e58"
"checksum mount 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32245731923cd096899502fc4c4317cfd09f121e80e73f7f576cf3777a824256"
"checksum net2 0.2.26 (registry+https://github.com/rust-lang/crates.io-index)" = "5edf9cb6be97212423aed9413dd4729d62b370b5e1c571750e882cebbbc1e3e2"
"checksum net2 0.2.27 (registry+https://github.com/rust-lang/crates.io-index)" = "18b9642ad6222faf5ce46f6966f59b71b9775ad5758c9e09fcf0a6c8061972b4"
"checksum nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bfb3ddedaa14746434a02041940495bf11325c22f6d36125d3bdd56090d50a79"
"checksum notify 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87c628262cc8a99209596ec610dcf199d6876a10cfa22e355acc5936d6f1fa63"
"checksum num 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "98b15ba84e910ea7a1973bccd3df7b31ae282bf9d8bd2897779950c9b8303d40"
@ -1092,10 +1092,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f5ff4b43cb07b86c5f9236c92714a22cdf9e5a27a7d85e398e2c9403328cb8"
"checksum staticfile 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31493480e073d52522a94cdf56269dd8eb05f99549effd1826b0271690608878"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum syn 0.11.8 (registry+https://github.com/rust-lang/crates.io-index)" = "37c279fb816210c9bb28b2c292664581e7b87b4561e86b94df462664d8620bb8"
"checksum syn 0.11.9 (registry+https://github.com/rust-lang/crates.io-index)" = "480c834701caba3548aa991e54677281be3a5414a9d09ddbdf4ed74a569a9d19"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum syntect 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f79be04af68d5fa09e71b3274159a955a25f25a5cbfba9a6ff64139b71d848a"
"checksum tera 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb775e4a7318e080e9c3000b150f720caf5825b66504f56f358df35b74fd0c14"
"checksum tera 0.8.0 (git+https://github.com/Keats/tera)" = "<none>"
"checksum term_size 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a"
"checksum thread-id 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4437c97558c70d129e40629a5b385b3fb1ffac301e63941335e4d354081ec14a"
"checksum thread_local 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c85048c6260d17cf486ceae3282d9fb6b90be220bf5b28c400f5485ffc29f0c7"

View file

@ -20,8 +20,8 @@ glob = "0.2"
serde = "0.9"
serde_json = "0.9"
serde_derive = "0.9"
# tera = { git = "https://github.com/Keats/tera", branch = "next" }
tera = "0.8"
tera = { git = "https://github.com/Keats/tera", branch = "master" }
# tera = "0.8"
slug = "0.1"
syntect = "1"
chrono = "0.3"

View file

@ -134,7 +134,7 @@ impl Page {
page.filename = path.file_stem().expect("Couldn't get filename").to_string_lossy().to_string();
page.slug = {
if let Some(ref slug) = page.meta.slug {
slug.to_string()
slug.trim().to_string()
} else {
slugify(page.filename.clone())
}
@ -144,7 +144,7 @@ impl Page {
// 4. Find sections
// Pages with custom urls exists outside of sections
if let Some(ref u) = page.meta.url {
page.url = u.to_string();
page.url = u.trim().to_string();
} else {
// find out if we have sections
for section in path.parent().unwrap().components() {
@ -381,6 +381,21 @@ Hello world"#;
assert_eq!(page.permalink, format!("{}{}", Config::default().base_url, "file-with-space"));
}
#[test]
fn test_trim_slug_if_needed() {
let content = r#"
+++
title = "Hello"
description = "hey there"
+++
Hello world"#;
let res = Page::parse(" file with space.md", content, &Config::default());
assert!(res.is_ok());
let page = res.unwrap();
assert_eq!(page.slug, "file-with-space");
assert_eq!(page.permalink, format!("{}{}", Config::default().base_url, "file-with-space"));
}
#[test]
fn test_reading_analytics_short() {
let content = r#"

View file

@ -153,6 +153,9 @@ impl Site {
self.render_categories_and_tags(RenderList::Categories, &category_pages)?;
self.render_categories_and_tags(RenderList::Tags, &tag_pages)?;
self.render_sitemap()?;
self.render_rss_feed()?;
// And finally the index page
let mut context = Context::new();
pages.sort_by(|a, b| a.partial_cmp(b).unwrap());
@ -161,8 +164,6 @@ impl Site {
let index = self.templates.render("index.html", &context)?;
create_file(public.join("index.html"), &self.inject_livereload(index))?;
self.render_sitemap()?;
// TODO: render rss feed
Ok(())
}
@ -218,7 +219,7 @@ impl Site {
Ok(())
}
pub fn render_sitemap(&self) -> Result<()> {
fn render_sitemap(&self) -> Result<()> {
let tpl = String::from_utf8(include_bytes!("templates/sitemap.xml").to_vec()).unwrap();
let mut context = Context::new();
context.add("pages", &self.pages.values().collect::<Vec<&Page>>());
@ -229,4 +230,38 @@ impl Site {
Ok(())
}
fn get_rss_feed_url(&self) -> String {
if self.config.base_url.ends_with("/") {
format!("{}{}", self.config.base_url, "feed.xml")
} else {
format!("{}/{}", self.config.base_url, "feed.xml")
}
}
fn render_rss_feed(&self) -> Result<()> {
let tpl = String::from_utf8(include_bytes!("templates/rss.xml").to_vec()).unwrap();
let mut context = Context::new();
let mut pages = self.pages.values()
.filter(|p| p.meta.date.is_some())
.take(15) // limit to the last 15 elements
.collect::<Vec<&Page>>();
// Don't generate a RSS feed if none of the pages has a date
if pages.is_empty() {
return Ok(());
}
pages.sort_by(|a, b| a.partial_cmp(b).unwrap());
context.add("pages", &pages);
context.add("last_build_date", &pages[0].meta.date);
context.add("config", &self.config);
context.add("feed_url", &self.get_rss_feed_url());
let sitemap = Tera::one_off(&tpl, &context, false)?;
let public = Path::new("public");
create_file(public.join("rss.xml"), &sitemap)?;
Ok(())
}
}

20
src/templates/rss.xml Normal file
View file

@ -0,0 +1,20 @@
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
<channel>
<title>{{ config.title }}</title>
<link>{{ config.base_url }}</link>
<description>{{ config.description }}</description>
<generator>Gutenberg</generator>
<language>{{ config.language_code }}</language>
<atom:link href="{{ feed_url }}" rel="self" type="application/rss+xml"/>
<lastBuildDate>{{ last_build_date | date(format="%a, %d %b %Y %H:%M:%S %z") }}</lastBuildDate>
{% for page in pages %}
<item>
<title>{{ page.title }}</title>
<pubDate>{{ page.date | date(format="%a, %d %b %Y %H:%M:%S %z") }}</pubDate>
<link>{{ page.permalink }}</link>
<guid>{{ page.permalink }}</guid>
<description>"{{ page.content | escape }}"</description>
</item>
{% endfor %}
</channel>
</rss>