Allow taxonomies to not be rendered

Closes #1750
This commit is contained in:
Vincent Prouillet 2022-04-27 21:09:02 +02:00
parent 844576e32e
commit 84951d39e3
15 changed files with 62 additions and 44 deletions

View File

@ -14,6 +14,8 @@ also specify classes on headers now
- `zola serve/build` can now run from anywhere in a zola directory - `zola serve/build` can now run from anywhere in a zola directory
- Add XML support to `load_data` - Add XML support to `load_data`
- `skip_prefixes` is now checked before parsing external link URLs - `skip_prefixes` is now checked before parsing external link URLs
- Add `render` attribute to taxonomies configuration in `config.toml`, for when you don't want to render
any pages related to that taxonomy
## 0.15.3 (2022-01-23) ## 0.15.3 (2022-01-23)

View File

@ -1,6 +1,6 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default)] #[serde(default)]
pub struct TaxonomyConfig { pub struct TaxonomyConfig {
/// The name used in the URL, usually the plural /// The name used in the URL, usually the plural
@ -9,10 +9,24 @@ pub struct TaxonomyConfig {
/// by this much /// by this much
pub paginate_by: Option<usize>, pub paginate_by: Option<usize>,
pub paginate_path: Option<String>, pub paginate_path: Option<String>,
/// Whether to generate a feed only for each taxonomy term, defaults to false /// Whether the taxonomy will be rendered, defaults to `true`
pub render: bool,
/// Whether to generate a feed only for each taxonomy term, defaults to `false`
pub feed: bool, pub feed: bool,
} }
impl Default for TaxonomyConfig {
fn default() -> Self {
Self {
name: String::new(),
paginate_by: None,
paginate_path: None,
render: true,
feed: false,
}
}
}
impl TaxonomyConfig { impl TaxonomyConfig {
pub fn is_paginated(&self) -> bool { pub fn is_paginated(&self) -> bool {
if let Some(paginate_by) = self.paginate_by { if let Some(paginate_by) = self.paginate_by {

View File

@ -17,5 +17,5 @@ pub use library::Library;
pub use page::Page; pub use page::Page;
pub use pagination::Paginator; pub use pagination::Paginator;
pub use section::Section; pub use section::Section;
pub use taxonomies::{Taxonomy, TaxonomyItem}; pub use taxonomies::{Taxonomy, TaxonomyTerm};
pub use types::*; pub use types::*;

View File

@ -10,13 +10,13 @@ use utils::templates::{check_template_fallbacks, render_template};
use crate::library::Library; use crate::library::Library;
use crate::ser::{SectionSerMode, SerializingPage, SerializingSection}; use crate::ser::{SectionSerMode, SerializingPage, SerializingSection};
use crate::taxonomies::{Taxonomy, TaxonomyItem}; use crate::taxonomies::{Taxonomy, TaxonomyTerm};
use crate::Section; use crate::Section;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
enum PaginationRoot<'a> { enum PaginationRoot<'a> {
Section(&'a Section), Section(&'a Section),
Taxonomy(&'a Taxonomy, &'a TaxonomyItem), Taxonomy(&'a Taxonomy, &'a TaxonomyTerm),
} }
/// A list of all the pages in the paginator with their index and links /// A list of all the pages in the paginator with their index and links
@ -90,7 +90,7 @@ impl<'a> Paginator<'a> {
/// It will always at least create one pager (the first) even if there are not enough pages to paginate /// It will always at least create one pager (the first) even if there are not enough pages to paginate
pub fn from_taxonomy( pub fn from_taxonomy(
taxonomy: &'a Taxonomy, taxonomy: &'a Taxonomy,
item: &'a TaxonomyItem, item: &'a TaxonomyTerm,
library: &'a Library, library: &'a Library,
tera: &Tera, tera: &Tera,
theme: &Option<String>, theme: &Option<String>,
@ -393,7 +393,7 @@ mod tests {
paginate_by: Some(2), paginate_by: Some(2),
..TaxonomyConfig::default() ..TaxonomyConfig::default()
}; };
let taxonomy_item = TaxonomyItem { let taxonomy_item = TaxonomyTerm {
name: "Something".to_string(), name: "Something".to_string(),
slug: "something".to_string(), slug: "something".to_string(),
path: "/some-tags/something/".to_string(), path: "/some-tags/something/".to_string(),

View File

@ -17,7 +17,7 @@ use crate::{Page, SortBy};
use crate::sorting::sort_pages; use crate::sorting::sort_pages;
#[derive(Debug, Clone, PartialEq, Serialize)] #[derive(Debug, Clone, PartialEq, Serialize)]
pub struct SerializedTaxonomyItem<'a> { pub struct SerializedTaxonomyTerm<'a> {
name: &'a str, name: &'a str,
slug: &'a str, slug: &'a str,
path: &'a str, path: &'a str,
@ -25,15 +25,15 @@ pub struct SerializedTaxonomyItem<'a> {
pages: Vec<SerializingPage<'a>>, pages: Vec<SerializingPage<'a>>,
} }
impl<'a> SerializedTaxonomyItem<'a> { impl<'a> SerializedTaxonomyTerm<'a> {
pub fn from_item(item: &'a TaxonomyItem, library: &'a Library) -> Self { pub fn from_item(item: &'a TaxonomyTerm, library: &'a Library) -> Self {
let mut pages = vec![]; let mut pages = vec![];
for p in &item.pages { for p in &item.pages {
pages.push(SerializingPage::new(&library.pages[p], Some(library), false)); pages.push(SerializingPage::new(&library.pages[p], Some(library), false));
} }
SerializedTaxonomyItem { SerializedTaxonomyTerm {
name: &item.name, name: &item.name,
slug: &item.slug, slug: &item.slug,
path: &item.path, path: &item.path,
@ -45,7 +45,7 @@ impl<'a> SerializedTaxonomyItem<'a> {
/// A taxonomy with all its pages /// A taxonomy with all its pages
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct TaxonomyItem { pub struct TaxonomyTerm {
pub name: String, pub name: String,
pub slug: String, pub slug: String,
pub path: String, pub path: String,
@ -53,7 +53,7 @@ pub struct TaxonomyItem {
pub pages: Vec<PathBuf>, pub pages: Vec<PathBuf>,
} }
impl TaxonomyItem { impl TaxonomyTerm {
pub fn new( pub fn new(
name: &str, name: &str,
lang: &str, lang: &str,
@ -75,11 +75,11 @@ impl TaxonomyItem {
let (mut pages, ignored_pages) = sort_pages(taxo_pages, SortBy::Date); let (mut pages, ignored_pages) = sort_pages(taxo_pages, SortBy::Date);
// We still append pages without dates at the end // We still append pages without dates at the end
pages.extend(ignored_pages); pages.extend(ignored_pages);
TaxonomyItem { name: name.to_string(), permalink, path, slug: item_slug, pages } TaxonomyTerm { name: name.to_string(), permalink, path, slug: item_slug, pages }
} }
pub fn serialize<'a>(&'a self, library: &'a Library) -> SerializedTaxonomyItem<'a> { pub fn serialize<'a>(&'a self, library: &'a Library) -> SerializedTaxonomyTerm<'a> {
SerializedTaxonomyItem::from_item(self, library) SerializedTaxonomyTerm::from_item(self, library)
} }
pub fn merge(&mut self, other: Self) { pub fn merge(&mut self, other: Self) {
@ -87,7 +87,7 @@ impl TaxonomyItem {
} }
} }
impl PartialEq for TaxonomyItem { impl PartialEq for TaxonomyTerm {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.permalink == other.permalink self.permalink == other.permalink
} }
@ -98,13 +98,13 @@ pub struct SerializedTaxonomy<'a> {
kind: &'a TaxonomyConfig, kind: &'a TaxonomyConfig,
lang: &'a str, lang: &'a str,
permalink: &'a str, permalink: &'a str,
items: Vec<SerializedTaxonomyItem<'a>>, items: Vec<SerializedTaxonomyTerm<'a>>,
} }
impl<'a> SerializedTaxonomy<'a> { impl<'a> SerializedTaxonomy<'a> {
pub fn from_taxonomy(taxonomy: &'a Taxonomy, library: &'a Library) -> Self { pub fn from_taxonomy(taxonomy: &'a Taxonomy, library: &'a Library) -> Self {
let items: Vec<SerializedTaxonomyItem> = let items: Vec<SerializedTaxonomyTerm> =
taxonomy.items.iter().map(|i| SerializedTaxonomyItem::from_item(i, library)).collect(); taxonomy.items.iter().map(|i| SerializedTaxonomyTerm::from_item(i, library)).collect();
SerializedTaxonomy { SerializedTaxonomy {
kind: &taxonomy.kind, kind: &taxonomy.kind,
lang: &taxonomy.lang, lang: &taxonomy.lang,
@ -121,7 +121,7 @@ pub struct Taxonomy {
pub slug: String, pub slug: String,
pub permalink: String, pub permalink: String,
// this vec is sorted by the count of item // this vec is sorted by the count of item
pub items: Vec<TaxonomyItem>, pub items: Vec<TaxonomyTerm>,
} }
impl Taxonomy { impl Taxonomy {
@ -129,7 +129,7 @@ impl Taxonomy {
let mut sorted_items = vec![]; let mut sorted_items = vec![];
let slug = tax_found.slug; let slug = tax_found.slug;
for (name, pages) in tax_found.terms { for (name, pages) in tax_found.terms {
sorted_items.push(TaxonomyItem::new(name, tax_found.lang, &slug, &pages, config)); sorted_items.push(TaxonomyTerm::new(name, tax_found.lang, &slug, &pages, config));
} }
sorted_items.sort_by(|a, b| match a.slug.cmp(&b.slug) { sorted_items.sort_by(|a, b| match a.slug.cmp(&b.slug) {
@ -166,7 +166,7 @@ impl Taxonomy {
pub fn render_term( pub fn render_term(
&self, &self,
item: &TaxonomyItem, item: &TaxonomyTerm,
tera: &Tera, tera: &Tera,
config: &Config, config: &Config,
library: &Library, library: &Library,
@ -174,7 +174,7 @@ impl Taxonomy {
let mut context = Context::new(); let mut context = Context::new();
context.insert("config", &config.serialize(&self.lang)); context.insert("config", &config.serialize(&self.lang));
context.insert("lang", &self.lang); context.insert("lang", &self.lang);
context.insert("term", &SerializedTaxonomyItem::from_item(item, library)); context.insert("term", &SerializedTaxonomyTerm::from_item(item, library));
context.insert("taxonomy", &self.kind); context.insert("taxonomy", &self.kind);
context.insert( context.insert(
"current_url", "current_url",
@ -199,8 +199,8 @@ impl Taxonomy {
) -> Result<String> { ) -> Result<String> {
let mut context = Context::new(); let mut context = Context::new();
context.insert("config", &config.serialize(&self.lang)); context.insert("config", &config.serialize(&self.lang));
let terms: Vec<SerializedTaxonomyItem> = let terms: Vec<SerializedTaxonomyTerm> =
self.items.iter().map(|i| SerializedTaxonomyItem::from_item(i, library)).collect(); self.items.iter().map(|i| SerializedTaxonomyTerm::from_item(i, library)).collect();
context.insert("terms", &terms); context.insert("terms", &terms);
context.insert("lang", &self.lang); context.insert("lang", &self.lang);
context.insert("taxonomy", &self.kind); context.insert("taxonomy", &self.kind);
@ -245,7 +245,6 @@ impl<'a> TaxonomyFound<'a> {
} }
pub fn find_taxonomies(config: &Config, pages: &AHashMap<PathBuf, Page>) -> Result<Vec<Taxonomy>> { pub fn find_taxonomies(config: &Config, pages: &AHashMap<PathBuf, Page>) -> Result<Vec<Taxonomy>> {
// lang -> tax names -> def
let mut taxonomies_def = AHashMap::new(); let mut taxonomies_def = AHashMap::new();
let mut taxonomies_slug = AHashMap::new(); let mut taxonomies_slug = AHashMap::new();

View File

@ -4,9 +4,9 @@ extern crate test;
use std::collections::HashMap; use std::collections::HashMap;
use config::Config; use config::Config;
use utils::types::InsertAnchor;
use libs::tera::Tera; use libs::tera::Tera;
use markdown::{render_content, RenderContext}; use markdown::{render_content, RenderContext};
use utils::types::InsertAnchor;
static CONTENT: &str = r#" static CONTENT: &str = r#"
# Modus cognitius profanam ne duae virtutis mundi # Modus cognitius profanam ne duae virtutis mundi

View File

@ -21,7 +21,6 @@ const CONTINUE_READING: &str = "<span id=\"continue-reading\"></span>";
const ANCHOR_LINK_TEMPLATE: &str = "anchor-link.html"; const ANCHOR_LINK_TEMPLATE: &str = "anchor-link.html";
static EMOJI_REPLACER: Lazy<EmojiReplacer> = Lazy::new(EmojiReplacer::new); static EMOJI_REPLACER: Lazy<EmojiReplacer> = Lazy::new(EmojiReplacer::new);
/// Efficiently insert multiple element in their specified index. /// Efficiently insert multiple element in their specified index.
/// The elements should sorted in ascending order by their index. /// The elements should sorted in ascending order by their index.
/// ///

View File

@ -6,7 +6,7 @@ use libs::tera::Context;
use serde::Serialize; use serde::Serialize;
use crate::Site; use crate::Site;
use content::{Page, TaxonomyItem}; use content::{Page, TaxonomyTerm};
use errors::Result; use errors::Result;
use utils::templates::render_template; use utils::templates::render_template;
@ -18,7 +18,7 @@ pub struct SerializedFeedTaxonomyItem<'a> {
} }
impl<'a> SerializedFeedTaxonomyItem<'a> { impl<'a> SerializedFeedTaxonomyItem<'a> {
pub fn from_item(item: &'a TaxonomyItem) -> Self { pub fn from_item(item: &'a TaxonomyTerm) -> Self {
SerializedFeedTaxonomyItem { SerializedFeedTaxonomyItem {
name: &item.name, name: &item.name,
slug: &item.slug, slug: &item.slug,

View File

@ -1,9 +1,9 @@
pub mod feed; pub mod feed;
pub mod link_checking; pub mod link_checking;
mod minify;
pub mod sass; pub mod sass;
pub mod sitemap; pub mod sitemap;
pub mod tpls; pub mod tpls;
mod minify;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::remove_dir_all; use std::fs::remove_dir_all;
@ -817,6 +817,9 @@ impl Site {
/// Renders all taxonomies /// Renders all taxonomies
pub fn render_taxonomies(&self) -> Result<()> { pub fn render_taxonomies(&self) -> Result<()> {
for taxonomy in &self.taxonomies { for taxonomy in &self.taxonomies {
if !taxonomy.kind.render {
continue;
}
self.render_taxonomy(taxonomy)?; self.render_taxonomy(taxonomy)?;
} }

View File

@ -98,6 +98,9 @@ pub fn find_entries<'a>(
let mut taxonomies_entries = vec![]; let mut taxonomies_entries = vec![];
for taxonomy in taxonomies { for taxonomy in taxonomies {
if !taxonomy.kind.render {
continue;
}
let name = &taxonomy.kind.name; let name = &taxonomy.kind.name;
let mut terms = vec![SitemapEntry::new(Cow::Owned(config.make_permalink(name)), None)]; let mut terms = vec![SitemapEntry::new(Cow::Owned(config.make_permalink(name)), None)];
for item in &taxonomy.items { for item in &taxonomy.items {

View File

@ -545,6 +545,7 @@ fn can_build_site_with_pagination_for_taxonomy() {
name: "tags".to_string(), name: "tags".to_string(),
paginate_by: Some(2), paginate_by: Some(2),
paginate_path: None, paginate_path: None,
render: true,
feed: true, feed: true,
}); });
site.load().unwrap(); site.load().unwrap();

View File

@ -186,7 +186,7 @@ impl TeraFn for GetTaxonomy {
mod tests { mod tests {
use super::*; use super::*;
use config::{Config, TaxonomyConfig}; use config::{Config, TaxonomyConfig};
use content::TaxonomyItem; use content::TaxonomyTerm;
#[test] #[test]
fn can_get_taxonomy() { fn can_get_taxonomy() {
@ -196,8 +196,8 @@ mod tests {
let taxo_config_fr = let taxo_config_fr =
TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() };
let library = Arc::new(RwLock::new(Library::new())); let library = Arc::new(RwLock::new(Library::new()));
let tag = TaxonomyItem::new("Programming", &config.default_language, "tags", &[], &config); let tag = TaxonomyTerm::new("Programming", &config.default_language, "tags", &[], &config);
let tag_fr = TaxonomyItem::new("Programmation", "fr", "tags", &[], &config); let tag_fr = TaxonomyTerm::new("Programmation", "fr", "tags", &[], &config);
let tags = Taxonomy { let tags = Taxonomy {
kind: taxo_config, kind: taxo_config,
lang: config.default_language.clone(), lang: config.default_language.clone(),
@ -265,8 +265,8 @@ mod tests {
let taxo_config = TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; let taxo_config = TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() };
let taxo_config_fr = let taxo_config_fr =
TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() }; TaxonomyConfig { name: "tags".to_string(), ..TaxonomyConfig::default() };
let tag = TaxonomyItem::new("Programming", &config.default_language, "tags", &[], &config); let tag = TaxonomyTerm::new("Programming", &config.default_language, "tags", &[], &config);
let tag_fr = TaxonomyItem::new("Programmation", "fr", "tags", &[], &config); let tag_fr = TaxonomyTerm::new("Programmation", "fr", "tags", &[], &config);
let tags = Taxonomy { let tags = Taxonomy {
kind: taxo_config, kind: taxo_config,
lang: config.default_language.clone(), lang: config.default_language.clone(),

View File

@ -88,9 +88,8 @@ pub fn copy_file_if_needed(src: &Path, dest: &Path, hard_link: bool) -> Result<(
if hard_link { if hard_link {
std::fs::hard_link(src, dest)? std::fs::hard_link(src, dest)?
} else { } else {
let src_metadata = metadata(src).with_context(|| { let src_metadata = metadata(src)
format!("Failed to get metadata of {}", src.display()) .with_context(|| format!("Failed to get metadata of {}", src.display()))?;
})?;
let src_mtime = FileTime::from_last_modification_time(&src_metadata); let src_mtime = FileTime::from_last_modification_time(&src_metadata);
if Path::new(&dest).is_file() { if Path::new(&dest).is_file() {
let target_metadata = metadata(&dest)?; let target_metadata = metadata(&dest)?;

View File

@ -3,7 +3,6 @@ use std::collections::HashMap;
use errors::{anyhow, Result}; use errors::{anyhow, Result};
/// Result of a successful resolution of an internal link. /// Result of a successful resolution of an internal link.
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct ResolvedInternalLink { pub struct ResolvedInternalLink {
@ -47,7 +46,7 @@ pub fn resolve_internal_link(
mod tests { mod tests {
use std::collections::HashMap; use std::collections::HashMap;
use super::{resolve_internal_link}; use super::resolve_internal_link;
#[test] #[test]
fn can_resolve_valid_internal_link() { fn can_resolve_valid_internal_link() {

View File

@ -29,8 +29,7 @@ name: String,
paginate_by: Number?; paginate_by: Number?;
paginate_path: String?; paginate_path: String?;
feed: Bool; feed: Bool;
lang: String; render: Bool;
permalink: String;
``` ```