cobalt/cobalt_model/
config.rs1use std::fmt;
2use std::path;
3
4use log::debug;
5use serde::Serialize;
6use serde_yaml;
7
8use crate::error::Result;
9
10use super::assets;
11use super::collection;
12use super::mark;
13use super::site;
14use super::template;
15use crate::SyntaxHighlight;
16
17#[derive(Debug, Clone, Serialize)]
18#[serde(deny_unknown_fields, default)]
19pub struct Config {
20 pub source: path::PathBuf,
21 pub destination: path::PathBuf,
22 pub ignore: Vec<liquid::model::KString>,
23 pub page_extensions: Vec<liquid::model::KString>,
24 pub include_drafts: bool,
25 pub pages: collection::Collection,
26 pub posts: collection::Collection,
27 pub site: site::Site,
28 pub layouts_path: path::PathBuf,
29 pub liquid: template::LiquidBuilder,
30 pub markdown: mark::MarkdownBuilder,
31 #[serde(skip)]
32 pub syntax: std::sync::Arc<SyntaxHighlight>,
33 pub assets: assets::AssetsBuilder,
34 pub minify: cobalt_config::Minify,
35}
36
37impl Config {
38 pub fn from_config(source: cobalt_config::Config) -> Result<Self> {
39 let cobalt_config::Config {
40 root,
41 source,
42 destination,
43 abs_dest,
44 include_drafts,
45 default,
46 pages,
47 posts,
48 site,
49 template_extensions,
50 ignore: custom_ignore,
51 syntax_highlight,
52 layouts_dir,
53 includes_dir,
54 assets,
55 minify,
56 } = source;
57
58 if include_drafts {
59 debug!("Draft mode enabled");
60 }
61
62 if template_extensions.is_empty() {
63 anyhow::bail!("`template_extensions` should not be empty.");
64 }
65
66 let source = source.to_path(&root);
67 let destination = abs_dest.unwrap_or_else(|| destination.to_path(root));
68
69 let pages = collection::Collection::from_page_config(pages, &site, &default)?;
70
71 let posts =
72 collection::Collection::from_post_config(posts, &site, include_drafts, &default)?;
73
74 let site = site::Site::from_config(site);
75
76 let mut ignore: Vec<liquid::model::KString> = vec![".*".into(), "_*".into()];
77 if let Ok(rel_dest) = path::Path::new(&destination).strip_prefix(&source) {
78 let rel_dest = rel_dest.to_str().expect("started as a utf-8 string");
79 if !rel_dest.is_empty() {
80 ignore.push(format!("/{}", rel_dest.to_owned()).into());
81 }
82 }
83 ignore.push(format!("/{includes_dir}").into());
84 ignore.push(format!("/{layouts_dir}").into());
85 ignore.push("/_defaults".into());
86 ignore.push(format!("/{}", assets.sass.import_dir).into());
87 assert_eq!(pages.dir, "");
88 assert_eq!(pages.drafts_dir, None);
89 ignore.push(format!("!/{}", posts.dir).into());
90 if let Some(dir) = posts.drafts_dir.as_deref() {
91 ignore.push(format!("!/{dir}").into());
92 }
93 ignore.extend(custom_ignore);
94
95 let assets = assets::AssetsBuilder::from_config(assets, &source);
96
97 let includes_path = source.join(includes_dir);
98 let layouts_path = source.join(layouts_dir);
99
100 let mut highlight = SyntaxHighlight::new();
101 let syntaxes_path = source.join("_syntaxes");
102 if syntaxes_path.exists() {
103 highlight.load_custom_syntaxes(&syntaxes_path);
104 }
105
106 let syntax = std::sync::Arc::new(highlight);
107
108 let liquid = template::LiquidBuilder {
109 includes_path,
110 syntax: syntax.clone(),
111 theme: syntax_highlight
112 .enabled
113 .then(|| syntax_highlight.theme.clone()),
114 };
115 let markdown = mark::MarkdownBuilder {
116 syntax: syntax.clone(),
117 theme: syntax_highlight
118 .enabled
119 .then(|| syntax_highlight.theme.clone()),
120 };
121
122 let config = Config {
123 source,
124 destination,
125 ignore,
126 page_extensions: template_extensions,
127 include_drafts,
128 pages,
129 posts,
130 site,
131 layouts_path,
132 liquid,
133 markdown,
134 syntax,
135 assets,
136 minify,
137 };
138
139 Ok(config)
140 }
141}
142
143impl Default for Config {
144 fn default() -> Config {
145 Config::from_config(cobalt_config::Config::default())
146 .expect("default config should not fail")
147 }
148}
149
150impl fmt::Display for Config {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 let mut converted = serde_yaml::to_string(self).map_err(|_| fmt::Error)?;
153 converted.drain(..4);
154 write!(f, "{converted}")
155 }
156}
157
158#[test]
159fn test_build_default() {
160 let config = cobalt_config::Config::default();
161 Config::from_config(config).unwrap();
162}
163
164#[test]
165fn test_build_dest() {
166 let config = cobalt_config::Config::from_file("tests/fixtures/config/_cobalt.yml").unwrap();
167 let result = Config::from_config(config).unwrap();
168 assert_eq!(
169 result.source,
170 path::Path::new("tests/fixtures/config").to_path_buf()
171 );
172 assert_eq!(
173 result.destination,
174 path::Path::new("tests/fixtures/config/dest").to_path_buf()
175 );
176}
177
178#[test]
179fn test_build_abs_dest() {
180 let mut config = cobalt_config::Config::from_file("tests/fixtures/config/_cobalt.yml").unwrap();
181 config.abs_dest = Some(path::PathBuf::from("hello/world"));
182 let result = Config::from_config(config).unwrap();
183 assert_eq!(
184 result.source,
185 path::Path::new("tests/fixtures/config").to_path_buf()
186 );
187 assert_eq!(
188 result.destination,
189 path::Path::new("hello/world").to_path_buf()
190 );
191}