Don't panic for missing highlight theme (close #1299) (#1307)

* No panic when markdown.highlight_theme is missing

* Better error message for missing theme

* Better error messages

Co-authored-by: southerntofu <southerntofu@thunix.net>
This commit is contained in:
southerntofu 2021-02-04 08:54:12 +00:00 committed by GitHub
parent aa57541c21
commit 53456bd052
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 18 additions and 43 deletions

View file

@ -16,7 +16,7 @@ use toml::Value as Toml;
use crate::highlighting::THEME_SET; use crate::highlighting::THEME_SET;
use crate::theme::Theme; use crate::theme::Theme;
use errors::{bail, Error, Result}; use errors::{bail, Error, Result};
use utils::fs::read_file_with_error; use utils::fs::read_file;
// We want a default base url for tests // We want a default base url for tests
static DEFAULT_BASE_URL: &str = "http://a-website.com"; static DEFAULT_BASE_URL: &str = "http://a-website.com";
@ -124,8 +124,9 @@ impl Config {
bail!("A base URL is required in config.toml with key `base_url`"); bail!("A base URL is required in config.toml with key `base_url`");
} }
if !THEME_SET.themes.contains_key(&config.highlight_theme) { let highlight_theme = config.highlight_theme();
bail!("Highlight theme {} not available", config.highlight_theme) if !THEME_SET.themes.contains_key(highlight_theme) {
bail!("Highlight theme {} defined in config does not exist.", highlight_theme);
} }
if config.languages.iter().any(|l| l.code == config.default_language) { if config.languages.iter().any(|l| l.code == config.default_language) {
@ -169,11 +170,8 @@ impl Config {
/// Parses a config file from the given path /// Parses a config file from the given path
pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config> { pub fn from_file<P: AsRef<Path>>(path: P) -> Result<Config> {
let path = path.as_ref(); let path = path.as_ref();
let file_name = path.file_name().unwrap(); let content = read_file(path)
let content = read_file_with_error( .map_err(|e| errors::Error::chain("Failed to load config", e))?;
path,
&format!("No `{:?}` file found. Are you in the right directory?", file_name),
)?;
Config::parse(&content) Config::parse(&content)
} }
@ -270,8 +268,8 @@ impl Config {
/// Parse the theme.toml file and merges the extra data from the theme /// Parse the theme.toml file and merges the extra data from the theme
/// with the config extra data /// with the config extra data
pub fn merge_with_theme(&mut self, path: &PathBuf) -> Result<()> { pub fn merge_with_theme(&mut self, path: &PathBuf, theme_name: &str) -> Result<()> {
let theme = Theme::from_file(path)?; let theme = Theme::from_file(path, theme_name)?;
self.add_theme_extra(&theme) self.add_theme_extra(&theme)
} }

View file

@ -4,18 +4,12 @@ mod theme;
pub use crate::config::{ pub use crate::config::{
languages::Language, link_checker::LinkChecker, slugify::Slugify, taxonomies::Taxonomy, Config, languages::Language, link_checker::LinkChecker, slugify::Slugify, taxonomies::Taxonomy, Config,
}; };
use errors::Result;
use std::path::Path; use std::path::Path;
/// Get and parse the config. /// Get and parse the config.
/// If it doesn't succeed, exit /// If it doesn't succeed, exit
pub fn get_config(filename: &Path) -> Config { pub fn get_config(filename: &Path) -> Result<Config> {
match Config::from_file(filename) { Config::from_file(filename)
Ok(c) => c,
Err(e) => {
println!("Failed to load {}", filename.display());
println!("Error: {}", e);
::std::process::exit(1);
}
}
} }

View file

@ -5,7 +5,7 @@ use serde_derive::{Deserialize, Serialize};
use toml::Value as Toml; use toml::Value as Toml;
use errors::{bail, Result}; use errors::{bail, Result};
use utils::fs::read_file_with_error; use utils::fs::read_file;
/// Holds the data from a `theme.toml` file. /// Holds the data from a `theme.toml` file.
/// There are other fields than `extra` in it but Zola /// There are other fields than `extra` in it but Zola
@ -39,13 +39,9 @@ impl Theme {
} }
/// Parses a theme file from the given path /// Parses a theme file from the given path
pub fn from_file(path: &PathBuf) -> Result<Theme> { pub fn from_file(path: &PathBuf, theme_name: &str) -> Result<Theme> {
let content = read_file_with_error( let content = read_file(path)
path, .map_err(|e| errors::Error::chain(format!("Failed to load theme {}", theme_name), e))?;
"No `theme.toml` file found. \
Is the `theme` defined in your `config.toml` present in the `themes` directory \
and does it have a `theme.toml` inside?",
)?;
Theme::parse(&content) Theme::parse(&content)
} }
} }

View file

@ -72,12 +72,12 @@ impl Site {
pub fn new<P: AsRef<Path>, P2: AsRef<Path>>(path: P, config_file: P2) -> Result<Site> { pub fn new<P: AsRef<Path>, P2: AsRef<Path>>(path: P, config_file: P2) -> Result<Site> {
let path = path.as_ref(); let path = path.as_ref();
let config_file = config_file.as_ref(); let config_file = config_file.as_ref();
let mut config = get_config(config_file); let mut config = get_config(config_file)?;
config.load_extra_syntaxes(path)?; config.load_extra_syntaxes(path)?;
if let Some(theme) = config.theme.clone() { if let Some(theme) = config.theme.clone() {
// Grab data from the extra section of the theme // Grab data from the extra section of the theme
config.merge_with_theme(&path.join("themes").join(&theme).join("theme.toml"))?; config.merge_with_theme(&path.join("themes").join(&theme).join("theme.toml"), &theme)?;
} }
let tera = tpls::load_tera(path, &config)?; let tera = tpls::load_tera(path, &config)?;

View file

@ -49,7 +49,7 @@ pub fn create_directory(path: &Path) -> Result<()> {
pub fn read_file(path: &Path) -> Result<String> { pub fn read_file(path: &Path) -> Result<String> {
let mut content = String::new(); let mut content = String::new();
File::open(path) File::open(path)
.map_err(|e| Error::chain(format!("Failed to open '{:?}'", path.display()), e))? .map_err(|e| Error::chain(format!("Failed to open '{}'", path.display()), e))?
.read_to_string(&mut content)?; .read_to_string(&mut content)?;
// Remove utf-8 BOM if any. // Remove utf-8 BOM if any.
@ -60,19 +60,6 @@ pub fn read_file(path: &Path) -> Result<String> {
Ok(content) Ok(content)
} }
/// Return the content of a file, with error handling added.
/// The default error message is overwritten by the message given.
/// That means it is allocating 2 strings, oh well
pub fn read_file_with_error(path: &Path, message: &str) -> Result<String> {
let res = read_file(&path);
if res.is_ok() {
return res;
}
let mut err = Error::msg(message);
err.source = res.unwrap_err().source;
Err(err)
}
/// Looks into the current folder for the path and see if there's anything that is not a .md /// Looks into the current folder for the path and see if there's anything that is not a .md
/// file. Those will be copied next to the rendered .html file /// file. Those will be copied next to the rendered .html file
pub fn find_related_assets(path: &Path) -> Vec<PathBuf> { pub fn find_related_assets(path: &Path) -> Vec<PathBuf> {