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).map_err(|e| {
86 anyhow::format_err!(
87 "Could not minify css file {} error {}",
88 src_file.to_string_lossy(),
89 e
90 )
91 })?;
92 std::fs::write(dest_file, minified)?;
93 } else {
94 files::copy_file(src_file, dest_file)?;
95 }
96 Ok(())
97}
98
99#[cfg(feature = "html-minifier")]
100fn copy_and_minify_js(src_file: &path::Path, dest_file: &path::Path, minify: bool) -> Result<()> {
101 if minify {
102 use html_minifier::js::minify;
103 if let Some(parent) = dest_file.parent() {
105 std::fs::create_dir_all(parent)
106 .with_context(|| anyhow::format_err!("Could not create {}", parent.display()))?;
107 }
108
109 debug!(
110 "Copying and minifying `{}` to `{}`",
111 src_file.display(),
112 dest_file.display()
113 );
114 let content = std::fs::read_to_string(src_file)?;
115 std::fs::write(dest_file, minify(&content))?;
116 } else {
117 files::copy_file(src_file, dest_file)?;
118 }
119 Ok(())
120}
121
122#[cfg(not(feature = "html-minifier"))]
123fn copy_and_minify_css(src_file: &path::Path, dest_file: &path::Path, _minify: bool) -> Result<()> {
124 files::copy_file(src_file, dest_file)?;
125 Ok(())
126}
127
128#[cfg(not(feature = "html-minifier"))]
129fn copy_and_minify_js(src_file: &path::Path, dest_file: &path::Path, _minify: bool) -> Result<()> {
130 files::copy_file(src_file, dest_file)?;
131 Ok(())
132}