From d7b53687a5102dfdf0296120498afb650cee1247 Mon Sep 17 00:00:00 2001 From: Vincent Prouillet Date: Sat, 25 Jul 2020 10:30:55 +0200 Subject: [PATCH] Extract some feed logic out of site/lib.rs --- components/library/src/content/section.rs | 4 +- components/rebuild/src/lib.rs | 2 +- components/site/src/feed.rs | 79 +++++++++++++++++++ components/site/src/lib.rs | 95 +++++------------------ components/site/src/sitemap.rs | 3 +- 5 files changed, 103 insertions(+), 80 deletions(-) create mode 100644 components/site/src/feed.rs diff --git a/components/library/src/content/section.rs b/components/library/src/content/section.rs index 5a2a61c0..705b5a2a 100644 --- a/components/library/src/content/section.rs +++ b/components/library/src/content/section.rs @@ -258,8 +258,8 @@ impl Section { None => None, Some(x) => match x { 0 => None, - _ => Some(x) - } + _ => Some(x), + }, } } } diff --git a/components/rebuild/src/lib.rs b/components/rebuild/src/lib.rs index c0918954..668c6ae8 100644 --- a/components/rebuild/src/lib.rs +++ b/components/rebuild/src/lib.rs @@ -403,7 +403,7 @@ pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> { site.library.read().unwrap().pages_values(), None, &site.config.default_language, - None, + |c| c, ) } "split_sitemap_index.xml" => site.render_sitemap(), diff --git a/components/site/src/feed.rs b/components/site/src/feed.rs new file mode 100644 index 00000000..13c45cdb --- /dev/null +++ b/components/site/src/feed.rs @@ -0,0 +1,79 @@ +use std::path::PathBuf; + +use rayon::prelude::*; +use serde_derive::Serialize; +use tera::Context; + +use crate::Site; +use errors::Result; +use library::{sort_actual_pages_by_date, Page, TaxonomyItem}; +use utils::templates::render_template; + +#[derive(Debug, Clone, PartialEq, Serialize)] +pub struct SerializedFeedTaxonomyItem<'a> { + name: &'a str, + slug: &'a str, + permalink: &'a str, +} + +impl<'a> SerializedFeedTaxonomyItem<'a> { + pub fn from_item(item: &'a TaxonomyItem) -> Self { + SerializedFeedTaxonomyItem { + name: &item.name, + slug: &item.slug, + permalink: &item.permalink, + } + } +} + +pub fn render_feed( + site: &Site, + all_pages: Vec<&Page>, + lang: &str, + base_path: Option<&PathBuf>, + additional_context_fn: impl Fn(Context) -> Context, +) -> Result> { + let mut pages = all_pages.into_iter().filter(|p| p.meta.date.is_some()).collect::>(); + + // Don't generate a feed if none of the pages has a date + if pages.is_empty() { + return Ok(None); + } + + pages.par_sort_unstable_by(sort_actual_pages_by_date); + + let mut context = Context::new(); + context.insert( + "last_updated", + pages + .iter() + .filter_map(|page| page.meta.updated.as_ref()) + .chain(pages[0].meta.date.as_ref()) + .max() // I love lexicographically sorted date strings + .unwrap(), // Guaranteed because of pages[0].meta.date + ); + let library = site.library.read().unwrap(); + // limit to the last n elements if the limit is set; otherwise use all. + let num_entries = site.config.feed_limit.unwrap_or_else(|| pages.len()); + let p = + pages.iter().take(num_entries).map(|x| x.to_serialized_basic(&library)).collect::>(); + + context.insert("pages", &p); + context.insert("config", &site.config); + context.insert("lang", lang); + + let feed_filename = &site.config.feed_filename; + let feed_url = if let Some(ref base) = base_path { + site.config.make_permalink(&base.join(feed_filename).to_string_lossy().replace('\\', "/")) + } else { + site.config.make_permalink(feed_filename) + }; + + context.insert("feed_url", &feed_url); + + context = additional_context_fn(context); + + let feed = render_template(feed_filename, &site.tera, context, &site.config.theme)?; + + Ok(Some(feed)) +} diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index f657e4ef..8e08528f 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -1,3 +1,4 @@ +pub mod feed; pub mod link_checking; pub mod sass; pub mod sitemap; @@ -10,18 +11,15 @@ use std::sync::{Arc, Mutex, RwLock}; use glob::glob; use rayon::prelude::*; -use serde_derive::Serialize; use tera::{Context, Tera}; +use crate::feed::render_feed; use crate::link_checking::{check_external_links, check_internal_links_with_anchors}; use crate::tpls::{load_tera, register_early_global_fns, register_tera_global_fns}; -use config::{get_config, Config, Taxonomy as TaxonomyConfig}; +use config::{get_config, Config}; use errors::{bail, Error, Result}; use front_matter::InsertAnchor; -use library::{ - find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy, - TaxonomyItem, -}; +use library::{find_taxonomies, Library, Page, Paginator, Section, Taxonomy}; use templates::render_redirect_template; use utils::fs::{copy_directory, create_directory, create_file, ensure_directory_exists}; use utils::net::get_available_port; @@ -50,23 +48,6 @@ pub struct Site { include_drafts: bool, } -#[derive(Debug, Clone, PartialEq, Serialize)] -struct SerializedFeedTaxonomyItem<'a> { - name: &'a str, - slug: &'a str, - permalink: &'a str, -} - -impl<'a> SerializedFeedTaxonomyItem<'a> { - pub fn from_item(item: &'a TaxonomyItem) -> Self { - SerializedFeedTaxonomyItem { - name: &item.name, - slug: &item.slug, - permalink: &item.permalink, - } - } -} - impl Site { /// Parse a site at the given path. Defaults to the current dir /// Passing in a path is used in tests and when --root argument is passed @@ -533,7 +514,7 @@ impl Site { } else { library.pages_values() }; - self.render_feed(pages, None, &self.config.default_language, None)?; + self.render_feed(pages, None, &self.config.default_language, |c| c)?; } for lang in &self.config.languages { @@ -542,7 +523,7 @@ impl Site { } let pages = library.pages_values().iter().filter(|p| p.lang == lang.code).cloned().collect(); - self.render_feed(pages, Some(&PathBuf::from(lang.code.clone())), &lang.code, None)?; + self.render_feed(pages, Some(&PathBuf::from(lang.code.clone())), &lang.code, |c| c)?; } self.render_404()?; @@ -714,7 +695,12 @@ impl Site { } else { &self.config.default_language }, - Some((&taxonomy.kind, &item)), + |mut context: Context| { + context.insert("taxonomy", &taxonomy.kind); + context + .insert("term", &feed::SerializedFeedTaxonomyItem::from_item(item)); + context + }, ) } else { Ok(()) @@ -782,58 +768,15 @@ impl Site { all_pages: Vec<&Page>, base_path: Option<&PathBuf>, lang: &str, - taxonomy_and_item: Option<(&TaxonomyConfig, &TaxonomyItem)>, + additional_context_fn: impl Fn(Context) -> Context, ) -> Result<()> { ensure_directory_exists(&self.output_path)?; - let mut context = Context::new(); - let mut pages = all_pages.into_iter().filter(|p| p.meta.date.is_some()).collect::>(); - - // Don't generate a feed if none of the pages has a date - if pages.is_empty() { - return Ok(()); - } - - pages.par_sort_unstable_by(sort_actual_pages_by_date); - - context.insert( - "last_updated", - pages - .iter() - .filter_map(|page| page.meta.updated.as_ref()) - .chain(pages[0].meta.date.as_ref()) - .max() // I love lexicographically sorted date strings - .unwrap(), // Guaranteed because of pages[0].meta.date - ); - let library = self.library.read().unwrap(); - // limit to the last n elements if the limit is set; otherwise use all. - let num_entries = self.config.feed_limit.unwrap_or_else(|| pages.len()); - let p = pages - .iter() - .take(num_entries) - .map(|x| x.to_serialized_basic(&library)) - .collect::>(); - - context.insert("pages", &p); - context.insert("config", &self.config); - context.insert("lang", lang); - - let feed_filename = &self.config.feed_filename; - let feed_url = if let Some(ref base) = base_path { - self.config - .make_permalink(&base.join(feed_filename).to_string_lossy().replace('\\', "/")) - } else { - self.config.make_permalink(feed_filename) + let feed = match render_feed(self, all_pages, lang, base_path, additional_context_fn)? { + Some(v) => v, + None => return Ok(()), }; - - context.insert("feed_url", &feed_url); - - if let Some((taxonomy, item)) = taxonomy_and_item { - context.insert("taxonomy", taxonomy); - context.insert("term", &SerializedFeedTaxonomyItem::from_item(item)); - } - - let feed = &render_template(feed_filename, &self.tera, context, &self.config.theme)?; + let feed_filename = &self.config.feed_filename; if let Some(ref base) = base_path { let mut output_path = self.output_path.clone(); @@ -843,9 +786,9 @@ impl Site { create_directory(&output_path)?; } } - create_file(&output_path.join(feed_filename), feed)?; + create_file(&output_path.join(feed_filename), &feed)?; } else { - create_file(&self.output_path.join(feed_filename), feed)?; + create_file(&self.output_path.join(feed_filename), &feed)?; } Ok(()) } diff --git a/components/site/src/sitemap.rs b/components/site/src/sitemap.rs index 52d458bd..ed9869be 100644 --- a/components/site/src/sitemap.rs +++ b/components/site/src/sitemap.rs @@ -89,7 +89,8 @@ pub fn find_entries<'a>( if let Some(paginate_by) = section.paginate_by() { let number_pagers = (section.pages.len() as f64 / paginate_by as f64).ceil() as isize; for i in 1..=number_pagers { - let permalink = format!("{}{}/{}/", section.permalink, section.meta.paginate_path, i); + let permalink = + format!("{}{}/{}/", section.permalink, section.meta.paginate_path, i); sections.push(SitemapEntry::new(Cow::Owned(permalink), None)) } }