Extract some feed logic out of site/lib.rs
This commit is contained in:
parent
5fe1036a1d
commit
d7b53687a5
|
@ -258,8 +258,8 @@ impl Section {
|
||||||
None => None,
|
None => None,
|
||||||
Some(x) => match x {
|
Some(x) => match x {
|
||||||
0 => None,
|
0 => None,
|
||||||
_ => Some(x)
|
_ => Some(x),
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -403,7 +403,7 @@ pub fn after_template_change(site: &mut Site, path: &Path) -> Result<()> {
|
||||||
site.library.read().unwrap().pages_values(),
|
site.library.read().unwrap().pages_values(),
|
||||||
None,
|
None,
|
||||||
&site.config.default_language,
|
&site.config.default_language,
|
||||||
None,
|
|c| c,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
"split_sitemap_index.xml" => site.render_sitemap(),
|
"split_sitemap_index.xml" => site.render_sitemap(),
|
||||||
|
|
79
components/site/src/feed.rs
Normal file
79
components/site/src/feed.rs
Normal file
|
@ -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<Option<String>> {
|
||||||
|
let mut pages = all_pages.into_iter().filter(|p| p.meta.date.is_some()).collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// 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::<Vec<_>>();
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
pub mod feed;
|
||||||
pub mod link_checking;
|
pub mod link_checking;
|
||||||
pub mod sass;
|
pub mod sass;
|
||||||
pub mod sitemap;
|
pub mod sitemap;
|
||||||
|
@ -10,18 +11,15 @@ use std::sync::{Arc, Mutex, RwLock};
|
||||||
|
|
||||||
use glob::glob;
|
use glob::glob;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
use serde_derive::Serialize;
|
|
||||||
use tera::{Context, Tera};
|
use tera::{Context, Tera};
|
||||||
|
|
||||||
|
use crate::feed::render_feed;
|
||||||
use crate::link_checking::{check_external_links, check_internal_links_with_anchors};
|
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 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 errors::{bail, Error, Result};
|
||||||
use front_matter::InsertAnchor;
|
use front_matter::InsertAnchor;
|
||||||
use library::{
|
use library::{find_taxonomies, Library, Page, Paginator, Section, Taxonomy};
|
||||||
find_taxonomies, sort_actual_pages_by_date, Library, Page, Paginator, Section, Taxonomy,
|
|
||||||
TaxonomyItem,
|
|
||||||
};
|
|
||||||
use templates::render_redirect_template;
|
use templates::render_redirect_template;
|
||||||
use utils::fs::{copy_directory, create_directory, create_file, ensure_directory_exists};
|
use utils::fs::{copy_directory, create_directory, create_file, ensure_directory_exists};
|
||||||
use utils::net::get_available_port;
|
use utils::net::get_available_port;
|
||||||
|
@ -50,23 +48,6 @@ pub struct Site {
|
||||||
include_drafts: bool,
|
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 {
|
impl Site {
|
||||||
/// Parse a site at the given path. Defaults to the current dir
|
/// 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
|
/// Passing in a path is used in tests and when --root argument is passed
|
||||||
|
@ -533,7 +514,7 @@ impl Site {
|
||||||
} else {
|
} else {
|
||||||
library.pages_values()
|
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 {
|
for lang in &self.config.languages {
|
||||||
|
@ -542,7 +523,7 @@ impl Site {
|
||||||
}
|
}
|
||||||
let pages =
|
let pages =
|
||||||
library.pages_values().iter().filter(|p| p.lang == lang.code).cloned().collect();
|
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()?;
|
self.render_404()?;
|
||||||
|
@ -714,7 +695,12 @@ impl Site {
|
||||||
} else {
|
} else {
|
||||||
&self.config.default_language
|
&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 {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -782,58 +768,15 @@ impl Site {
|
||||||
all_pages: Vec<&Page>,
|
all_pages: Vec<&Page>,
|
||||||
base_path: Option<&PathBuf>,
|
base_path: Option<&PathBuf>,
|
||||||
lang: &str,
|
lang: &str,
|
||||||
taxonomy_and_item: Option<(&TaxonomyConfig, &TaxonomyItem)>,
|
additional_context_fn: impl Fn(Context) -> Context,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
ensure_directory_exists(&self.output_path)?;
|
ensure_directory_exists(&self.output_path)?;
|
||||||
|
|
||||||
let mut context = Context::new();
|
let feed = match render_feed(self, all_pages, lang, base_path, additional_context_fn)? {
|
||||||
let mut pages = all_pages.into_iter().filter(|p| p.meta.date.is_some()).collect::<Vec<_>>();
|
Some(v) => v,
|
||||||
|
None => return Ok(()),
|
||||||
// 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::<Vec<_>>();
|
|
||||||
|
|
||||||
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_filename = &self.config.feed_filename;
|
||||||
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)?;
|
|
||||||
|
|
||||||
if let Some(ref base) = base_path {
|
if let Some(ref base) = base_path {
|
||||||
let mut output_path = self.output_path.clone();
|
let mut output_path = self.output_path.clone();
|
||||||
|
@ -843,9 +786,9 @@ impl Site {
|
||||||
create_directory(&output_path)?;
|
create_directory(&output_path)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
create_file(&output_path.join(feed_filename), feed)?;
|
create_file(&output_path.join(feed_filename), &feed)?;
|
||||||
} else {
|
} else {
|
||||||
create_file(&self.output_path.join(feed_filename), feed)?;
|
create_file(&self.output_path.join(feed_filename), &feed)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,8 @@ pub fn find_entries<'a>(
|
||||||
if let Some(paginate_by) = section.paginate_by() {
|
if let Some(paginate_by) = section.paginate_by() {
|
||||||
let number_pagers = (section.pages.len() as f64 / paginate_by as f64).ceil() as isize;
|
let number_pagers = (section.pages.len() as f64 / paginate_by as f64).ceil() as isize;
|
||||||
for i in 1..=number_pagers {
|
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))
|
sections.push(SitemapEntry::new(Cow::Owned(permalink), None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue