Added support for multiple feeds (i.e. generating both Atom and RSS) (#2477)
* Added support for multiple feeds * Implemented backwards-compatibility for feed config * Added a test for feed config backwards-compat, fixed bugs - Fixed language config merge bug found by a test - Adjusted two existing tests to fully check stuff related to multiple feeds - Added a new test for backwards-compatibility of the changes - Fixed bugs found by the newly added test * Renamed MightBeSingle to SingleOrVec * Made the multiple feeds config changes "loudly" backwards-incompatible * added #[serde(deny_unknown_fields)] to front-matter, fixed problems this found in tests
This commit is contained in:
parent
7f59792d50
commit
c054ed1b10
|
@ -11,6 +11,10 @@
|
|||
- Add `render = false` capability to pages
|
||||
- Handle string dates in YAML front-matter
|
||||
- Add support for fuse.js search format
|
||||
- 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
|
||||
|
||||
## 0.18.0 (2023-12-18)
|
||||
|
||||
|
|
|
@ -8,17 +8,17 @@ use crate::config::search;
|
|||
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 a feed for that language, defaults to `false`
|
||||
pub generate_feed: bool,
|
||||
/// The filename to use for feeds. Used to find the template, too.
|
||||
/// Defaults to "atom.xml", with "rss.xml" also having a template provided out of the box.
|
||||
pub feed_filename: String,
|
||||
/// Whether to generate feeds for that language, defaults to `false`
|
||||
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.
|
||||
pub feed_filenames: Vec<String>,
|
||||
pub taxonomies: Vec<taxonomies::TaxonomyConfig>,
|
||||
/// Whether to generate search index for that language, defaults to `false`
|
||||
pub build_search_index: bool,
|
||||
|
@ -66,9 +66,10 @@ impl LanguageOptions {
|
|||
merge_field!(self.title, other.title, "title");
|
||||
merge_field!(self.description, other.description, "description");
|
||||
merge_field!(
|
||||
self.feed_filename == "atom.xml",
|
||||
self.feed_filename,
|
||||
other.feed_filename,
|
||||
self.feed_filenames.is_empty()
|
||||
|| self.feed_filenames == LanguageOptions::default().feed_filenames,
|
||||
self.feed_filenames,
|
||||
other.feed_filenames,
|
||||
"feed_filename"
|
||||
);
|
||||
merge_field!(self.taxonomies.is_empty(), self.taxonomies, other.taxonomies, "taxonomies");
|
||||
|
@ -79,7 +80,7 @@ impl LanguageOptions {
|
|||
"translations"
|
||||
);
|
||||
|
||||
self.generate_feed = self.generate_feed || other.generate_feed;
|
||||
self.generate_feeds = self.generate_feeds || other.generate_feeds;
|
||||
self.build_search_index = self.build_search_index || other.build_search_index;
|
||||
|
||||
if self.search == search::Search::default() {
|
||||
|
@ -101,8 +102,8 @@ impl Default for LanguageOptions {
|
|||
LanguageOptions {
|
||||
title: None,
|
||||
description: None,
|
||||
generate_feed: false,
|
||||
feed_filename: "atom.xml".to_string(),
|
||||
generate_feeds: false,
|
||||
feed_filenames: vec!["atom.xml".to_string()],
|
||||
taxonomies: vec![],
|
||||
build_search_index: false,
|
||||
search: search::Search::default(),
|
||||
|
@ -129,8 +130,8 @@ mod tests {
|
|||
let mut base_default_language_options = LanguageOptions {
|
||||
title: Some("Site's title".to_string()),
|
||||
description: None,
|
||||
generate_feed: true,
|
||||
feed_filename: "atom.xml".to_string(),
|
||||
generate_feeds: true,
|
||||
feed_filenames: vec!["atom.xml".to_string()],
|
||||
taxonomies: vec![],
|
||||
build_search_index: true,
|
||||
search: search::Search::default(),
|
||||
|
@ -140,8 +141,8 @@ mod tests {
|
|||
let section_default_language_options = LanguageOptions {
|
||||
title: None,
|
||||
description: Some("Site's description".to_string()),
|
||||
generate_feed: false,
|
||||
feed_filename: "rss.xml".to_string(),
|
||||
generate_feeds: false,
|
||||
feed_filenames: vec!["rss.xml".to_string()],
|
||||
taxonomies: vec![],
|
||||
build_search_index: true,
|
||||
search: search::Search::default(),
|
||||
|
@ -156,8 +157,8 @@ mod tests {
|
|||
let mut base_default_language_options = LanguageOptions {
|
||||
title: Some("Site's title".to_string()),
|
||||
description: Some("Duplicate site description".to_string()),
|
||||
generate_feed: true,
|
||||
feed_filename: "".to_string(),
|
||||
generate_feeds: true,
|
||||
feed_filenames: vec![],
|
||||
taxonomies: vec![],
|
||||
build_search_index: true,
|
||||
search: search::Search::default(),
|
||||
|
@ -167,8 +168,8 @@ mod tests {
|
|||
let section_default_language_options = LanguageOptions {
|
||||
title: None,
|
||||
description: Some("Site's description".to_string()),
|
||||
generate_feed: false,
|
||||
feed_filename: "Some feed_filename".to_string(),
|
||||
generate_feeds: false,
|
||||
feed_filenames: vec!["Some feed_filename".to_string()],
|
||||
taxonomies: vec![],
|
||||
build_search_index: true,
|
||||
search: search::Search::default(),
|
||||
|
|
|
@ -30,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,
|
||||
|
@ -49,13 +49,13 @@ pub struct Config {
|
|||
/// The translations strings for the default language
|
||||
translations: HashMap<String, String>,
|
||||
|
||||
/// Whether to generate a feed. Defaults to false.
|
||||
pub generate_feed: bool,
|
||||
/// Whether to generate feeds. Defaults to false.
|
||||
pub generate_feeds: bool,
|
||||
/// The number of articles to include in the feed. Defaults to including all items.
|
||||
pub feed_limit: Option<usize>,
|
||||
/// The filename to use for feeds. Used to find the template, too.
|
||||
/// Defaults to "atom.xml", with "rss.xml" also having a template provided out of the box.
|
||||
pub feed_filename: String,
|
||||
/// 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.
|
||||
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,
|
||||
pub taxonomies: Vec<taxonomies::TaxonomyConfig>,
|
||||
|
@ -109,7 +109,7 @@ pub struct SerializedConfig<'a> {
|
|||
languages: HashMap<&'a String, &'a languages::LanguageOptions>,
|
||||
default_language: &'a str,
|
||||
generate_feed: bool,
|
||||
feed_filename: &'a str,
|
||||
feed_filenames: &'a [String],
|
||||
taxonomies: &'a [taxonomies::TaxonomyConfig],
|
||||
author: &'a Option<String>,
|
||||
build_search_index: bool,
|
||||
|
@ -183,12 +183,14 @@ impl Config {
|
|||
|
||||
/// Makes a url, taking into account that the base url might have a trailing slash
|
||||
pub fn make_permalink(&self, path: &str) -> String {
|
||||
let trailing_bit =
|
||||
if path.ends_with('/') || path.ends_with(&self.feed_filename) || path.is_empty() {
|
||||
""
|
||||
} else {
|
||||
"/"
|
||||
};
|
||||
let trailing_bit = if path.ends_with('/')
|
||||
|| self.feed_filenames.iter().any(|feed_filename| path.ends_with(feed_filename))
|
||||
|| path.is_empty()
|
||||
{
|
||||
""
|
||||
} else {
|
||||
"/"
|
||||
};
|
||||
|
||||
// Index section with a base url that has a trailing slash
|
||||
if self.base_url.ends_with('/') && path == "/" {
|
||||
|
@ -212,8 +214,8 @@ impl Config {
|
|||
let mut base_language_options = languages::LanguageOptions {
|
||||
title: self.title.clone(),
|
||||
description: self.description.clone(),
|
||||
generate_feed: self.generate_feed,
|
||||
feed_filename: self.feed_filename.clone(),
|
||||
generate_feeds: self.generate_feeds,
|
||||
feed_filenames: self.feed_filenames.clone(),
|
||||
build_search_index: self.build_search_index,
|
||||
taxonomies: self.taxonomies.clone(),
|
||||
search: self.search.clone(),
|
||||
|
@ -320,8 +322,8 @@ impl Config {
|
|||
description: &options.description,
|
||||
languages: self.languages.iter().filter(|(k, _)| k.as_str() != lang).collect(),
|
||||
default_language: &self.default_language,
|
||||
generate_feed: options.generate_feed,
|
||||
feed_filename: &options.feed_filename,
|
||||
generate_feed: options.generate_feeds,
|
||||
feed_filenames: &options.feed_filenames,
|
||||
taxonomies: &options.taxonomies,
|
||||
author: &self.author,
|
||||
build_search_index: options.build_search_index,
|
||||
|
@ -369,9 +371,9 @@ impl Default for Config {
|
|||
theme: None,
|
||||
default_language: "en".to_string(),
|
||||
languages: HashMap::new(),
|
||||
generate_feed: false,
|
||||
generate_feeds: false,
|
||||
feed_limit: None,
|
||||
feed_filename: "atom.xml".to_string(),
|
||||
feed_filenames: vec!["atom.xml".to_string()],
|
||||
hard_link_static: false,
|
||||
taxonomies: Vec::new(),
|
||||
author: None,
|
||||
|
@ -428,8 +430,8 @@ mod tests {
|
|||
languages::LanguageOptions {
|
||||
title: None,
|
||||
description: description_lang_section.clone(),
|
||||
generate_feed: true,
|
||||
feed_filename: config.feed_filename.clone(),
|
||||
generate_feeds: true,
|
||||
feed_filenames: config.feed_filenames.clone(),
|
||||
taxonomies: config.taxonomies.clone(),
|
||||
build_search_index: false,
|
||||
search: search::Search::default(),
|
||||
|
@ -456,8 +458,8 @@ mod tests {
|
|||
languages::LanguageOptions {
|
||||
title: title_lang_section.clone(),
|
||||
description: None,
|
||||
generate_feed: true,
|
||||
feed_filename: config.feed_filename.clone(),
|
||||
generate_feeds: true,
|
||||
feed_filenames: config.feed_filenames.clone(),
|
||||
taxonomies: config.taxonomies.clone(),
|
||||
build_search_index: false,
|
||||
search: search::Search::default(),
|
||||
|
@ -976,4 +978,16 @@ author = "person@example.com (Some Person)"
|
|||
let config = Config::parse(config).unwrap();
|
||||
assert_eq!(config.author, Some("person@example.com (Some Person)".to_owned()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_backwards_incompatibility_for_feeds() {
|
||||
let config = r#"
|
||||
base_url = "example.com"
|
||||
generate_feed = true
|
||||
feed_filename = "test.xml"
|
||||
"#;
|
||||
|
||||
Config::parse(config).unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ static DEFAULT_PAGINATE_PATH: &str = "page";
|
|||
|
||||
/// The front matter of every section
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct SectionFrontMatter {
|
||||
/// <title> of the page
|
||||
pub title: Option<String>,
|
||||
|
@ -69,7 +69,7 @@ pub struct SectionFrontMatter {
|
|||
pub aliases: Vec<String>,
|
||||
/// Whether to generate a feed for the current section
|
||||
#[serde(skip_serializing)]
|
||||
pub generate_feed: bool,
|
||||
pub generate_feeds: bool,
|
||||
/// Any extra parameter present in the front matter
|
||||
pub extra: Map<String, Value>,
|
||||
}
|
||||
|
@ -113,7 +113,7 @@ impl Default for SectionFrontMatter {
|
|||
transparent: false,
|
||||
page_template: None,
|
||||
aliases: Vec::new(),
|
||||
generate_feed: false,
|
||||
generate_feeds: false,
|
||||
extra: Map::new(),
|
||||
draft: false,
|
||||
}
|
||||
|
|
|
@ -283,7 +283,7 @@ mod tests {
|
|||
create_dir_all(path.join(&article_path).join("foo/baz/quux"))
|
||||
.expect("create nested temp dir");
|
||||
let mut f = File::create(article_path.join("_index.md")).unwrap();
|
||||
f.write_all(b"+++\nslug=\"hey\"\n+++\n").unwrap();
|
||||
f.write_all(b"+++\n+++\n").unwrap();
|
||||
File::create(article_path.join("example.js")).unwrap();
|
||||
File::create(article_path.join("graph.jpg")).unwrap();
|
||||
File::create(article_path.join("fail.png")).unwrap();
|
||||
|
|
|
@ -160,7 +160,7 @@ pub struct SerializingSection<'a> {
|
|||
subsections: Vec<&'a str>,
|
||||
translations: Vec<TranslatedContent<'a>>,
|
||||
backlinks: Vec<BackLink<'a>>,
|
||||
generate_feed: bool,
|
||||
generate_feeds: bool,
|
||||
transparent: bool,
|
||||
}
|
||||
|
||||
|
@ -220,7 +220,7 @@ impl<'a> SerializingSection<'a> {
|
|||
reading_time: section.reading_time,
|
||||
assets: §ion.serialized_assets,
|
||||
lang: §ion.lang,
|
||||
generate_feed: section.meta.generate_feed,
|
||||
generate_feeds: section.meta.generate_feeds,
|
||||
transparent: section.meta.transparent,
|
||||
pages,
|
||||
subsections,
|
||||
|
|
|
@ -42,7 +42,7 @@ fn bench_render_feed(b: &mut test::Bencher) {
|
|||
let public = &tmp_dir.path().join("public");
|
||||
site.set_output_path(&public);
|
||||
b.iter(|| {
|
||||
site.render_feed(
|
||||
site.render_feeds(
|
||||
site.library.read().unwrap().pages.values().collect(),
|
||||
None,
|
||||
&site.config.default_language,
|
||||
|
|
|
@ -27,13 +27,13 @@ impl<'a> SerializedFeedTaxonomyItem<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn render_feed(
|
||||
pub fn render_feeds(
|
||||
site: &Site,
|
||||
all_pages: Vec<&Page>,
|
||||
lang: &str,
|
||||
base_path: Option<&PathBuf>,
|
||||
additional_context_fn: impl Fn(Context) -> Context,
|
||||
) -> Result<Option<String>> {
|
||||
) -> Result<Option<Vec<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
|
||||
|
@ -73,18 +73,23 @@ pub fn render_feed(
|
|||
context.insert("config", &site.config.serialize(lang));
|
||||
context.insert("lang", lang);
|
||||
|
||||
let feed_filename = &site.config.feed_filename;
|
||||
let feed_url = if let Some(base) = base_path {
|
||||
site.config.make_permalink(&base.join(feed_filename).to_string_lossy().replace('\\', "/"))
|
||||
} else {
|
||||
site.config.make_permalink(feed_filename)
|
||||
};
|
||||
let mut feeds = Vec::new();
|
||||
for feed_filename in &site.config.feed_filenames {
|
||||
let mut context = context.clone();
|
||||
|
||||
context.insert("feed_url", &feed_url);
|
||||
let feed_url = if let Some(base) = base_path {
|
||||
site.config
|
||||
.make_permalink(&base.join(feed_filename).to_string_lossy().replace('\\', "/"))
|
||||
} else {
|
||||
site.config.make_permalink(feed_filename)
|
||||
};
|
||||
|
||||
context = additional_context_fn(context);
|
||||
context.insert("feed_url", &feed_url);
|
||||
|
||||
let feed = render_template(feed_filename, &site.tera, context, &site.config.theme)?;
|
||||
context = additional_context_fn(context);
|
||||
|
||||
Ok(Some(feed))
|
||||
feeds.push(render_template(feed_filename, &site.tera, context, &site.config.theme)?);
|
||||
}
|
||||
|
||||
Ok(Some(feeds))
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
pub mod feed;
|
||||
pub mod feeds;
|
||||
pub mod link_checking;
|
||||
mod minify;
|
||||
pub mod sass;
|
||||
|
@ -746,23 +746,23 @@ impl Site {
|
|||
start = log_time(start, "Rendered sitemap");
|
||||
|
||||
let library = self.library.read().unwrap();
|
||||
if self.config.generate_feed {
|
||||
if self.config.generate_feeds {
|
||||
let is_multilingual = self.config.is_multilingual();
|
||||
let pages: Vec<_> = if is_multilingual {
|
||||
library.pages.values().filter(|p| p.lang == self.config.default_language).collect()
|
||||
} else {
|
||||
library.pages.values().collect()
|
||||
};
|
||||
self.render_feed(pages, None, &self.config.default_language, |c| c)?;
|
||||
self.render_feeds(pages, None, &self.config.default_language, |c| c)?;
|
||||
start = log_time(start, "Generated feed in default language");
|
||||
}
|
||||
|
||||
for (code, language) in &self.config.other_languages() {
|
||||
if !language.generate_feed {
|
||||
if !language.generate_feeds {
|
||||
continue;
|
||||
}
|
||||
let pages: Vec<_> = library.pages.values().filter(|p| &p.lang == code).collect();
|
||||
self.render_feed(pages, Some(&PathBuf::from(code)), code, |c| c)?;
|
||||
self.render_feeds(pages, Some(&PathBuf::from(code)), code, |c| c)?;
|
||||
start = log_time(start, "Generated feed in other language");
|
||||
}
|
||||
self.render_themes_css()?;
|
||||
|
@ -965,14 +965,16 @@ impl Site {
|
|||
} else {
|
||||
PathBuf::from(format!("{}/{}/{}", taxonomy.lang, taxonomy.slug, item.slug))
|
||||
};
|
||||
self.render_feed(
|
||||
self.render_feeds(
|
||||
item.pages.iter().map(|p| library.pages.get(p).unwrap()).collect(),
|
||||
Some(&tax_path),
|
||||
&taxonomy.lang,
|
||||
|mut context: Context| {
|
||||
context.insert("taxonomy", &taxonomy.kind);
|
||||
context
|
||||
.insert("term", &feed::SerializedFeedTaxonomyItem::from_item(item));
|
||||
context.insert(
|
||||
"term",
|
||||
&feeds::SerializedFeedTaxonomyItem::from_item(item),
|
||||
);
|
||||
context
|
||||
},
|
||||
)
|
||||
|
@ -1028,36 +1030,38 @@ impl Site {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// Renders a feed for the given path and at the given path
|
||||
/// If both arguments are `None`, it will render only the feed for the whole
|
||||
/// Renders feeds for the given path and at the given path
|
||||
/// If both arguments are `None`, it will render only the feeds for the whole
|
||||
/// site at the root folder.
|
||||
pub fn render_feed(
|
||||
pub fn render_feeds(
|
||||
&self,
|
||||
all_pages: Vec<&Page>,
|
||||
base_path: Option<&PathBuf>,
|
||||
lang: &str,
|
||||
additional_context_fn: impl Fn(Context) -> Context,
|
||||
) -> Result<()> {
|
||||
let feed = match feed::render_feed(self, all_pages, lang, base_path, additional_context_fn)?
|
||||
{
|
||||
Some(v) => v,
|
||||
None => return Ok(()),
|
||||
};
|
||||
let feed_filename = &self.config.feed_filename;
|
||||
let feeds =
|
||||
match feeds::render_feeds(self, all_pages, lang, base_path, additional_context_fn)? {
|
||||
Some(v) => v,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
if let Some(base) = base_path {
|
||||
let mut components = Vec::new();
|
||||
for component in base.components() {
|
||||
components.push(component.as_os_str().to_string_lossy());
|
||||
for (feed, feed_filename) in feeds.into_iter().zip(self.config.feed_filenames.iter()) {
|
||||
if let Some(base) = base_path {
|
||||
let mut components = Vec::new();
|
||||
for component in base.components() {
|
||||
components.push(component.as_os_str().to_string_lossy());
|
||||
}
|
||||
self.write_content(
|
||||
&components.iter().map(|x| x.as_ref()).collect::<Vec<_>>(),
|
||||
feed_filename,
|
||||
feed,
|
||||
)?;
|
||||
} else {
|
||||
self.write_content(&[], feed_filename, feed)?;
|
||||
}
|
||||
self.write_content(
|
||||
&components.iter().map(|x| x.as_ref()).collect::<Vec<_>>(),
|
||||
feed_filename,
|
||||
feed,
|
||||
)?;
|
||||
} else {
|
||||
self.write_content(&[], feed_filename, feed)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -1076,10 +1080,10 @@ impl Site {
|
|||
output_path.push(component);
|
||||
}
|
||||
|
||||
if section.meta.generate_feed {
|
||||
if section.meta.generate_feeds {
|
||||
let library = &self.library.read().unwrap();
|
||||
let pages = section.pages.iter().map(|k| library.pages.get(k).unwrap()).collect();
|
||||
self.render_feed(
|
||||
self.render_feeds(
|
||||
pages,
|
||||
Some(&PathBuf::from(§ion.path[1..])),
|
||||
§ion.lang,
|
||||
|
|
|
@ -461,27 +461,34 @@ title = "A title"
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn can_get_feed_url_with_default_language() {
|
||||
fn can_get_feed_urls_with_default_language() {
|
||||
let config = Config::parse(CONFIG_DATA).unwrap();
|
||||
let dir = create_temp_dir();
|
||||
let static_fn =
|
||||
GetUrl::new(dir.path().to_path_buf(), config.clone(), HashMap::new(), PathBuf::new());
|
||||
let mut args = HashMap::new();
|
||||
args.insert("path".to_string(), to_value(config.feed_filename).unwrap());
|
||||
args.insert("lang".to_string(), to_value("fr").unwrap());
|
||||
assert_eq!(static_fn.call(&args).unwrap(), "https://remplace-par-ton-url.fr/atom.xml");
|
||||
for feed_filename in &config.feed_filenames {
|
||||
let mut args = HashMap::new();
|
||||
args.insert("path".to_string(), to_value(feed_filename).unwrap());
|
||||
args.insert("lang".to_string(), to_value("fr").unwrap());
|
||||
assert_eq!(static_fn.call(&args).unwrap(), "https://remplace-par-ton-url.fr/atom.xml");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_get_feed_url_with_other_language() {
|
||||
fn can_get_feed_urls_with_other_language() {
|
||||
let config = Config::parse(CONFIG_DATA).unwrap();
|
||||
let dir = create_temp_dir();
|
||||
let static_fn =
|
||||
GetUrl::new(dir.path().to_path_buf(), config.clone(), HashMap::new(), PathBuf::new());
|
||||
let mut args = HashMap::new();
|
||||
args.insert("path".to_string(), to_value(config.feed_filename).unwrap());
|
||||
args.insert("lang".to_string(), to_value("en").unwrap());
|
||||
assert_eq!(static_fn.call(&args).unwrap(), "https://remplace-par-ton-url.fr/en/atom.xml");
|
||||
for feed_filename in &config.feed_filenames {
|
||||
let mut args = HashMap::new();
|
||||
args.insert("path".to_string(), to_value(feed_filename).unwrap());
|
||||
args.insert("lang".to_string(), to_value("en").unwrap());
|
||||
assert_eq!(
|
||||
static_fn.call(&args).unwrap(),
|
||||
"https://remplace-par-ton-url.fr/en/atom.xml"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -11,7 +11,7 @@ to your `config.toml`. For example:
|
|||
|
||||
```toml
|
||||
[languages.fr]
|
||||
generate_feed = true # there will be a feed for French content
|
||||
generate_feeds = true # there will be a feed for French content
|
||||
build_search_index = true
|
||||
taxonomies = [
|
||||
{name = "auteurs"},
|
||||
|
|
|
@ -106,11 +106,11 @@ transparent = false
|
|||
# current one. This takes an array of paths, not URLs.
|
||||
aliases = []
|
||||
|
||||
# If set to "true", a feed file will be generated for this section at the
|
||||
# If set to "true", feed files will be generated for this section at the
|
||||
# section's root path. This is independent of the site-wide variable of the same
|
||||
# name. The section feed will only include posts from that respective feed, and
|
||||
# not from any other sections, including sub-sections under that section.
|
||||
generate_feed = false
|
||||
generate_feeds = false
|
||||
|
||||
# Your own data.
|
||||
[extra]
|
||||
|
|
|
@ -65,12 +65,12 @@ ignored_content = []
|
|||
ignored_static = []
|
||||
|
||||
# When set to "true", a feed is automatically generated.
|
||||
generate_feed = false
|
||||
generate_feeds = false
|
||||
|
||||
# The filename to use for the feed. Used as the template filename, too.
|
||||
# Defaults to "atom.xml", which has a built-in template that renders an Atom 1.0 feed.
|
||||
# The filenames to use for the feeds. Used as the template filenames, too.
|
||||
# Defaults to ["atom.xml"], which has a built-in template that renders an Atom 1.0 feed.
|
||||
# There is also a built-in template "rss.xml" that renders an RSS 2.0 feed.
|
||||
feed_filename = "atom.xml"
|
||||
feed_filenames = ["atom.xml"]
|
||||
|
||||
# The number of articles to include in the feed. All items are included if
|
||||
# this limit is not set (the default).
|
||||
|
@ -199,13 +199,13 @@ index_format = "elasticlunr_javascript"
|
|||
|
||||
# Additional languages definition
|
||||
# You can define language specific config values and translations:
|
||||
# title, description, generate_feed, feed_filename, taxonomies, build_search_index
|
||||
# title, description, generate_feeds, feed_filenames, taxonomies, build_search_index
|
||||
# as well as its own search configuration and translations (see above for details on those)
|
||||
[languages]
|
||||
# For example
|
||||
# [languages.fr]
|
||||
# title = "Mon blog"
|
||||
# generate_feed = true
|
||||
# generate_feeds = true
|
||||
# taxonomies = [
|
||||
# {name = "auteurs"},
|
||||
# {name = "tags"},
|
||||
|
|
|
@ -4,13 +4,13 @@ weight = 50
|
|||
aliases = ["/documentation/templates/rss/"]
|
||||
+++
|
||||
|
||||
If the site `config.toml` file sets `generate_feed = true`, then Zola will
|
||||
generate a feed file for the site, named according to the `feed_filename`
|
||||
If the site `config.toml` file sets `generate_feeds = true`, then Zola will
|
||||
generate feed files for the site, named according to the `feed_filenames`
|
||||
setting in `config.toml`, which defaults to `atom.xml`. Given the feed filename
|
||||
`atom.xml`, the generated file will live at `base_url/atom.xml`, based upon the
|
||||
`atom.xml` file in the `templates` directory, or the built-in Atom template.
|
||||
|
||||
`feed_filename` can be set to any value, but built-in templates are provided
|
||||
`feed_filenames` can be set to any value, but built-in templates are provided
|
||||
for `atom.xml` (in the preferred Atom 1.0 format), and `rss.xml` (in the RSS
|
||||
2.0 format). If you choose a different filename (e.g. `feed.xml`), you will
|
||||
need to provide a template yourself.
|
||||
|
@ -54,7 +54,7 @@ Feeds for taxonomy terms get two more variables, using types from the
|
|||
- `term`: of type `TaxonomyTerm`, but without `term.pages` (use `pages` instead)
|
||||
|
||||
You can also enable separate feeds for each section by setting the
|
||||
`generate_feed` variable to true in the respective section's front matter.
|
||||
`generate_feeds` variable to true in the respective section's front matter.
|
||||
Section feeds will use the same template as indicated in the `config.toml` file.
|
||||
Section feeds, in addition to the five feed template variables, get the
|
||||
`section` variable from the [section
|
||||
|
@ -85,4 +85,4 @@ In order to enable the tag feeds as well, you can overload the `block rss` using
|
|||
Each tag page will refer to it's dedicated feed.
|
||||
|
||||
[atom_rfc]: https://www.rfc-editor.org/rfc/rfc4287
|
||||
[rss_spec]: https://www.rssboard.org/rss-specification#ltauthorgtSubelementOfLtitemgt
|
||||
[rss_spec]: https://www.rssboard.org/rss-specification#ltauthorgtSubelementOfLtitemgt
|
||||
|
|
|
@ -108,8 +108,8 @@ lang: String;
|
|||
translations: Array<TranslatedContent>;
|
||||
// All the pages/sections linking this page: their permalink and a title if there is one
|
||||
backlinks: Array<{permalink: String, title: String?}>;
|
||||
// Whether this section generates a feed or not. Taken from the front-matter if set
|
||||
generate_feed: bool;
|
||||
// Whether this section generates feeds or not. Taken from the front-matter if set
|
||||
generate_feeds: bool;
|
||||
// Whether this section is transparent. Taken from the front-matter if set
|
||||
transparent: bool;
|
||||
```
|
||||
|
|
|
@ -120,7 +120,7 @@ Here's a breakdown of the configuration settings tailored for this theme:
|
|||
- **build_search_index**: If set to `true`, a search index will be built from the pages and section content for the `default_language`.
|
||||
In this configuration and for this theme, it's disabled (`false`).
|
||||
|
||||
- **generate_feed**: Determines if an Atom feed (file `atom.xml`) is automatically generated.
|
||||
- **generate_feeds**: Determines if an Atom feed (file `atom.xml`) is automatically generated.
|
||||
It's set to `true`, meaning a feed will be generated.
|
||||
|
||||
- **taxonomies**: An array of taxonomies (classification systems) used for the site.
|
||||
|
@ -408,4 +408,4 @@ Just use the file `en.toml` as a template for your own translations.
|
|||
This theme is under the MIT License.
|
||||
For details, please refer to the LICENSE file.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
title = "My Integration Testing site"
|
||||
base_url = "https://replace-this-with-your-url.com"
|
||||
compile_sass = true
|
||||
generate_feed = true
|
||||
generate_feeds = true
|
||||
theme = "sample"
|
||||
|
||||
taxonomies = [
|
||||
|
|
|
@ -5,5 +5,5 @@ template = "section_paginated.html"
|
|||
insert_anchor_links = "left"
|
||||
sort_by = "date"
|
||||
aliases = ["another-old-url/index.html"]
|
||||
generate_feed = true
|
||||
generate_feeds = true
|
||||
+++
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
title = "Programming"
|
||||
sort_by = "weight"
|
||||
weight = 1
|
||||
generate_feed = true
|
||||
generate_feeds = true
|
||||
|
||||
[extra]
|
||||
we_have_extra = "variables"
|
||||
|
|
|
@ -9,7 +9,7 @@ build_search_index = true
|
|||
|
||||
default_language = "en"
|
||||
|
||||
generate_feed = true
|
||||
generate_feeds = true
|
||||
|
||||
taxonomies = [
|
||||
{name = "authors", feed = true},
|
||||
|
@ -17,7 +17,7 @@ taxonomies = [
|
|||
]
|
||||
|
||||
[languages.fr]
|
||||
generate_feed = true
|
||||
generate_feeds = true
|
||||
taxonomies = [
|
||||
{name = "auteurs", feed = true},
|
||||
{name = "tags"},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
+++
|
||||
title = "Mon blog"
|
||||
sort_by = "date"
|
||||
insert_anchors = "right"
|
||||
insert_anchor_links = "right"
|
||||
+++
|
||||
|
||||
[Dernières nouvelles](#news)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
+++
|
||||
title = "Il mio blog"
|
||||
sort_by = "date"
|
||||
insert_anchors = "right"
|
||||
insert_anchor_links = "right"
|
||||
+++
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
+++
|
||||
title = "My blog"
|
||||
sort_by = "date"
|
||||
insert_anchors = "left"
|
||||
insert_anchor_links = "left"
|
||||
+++
|
||||
|
|
Loading…
Reference in New Issue