Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add default template warning #2205

Open
wants to merge 8 commits into
base: next
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Changelog

## 0.18.0 (unreleased)

## 0.17.2 (2023-03-19)

- Fix one more invalid error with colocated directories
Expand Down
13 changes: 8 additions & 5 deletions components/link_checker/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ pub fn message(res: &Result) -> String {
// Keep history of link checks so a rebuild doesn't have to check again
static LINKS: Lazy<Arc<RwLock<HashMap<String, Result>>>> =
Lazy::new(|| Arc::new(RwLock::new(HashMap::new())));
// Make sure to create only a single Client so that we can reuse the connections
static CLIENT: Lazy<Client> = Lazy::new(|| {
Client::builder()
.user_agent(concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")))
.build()
.expect("reqwest client build")
});

pub fn check_url(url: &str, config: &LinkChecker) -> Result {
{
Expand All @@ -44,15 +51,11 @@ pub fn check_url(url: &str, config: &LinkChecker) -> Result {
headers.append(ACCEPT, "*/*".parse().unwrap());

// TODO: pass the client to the check_url, do not pass the config
let client = Client::builder()
.user_agent(concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION")))
.build()
.expect("reqwest client build");

let check_anchor = !config.skip_anchor_prefixes.iter().any(|prefix| url.starts_with(prefix));

// Need to actually do the link checking
let res = match client.get(url).headers(headers).send() {
let res = match CLIENT.get(url).headers(headers).send() {
Ok(ref mut response) if check_anchor && has_anchor(url) => {
let body = {
let mut buf: Vec<u8> = vec![];
Expand Down
36 changes: 35 additions & 1 deletion components/site/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use utils::fs::{
ensure_directory_exists,
};
use utils::net::{get_available_port, is_external_link};
use utils::templates::{render_template, ShortcodeDefinition};
use utils::templates::{is_default_template, render_template, ShortcodeDefinition};
use utils::types::InsertAnchor;

pub static SITE_CONTENT: Lazy<Arc<RwLock<HashMap<RelativePathBuf, String>>>> =
Expand Down Expand Up @@ -362,6 +362,40 @@ impl Site {
Ok(())
}

/// Gather all sites and pages which were rendered with a default template.
/// We can later warn the user about possible unexpected defaults.
pub fn get_default_templates(&self) -> Result<Vec<String>> {
let lib = self.library.read().unwrap();
let pages = &lib.pages;
let sections = &lib.sections;
let mut result: Vec<String> = Vec::with_capacity(pages.len() + sections.len());
for (path, page) in pages.iter() {
let name;
let default_name = "page.html".to_owned();
if let Some(template) = &page.meta.template {
name = template;
} else {
name = &default_name;
}
if is_default_template(name, &self.tera, &self.config.theme)? {
result.push(path.display().to_string());
}
}
for (path, section) in sections.iter() {
let name;
let default_name = "section.html".to_owned();
if let Some(template) = &section.meta.template {
name = template;
} else {
name = &default_name;
}
if is_default_template(name, &self.tera, &self.config.theme)? {
result.push(path.display().to_string());
}
}
Ok(result)
}

/// Insert a default index section for each language if necessary so we don't need to create
/// a _index.md to render the index page at the root of the site
pub fn create_default_index_sections(&mut self) -> Result<()> {
Expand Down
2 changes: 1 addition & 1 deletion components/templates/src/builtins/atom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
{% if page.summary %}
<summary type="html">{{ page.summary }}</summary>
{% else %}
<content type="html">{{ page.content }}</content>
<content type="html" xml:base="{{ page.permalink | escape_xml | safe }}">{{ page.content }}</content>
{% endif %}
</entry>
{%- endfor %}
Expand Down
2 changes: 1 addition & 1 deletion components/templates/src/builtins/rss.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
</author>
<link>{{ page.permalink | escape_xml | safe }}</link>
<guid>{{ page.permalink | escape_xml | safe }}</guid>
<description>{% if page.summary %}{{ page.summary }}{% else %}{{ page.content }}{% endif %}</description>
<description xml:base="{{ page.permalink | escape_xml | safe }}">{% if page.summary %}{{ page.summary }}{% else %}{{ page.content }}{% endif %}</description>
</item>
{%- endfor %}
</channel>
Expand Down
70 changes: 69 additions & 1 deletion components/templates/src/filters.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::hash::BuildHasher;
use std::sync::{Arc, Mutex};

use config::Config;

use libs::base64::engine::{general_purpose::STANDARD as standard_b64, Engine};
use libs::regex::Regex;
use libs::tera::{
to_value, try_get_value, Error as TeraError, Filter as TeraFilter, Result as TeraResult, Tera,
Value,
Expand Down Expand Up @@ -78,6 +81,53 @@ pub fn base64_decode<S: BuildHasher>(
Ok(to_value(as_str).unwrap())
}

#[derive(Debug)]
pub struct RegexReplaceFilter {
re_cache: Arc<Mutex<HashMap<String, Regex>>>,
}

impl RegexReplaceFilter {
pub fn new() -> Self {
return Self { re_cache: Arc::new(Mutex::new(HashMap::new())) };
}
}

impl TeraFilter for RegexReplaceFilter {
fn filter(&self, value: &Value, args: &HashMap<String, Value>) -> TeraResult<Value> {
let text = try_get_value!("regex_replace", "value", String, value);
let pattern = match args.get("pattern") {
Some(val) => try_get_value!("regex_replace", "pattern", String, val),
None => {
return Err(TeraError::msg(
"Filter `regex_replace` expected an arg called `pattern`",
))
}
};
let rep = match args.get("rep") {
Some(val) => try_get_value!("regex_replace", "rep", String, val),
None => {
return Err(TeraError::msg("Filter `regex_replace` expected an arg called `rep`"))
}
};

let mut cache = self.re_cache.lock().expect("re_cache lock");
let replaced = {
match cache.get(&pattern) {
Some(pat) => pat.replace_all(&text, &rep),
None => {
let pat = Regex::new(&pattern)
.map_err(|e| format!("`regex_replace`: failed to compile regex: {}", e))?;
let replaced = pat.replace_all(&text, &rep);
cache.insert(pattern, pat);
replaced
}
}
};

Ok(to_value(replaced).unwrap())
}
}

#[derive(Debug)]
pub struct NumFormatFilter {
default_language: String,
Expand Down Expand Up @@ -114,7 +164,9 @@ mod tests {

use libs::tera::{to_value, Filter, Tera};

use super::{base64_decode, base64_encode, MarkdownFilter, NumFormatFilter};
use super::{
base64_decode, base64_encode, MarkdownFilter, NumFormatFilter, RegexReplaceFilter,
};
use config::Config;

#[test]
Expand Down Expand Up @@ -251,6 +303,22 @@ mod tests {
}
}

#[test]
fn regex_replace_filter() {
let value = "Springsteen, Bruce";
let expected = "Bruce Springsteen";
let pattern = r"(?P<last>[^,\s]+),\s+(?P<first>\S+)";
let rep = "$first $last";
let mut args = HashMap::new();
args.insert("pattern".to_string(), to_value(pattern).unwrap());
args.insert("rep".to_string(), to_value(rep).unwrap());
let regex_replace = RegexReplaceFilter::new();
let result = regex_replace.filter(&to_value(value).unwrap(), &args);
assert!(result.is_ok());
assert_eq!(result.unwrap(), to_value(expected).unwrap());
assert!(regex_replace.re_cache.lock().unwrap().contains_key(pattern));
}

#[test]
fn num_format_filter() {
let tests = vec![
Expand Down
1 change: 1 addition & 0 deletions components/templates/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ pub static ZOLA_TERA: Lazy<Tera> = Lazy::new(|| {
.unwrap();
tera.register_filter("base64_encode", filters::base64_encode);
tera.register_filter("base64_decode", filters::base64_decode);
tera.register_filter("regex_replace", filters::RegexReplaceFilter::new());
tera
});

Expand Down
10 changes: 10 additions & 0 deletions components/utils/src/templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ pub fn render_template(
}
}

pub fn is_default_template(name: &str, tera: &Tera, theme: &Option<String>) -> Result<bool> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's not the right place to check. You essentially need to search for templates with that name in a theme or the templates directory Tera instances. Only if there are no overrides should the message be shown. Another way to do it would be to have a log Tera functions that does println so the template itself can warn

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You essentially need to search for templates with that name in a theme or the templates directory Tera instances. Only if there are no overrides should the message be shown.

Sorry, I thought I had accomplished this with this function which uses check_template_fallbacks. I will think on this but I am currently confused as to how to do this differently without repeating the logic in check_template_fallbacks.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How do I do this without repeating logic in check_template_fallbacks?

if check_template_fallbacks(name, tera, theme).is_some() {
return Ok(false);
}
match name {
"index.html" | "section.html" | "page.html" | "single.html" | "list.html" => Ok(true),
_ => bail!("Template not found for {}", name),
}
}

/// Rewrites the path of duplicate templates to include the complete theme path
/// Theme templates will be injected into site templates, with higher priority for site
/// templates. To keep a copy of the template in case it's being extended from a site template
Expand Down
8 changes: 8 additions & 0 deletions docs/content/documentation/templates/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,14 @@ Encode the variable to base64.
### base64_decode
Decode the variable from base64.

### regex_replace
Replace text via regular expressions.

```jinja2
{{ "World Hello" | regex_replace(pattern=`(?P<subject>\w+), (?P<greeting>\w+)`, rep=`$greeting $subject`) }}
<!-- Hello World -->
```

### num_format
Format a number into its string representation.

Expand Down
1 change: 1 addition & 0 deletions src/cmd/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ pub fn build(
site.load()?;
messages::notify_site_size(&site);
messages::warn_about_ignored_pages(&site);
messages::warn_about_default_templates(&site)?;
site.build()
}
1 change: 1 addition & 0 deletions src/cmd/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@ pub fn check(
site.load()?;
messages::check_site_summary(&site);
messages::warn_about_ignored_pages(&site);
messages::warn_about_default_templates(&site)?;
Ok(())
}
1 change: 1 addition & 0 deletions src/cmd/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ fn create_new_site(
}
messages::notify_site_size(&site);
messages::warn_about_ignored_pages(&site);
messages::warn_about_default_templates(&site)?;
site.build()?;
Ok((site, address))
}
Expand Down
16 changes: 12 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::path::{Path, PathBuf};
use std::time::Instant;

use cli::{Cli, Command};
use errors::anyhow;
use utils::net::{get_available_port, port_is_available};

use clap::{CommandFactory, Parser};
Expand All @@ -13,10 +14,17 @@ mod messages;
mod prompt;

fn get_config_file_path(dir: &Path, config_path: &Path) -> (PathBuf, PathBuf) {
let root_dir = dir
.ancestors()
.find(|a| a.join(config_path).exists())
.unwrap_or_else(|| panic!("could not find directory containing config file"));
let root_dir = dir.ancestors().find(|a| a.join(config_path).exists()).unwrap_or_else(|| {
messages::unravel_errors(
"",
&anyhow!(
"{} not found in current directory or ancestors, current_dir is {}",
config_path.display(),
dir.display()
),
);
std::process::exit(1);
});

// if we got here we found root_dir so config file should exist so we can unwrap safely
let config_file = root_dir
Expand Down
11 changes: 10 additions & 1 deletion src/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use libs::time::Duration;
use std::convert::TryInto;
use std::time::Instant;

use errors::Error;
use errors::{Error, Result};
use site::Site;

/// Display in the console the number of pages/sections in the site
Expand Down Expand Up @@ -52,6 +52,15 @@ pub fn warn_about_ignored_pages(site: &Site) {
}
}

/// Display a warning in the console if there are default templates rendered
pub fn warn_about_default_templates(site: &Site) -> Result<()> {
let default_templates = site.get_default_templates()?;
for path_string in default_templates.iter() {
console::warn(&format!("- {} is using the default template", path_string));
}
Ok(())
}

/// Print the time elapsed rounded to 1 decimal
pub fn report_elapsed_time(instant: Instant) {
let duration: Duration = instant.elapsed().try_into().unwrap();
Expand Down