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 link_checker settings for external_level and internal_level #1848

Merged
merged 16 commits into from
May 11, 2022
Merged
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
17 changes: 14 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,7 @@ time = "0.3"
name = "zola"

[dependencies]
atty = "0.2.11"
clap = { version = "3", features = ["derive"] }
termcolor = "1.0.4"
# Below is for the serve cmd
hyper = { version = "0.14.1", default-features = false, features = ["runtime", "server", "http2", "http1"] }
tokio = { version = "1.0.1", default-features = false, features = ["rt", "fs", "time"] }
Expand All @@ -39,6 +37,7 @@ mime_guess = "2.0"

site = { path = "components/site" }
errors = { path = "components/errors" }
console = { path = "components/console" }
utils = { path = "components/utils" }
libs = { path = "components/libs" }

Expand Down
18 changes: 18 additions & 0 deletions components/config/src/config/link_checker.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
use serde::{Deserialize, Serialize};

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum LinkCheckerLevel {
#[serde(rename = "error")]
Error,
#[serde(rename = "warn")]
Warn,
}

impl Default for LinkCheckerLevel {
fn default() -> Self {
Self::Error
}
}

#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
#[serde(default)]
pub struct LinkChecker {
/// Skip link checking for these URL prefixes
pub skip_prefixes: Vec<String>,
/// Skip anchor checking for these URL prefixes
pub skip_anchor_prefixes: Vec<String>,
/// Emit either "error" or "warn" for broken internal links (including anchor links).
pub internal_level: LinkCheckerLevel,
/// Emit either "error" or "warn" for broken external links (including anchor links).
pub external_level: LinkCheckerLevel,
}
4 changes: 2 additions & 2 deletions components/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ mod theme;
use std::path::Path;

pub use crate::config::{
languages::LanguageOptions, link_checker::LinkChecker, search::Search, slugify::Slugify,
taxonomies::TaxonomyConfig, Config,
languages::LanguageOptions, link_checker::LinkChecker, link_checker::LinkCheckerLevel,
search::Search, slugify::Slugify, taxonomies::TaxonomyConfig, Config,
};
use errors::Result;

Expand Down
8 changes: 8 additions & 0 deletions components/console/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "console"
mwcz marked this conversation as resolved.
Show resolved Hide resolved
version = "0.1.0"
edition = "2021"

[dependencies]
errors = { path = "../errors" }
libs = { path = "../libs" }
57 changes: 57 additions & 0 deletions components/console/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use std::env;
use std::io::Write;

use libs::atty;
use libs::once_cell::sync::Lazy;
use libs::termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};

/// Termcolor color choice.
/// We do not rely on ColorChoice::Auto behavior
/// as the check is already performed by has_color.
static COLOR_CHOICE: Lazy<ColorChoice> =
Lazy::new(|| if has_color() { ColorChoice::Always } else { ColorChoice::Never });

pub fn info(message: &str) {
colorize(message, ColorSpec::new().set_bold(true), StandardStream::stdout(*COLOR_CHOICE));
}

pub fn warn(message: &str) {
colorize(
&format!("{}{}", "Warning: ", message),
ColorSpec::new().set_bold(true).set_fg(Some(Color::Yellow)),
StandardStream::stdout(*COLOR_CHOICE),
);
}

pub fn success(message: &str) {
colorize(
message,
ColorSpec::new().set_bold(true).set_fg(Some(Color::Green)),
StandardStream::stdout(*COLOR_CHOICE),
);
}

pub fn error(message: &str) {
colorize(
&format!("{}{}", "Error: ", message),
ColorSpec::new().set_bold(true).set_fg(Some(Color::Red)),
StandardStream::stderr(*COLOR_CHOICE),
);
}

/// Print a colorized message to stdout
fn colorize(message: &str, color: &ColorSpec, mut stream: StandardStream) {
stream.set_color(color).unwrap();
write!(stream, "{}", message).unwrap();
stream.set_color(&ColorSpec::new()).unwrap();
writeln!(stream).unwrap();
}

/// Check whether to output colors
fn has_color() -> bool {
let use_colors = env::var("CLICOLOR").unwrap_or_else(|_| "1".to_string()) != "0"
&& env::var("NO_COLOR").is_err();
let force_colors = env::var("CLICOLOR_FORCE").unwrap_or_else(|_| "0".to_string()) != "0";

force_colors || use_colors && atty::is(atty::Stream::Stdout)
}
2 changes: 2 additions & 0 deletions components/libs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ edition = "2021"
[dependencies]
ahash = "0.7.6"
ammonia = "3"
atty = "0.2.11"
base64 = "0.13"
csv = "1"
elasticlunr-rs = {version = "2", default-features = false, features = ["da", "no", "de", "du", "es", "fi", "fr", "it", "pt", "ro", "ru", "sv", "tr"] }
Expand Down Expand Up @@ -34,6 +35,7 @@ slug = "0.1"
svg_metadata = "0.4"
syntect = "5"
tera = { version = "1", features = ["preserve_order"] }
termcolor = "1.0.4"
time = "0.3"
toml = "0.5"
unic-langid = "0.9"
Expand Down
2 changes: 2 additions & 0 deletions components/libs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
pub use ahash;
pub use ammonia;
pub use atty;
pub use base64;
pub use csv;
pub use elasticlunr;
Expand Down Expand Up @@ -34,6 +35,7 @@ pub use slug;
pub use svg_metadata;
pub use syntect;
pub use tera;
pub use termcolor;
pub use time;
pub use toml;
pub use unic_langid;
Expand Down
1 change: 1 addition & 0 deletions components/markdown/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pest_derive = "2"
errors = { path = "../errors" }
utils = { path = "../utils" }
config = { path = "../config" }
console = { path = "../console" }
libs = { path = "../libs" }

[dev-dependencies]
Expand Down
16 changes: 14 additions & 2 deletions components/markdown/src/markdown.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use std::fmt::Write;

use errors::bail;
use libs::gh_emoji::Replacer as EmojiReplacer;
use libs::once_cell::sync::Lazy;
use libs::pulldown_cmark as cmark;
use libs::tera;

use crate::context::RenderContext;
use errors::{anyhow, Context, Error, Result};
use errors::{Context, Error, Result};
use libs::pulldown_cmark::escape::escape_html;
use utils::site::resolve_internal_link;
use utils::slugs::slugify_anchors;
Expand Down Expand Up @@ -139,7 +140,18 @@ fn fix_link(
resolved.permalink
}
Err(_) => {
return Err(anyhow!("Relative link {} not found.", link));
let msg = format!(
"Broken relative link `{}` in {}",
link,
context.current_page_path.unwrap_or("unknown"),
);
match context.config.link_checker.internal_level {
config::LinkCheckerLevel::Error => bail!(msg),
config::LinkCheckerLevel::Warn => {
console::warn(&msg);
link.to_string()
}
}
}
}
} else if is_external_link(link) {
Expand Down
1 change: 1 addition & 0 deletions components/site/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ serde = { version = "1.0", features = ["derive"] }

errors = { path = "../errors" }
config = { path = "../config" }
console = { path = "../console" }
utils = { path = "../utils" }
templates = { path = "../templates" }
search = { path = "../search" }
Expand Down
39 changes: 37 additions & 2 deletions components/site/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,10 +295,45 @@ impl Site {
tpls::register_tera_global_fns(self);

// Needs to be done after rendering markdown as we only get the anchors at that point
link_checking::check_internal_links_with_anchors(self)?;
let internal_link_messages = link_checking::check_internal_links_with_anchors(self);

// log any broken internal links and error out if needed
if let Err(messages) = internal_link_messages {
let messages: Vec<String> = messages
.iter()
.enumerate()
.map(|(i, msg)| format!(" {}. {}", i + 1, msg))
.collect();
let msg = format!(
"Found {} broken internal anchor link(s)\n{}",
messages.len(),
messages.join("\n")
);
match self.config.link_checker.internal_level {
config::LinkCheckerLevel::Warn => console::warn(&msg),
config::LinkCheckerLevel::Error => return Err(anyhow!(msg.clone())),
}
}

// check external links, log the results, and error out if needed
if self.config.is_in_check_mode() {
link_checking::check_external_links(self)?;
let external_link_messages = link_checking::check_external_links(self);
if let Err(messages) = external_link_messages {
let messages: Vec<String> = messages
.iter()
.enumerate()
.map(|(i, msg)| format!(" {}. {}", i + 1, msg))
.collect();
let msg = format!(
"Found {} broken external link(s)\n{}",
messages.len(),
messages.join("\n")
);
match self.config.link_checker.external_level {
config::LinkCheckerLevel::Warn => console::warn(&msg),
config::LinkCheckerLevel::Error => return Err(anyhow!(msg.clone())),
}
}
}

Ok(())
Expand Down
Loading