cobalt/cobalt_model/
assets.rs1use std::ffi::OsStr;
2use std::path;
3
4use anyhow::Context as _;
5use log::debug;
6use serde::{Deserialize, Serialize};
7
8use super::sass;
9use super::{Minify, files};
10
11use crate::error::Result;
12
13#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)]
14#[serde(deny_unknown_fields, default)]
15pub struct AssetsBuilder {
16 pub sass: sass::SassBuilder,
17 pub source: path::PathBuf,
18}
19
20impl AssetsBuilder {
21 pub fn from_config(config: cobalt_config::Assets, source: &path::Path) -> Self {
22 Self {
23 sass: sass::SassBuilder::from_config(config.sass, source),
24 source: source.to_owned(),
25 }
26 }
27
28 pub fn build(self) -> Result<Assets> {
29 let AssetsBuilder { sass, source } = self;
30
31 let sass = sass.build();
32
33 let assets = Assets { sass, source };
34 Ok(assets)
35 }
36}
37
38#[derive(Debug)]
39pub struct Assets {
40 sass: sass::SassCompiler,
41 source: path::PathBuf,
42}
43
44impl Assets {
45 pub fn process(
46 &self,
47 path: &path::Path,
48 dest_root: &path::Path,
49 minify: &Minify,
50 ) -> Result<()> {
51 let rel_src = path
52 .strip_prefix(&self.source)
53 .expect("file was found under the root");
54 let dest_path = dest_root.join(rel_src);
55 if sass::is_sass_file(path) {
56 self.sass
57 .compile_file(&self.source, dest_root, path, minify)?;
58 } else if path.extension() == Some(OsStr::new("js")) {
59 copy_and_minify_js(path, &dest_path, minify.js)?;
60 } else if path.extension() == Some(OsStr::new("css")) {
61 copy_and_minify_css(path, &dest_path, minify.css)?;
62 } else {
63 files::copy_file(path, &dest_path)?;
64 }
65 Ok(())
66 }
67}
68
69#[cfg(feature = "html-minifier")]
70fn copy_and_minify_css(src_file: &path::Path, dest_file: &path::Path, minify: bool) -> Result<()> {
71 if minify {
72 use html_minifier::css::minify;
73 if let Some(parent) = dest_file.parent() {
75 std::fs::create_dir_all(parent)
76 .with_context(|| anyhow::format_err!("Could not create {}", parent.display()))?;
77 }
78
79 debug!(
80 "Copying and minifying `{}` to `{}`",
81 src_file.display(),
82 dest_file.display()
83 );
84 let content = std::fs::read_to_string(src_file)?;
85 let minified = minify(&content)
86 .map_err(|e| {
87 anyhow::format_err!(
88 "Could not minify css file {} error {}",
89 src_file.to_string_lossy(),
90 e
91 )
92 })?
93 .to_string();
94 std::fs::write(dest_file, minified)?;
95 } else {
96 files::copy_file(src_file, dest_file)?;
97 }
98 Ok(())
99}
100
101#[cfg(feature = "html-minifier")]
102fn copy_and_minify_js(src_file: &path::Path, dest_file: &path::Path, minify: bool) -> Result<()> {
103 if minify {
104 use html_minifier::js::minify;
105 if let Some(parent) = dest_file.parent() {
107 std::fs::create_dir_all(parent)
108 .with_context(|| anyhow::format_err!("Could not create {}", parent.display()))?;
109 }
110
111 debug!(
112 "Copying and minifying `{}` to `{}`",
113 src_file.display(),
114 dest_file.display()
115 );
116 let content = std::fs::read_to_string(src_file)?;
117 let minified = minify(&content).to_string();
118 std::fs::write(dest_file, minified)?;
119 } else {
120 files::copy_file(src_file, dest_file)?;
121 }
122 Ok(())
123}
124
125#[cfg(not(feature = "html-minifier"))]
126fn copy_and_minify_css(src_file: &path::Path, dest_file: &path::Path, _minify: bool) -> Result<()> {
127 files::copy_file(src_file, dest_file)?;
128 Ok(())
129}
130
131#[cfg(not(feature = "html-minifier"))]
132fn copy_and_minify_js(src_file: &path::Path, dest_file: &path::Path, _minify: bool) -> Result<()> {
133 files::copy_file(src_file, dest_file)?;
134 Ok(())
135}