Skip to content

Commit

Permalink
Made the multiple feeds config changes "loudly" backwards-incompatible
Browse files Browse the repository at this point in the history
  • Loading branch information
LunarEclipse363 committed May 30, 2024
1 parent ff92ecd commit fae17a5
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 57 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- Added support for generating multiple kinds of feeds at once
- Changed config options named `generate_feed` to `generate_feeds` (both in config.toml and in section front-matter)
- Changed config option `feed_filename: String` to `feed_filenames: Vec<String>`
- The config file no longer allows arbitrary fields outside the `[extra]` section (front-matter is unaffected)

## 0.18.0 (2023-12-18)

Expand Down
5 changes: 1 addition & 4 deletions components/config/src/config/languages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,19 @@ use libs::unic_langid::LanguageIdentifier;
use serde::{Deserialize, Serialize};

use crate::config::search;
use crate::config::single_or_vec;
use crate::config::taxonomies;

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct LanguageOptions {
/// Title of the site. Defaults to None
pub title: Option<String>,
/// Description of the site. Defaults to None
pub description: Option<String>,
/// Whether to generate feeds for that language, defaults to `false`
#[serde(alias = "generate_feed")]
pub generate_feeds: bool,
/// The filenames to use for feeds. Used to find the templates, too.
/// Defaults to ["atom.xml"], with "rss.xml" also having a template provided out of the box.
#[serde(alias = "feed_filename", deserialize_with = "single_or_vec")]
pub feed_filenames: Vec<String>,
pub taxonomies: Vec<taxonomies::TaxonomyConfig>,
/// Whether to generate search index for that language, defaults to `false`
Expand Down
56 changes: 5 additions & 51 deletions components/config/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ use std::path::{Path, PathBuf};

use libs::globset::GlobSet;
use libs::toml::Value as Toml;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer, Serialize};
use serde::{Deserialize, Serialize};

use crate::theme::Theme;
use errors::{anyhow, bail, Result};
Expand All @@ -31,7 +30,7 @@ pub enum Mode {
}

#[derive(Clone, Debug, Deserialize)]
#[serde(default)]
#[serde(default, deny_unknown_fields)]
pub struct Config {
/// Base URL of the site, the only required config argument
pub base_url: String,
Expand All @@ -51,13 +50,11 @@ pub struct Config {
translations: HashMap<String, String>,

/// Whether to generate feeds. Defaults to false.
#[serde(alias = "generate_feed")]
pub generate_feeds: bool,
/// The number of articles to include in the feed. Defaults to including all items.
pub feed_limit: Option<usize>,
/// The filenames to use for feeds. Used to find the templates, too.
/// Defaults to ["atom.xml"], with "rss.xml" also having a template provided out of the box.
#[serde(alias = "feed_filename", deserialize_with = "single_or_vec")]
pub feed_filenames: Vec<String>,
/// If set, files from static/ will be hardlinked instead of copied to the output dir.
pub hard_link_static: bool,
Expand Down Expand Up @@ -400,48 +397,6 @@ impl Default for Config {
}
}

/// Used for deserializing values that can be either a single value or a vec of values
pub(crate) fn single_or_vec<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
where
T: DeserializeOwned,
D: Deserializer<'de>,
{
let v = SingleOrVec::deserialize(deserializer)?;
Ok(v.into())
}

#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
#[serde(untagged)]
pub(crate) enum SingleOrVec<T> {
Multiple(Vec<T>),
One(T),
None,
}

impl<T> From<SingleOrVec<T>> for Vec<T> {
fn from(x: SingleOrVec<T>) -> Vec<T> {
use SingleOrVec::*;

match x {
Multiple(v) => v,
One(v) => vec![v],
None => vec![],
}
}
}

impl<T> From<Vec<T>> for SingleOrVec<T> {
fn from(value: Vec<T>) -> Self {
Self::Multiple(value)
}
}

impl<T> Default for SingleOrVec<T> {
fn default() -> Self {
Self::None
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -1025,15 +980,14 @@ author = "[email protected] (Some Person)"
}

#[test]
fn test_backwards_compatibility_for_feeds() {
#[should_panic]
fn test_backwards_incompatibility_for_feeds() {
let config = r#"
base_url = "example.com"
generate_feed = true
feed_filename = "test.xml"
"#;

let config = Config::parse(config).unwrap();
assert_eq!(config.generate_feeds, true);
assert_eq!(config.feed_filenames, vec!["test.xml".to_owned()]);
Config::parse(config).unwrap();
}
}
28 changes: 27 additions & 1 deletion components/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ mod config;
pub mod highlighting;
mod theme;

use std::path::Path;
use std::{marker::PhantomData, path::Path};

pub use crate::config::{
languages::LanguageOptions,
Expand All @@ -14,9 +14,35 @@ pub use crate::config::{
Config,
};
use errors::Result;
use serde::Deserialize;

/// Get and parse the config.
/// If it doesn't succeed, exit
pub fn get_config(filename: &Path) -> Result<Config> {
Config::from_file(filename)
}

/// This is used to print an error message for deprecated fields
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct Deprecated<T> {
_type: PhantomData<T>,
}

impl<T> Deprecated<T> {
pub fn new() -> Self {
Self { _type: PhantomData }
}
}

pub trait DeprecationReason {
const REASON: &'static str;
}

impl<'de, T: DeprecationReason> Deserialize<'de> for Deprecated<T> {
fn deserialize<D>(_deserializer: D) -> std::prelude::v1::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Err(serde::de::Error::custom(format!("Failed to parse a deprecated option: {}", T::REASON)))
}
}
14 changes: 13 additions & 1 deletion components/content/src/front_matter/section.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use libs::tera::{Map, Value};
use serde::{Deserialize, Serialize};

use config::{Deprecated, DeprecationReason};
use errors::Result;
use utils::de::fix_toml_dates;
use utils::types::InsertAnchor;
Expand Down Expand Up @@ -67,13 +68,23 @@ pub struct SectionFrontMatter {
/// redirect to this
#[serde(skip_serializing)]
pub aliases: Vec<String>,
/// Deprecated
#[serde(skip_serializing)]
pub generate_feed: Deprecated<DeprecatedGenerateFeed>,
/// Whether to generate a feed for the current section
#[serde(skip_serializing, alias = "generate_feed")]
#[serde(skip_serializing)]
pub generate_feeds: bool,
/// Any extra parameter present in the front matter
pub extra: Map<String, Value>,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct DeprecatedGenerateFeed {}

impl DeprecationReason for DeprecatedGenerateFeed {
const REASON: &'static str = "generate_feed is deprecated, please use generate_feeds instead";
}

impl SectionFrontMatter {
pub fn parse(raw: &RawFrontMatter) -> Result<SectionFrontMatter> {
let mut f: SectionFrontMatter = raw.deserialize()?;
Expand Down Expand Up @@ -113,6 +124,7 @@ impl Default for SectionFrontMatter {
transparent: false,
page_template: None,
aliases: Vec::new(),
generate_feed: Deprecated::new(),
generate_feeds: false,
extra: Map::new(),
draft: false,
Expand Down

0 comments on commit fae17a5

Please sign in to comment.