use std::{error::Error, ffi::OsStr, fs, path::PathBuf, process::{self, Command}}; use css_minify::optimizations::{Minifier, Level}; fn asset_path(asset: &PathBuf) -> PathBuf { let mut path = asset.components().take(1).collect::(); path.push(asset.components().last().unwrap()); path } fn template_path(template: &PathBuf) -> PathBuf { let mut path = template.components().take(template.components().count() - 2).collect::(); path.push(template.components().last().unwrap()); path } fn extfilter(valid: String, x: Option<&OsStr>) -> bool { if x.is_none() { return false } let ext = x.clone().unwrap().to_str().unwrap().to_string(); ext == valid } fn system(cmd: &str, args: &[&str]) -> Result> { let out = Command::new(cmd) .args(args) .output() ?; if out.stderr.len() != 0 { panic!("Got this while running {cmd} with \"{}\": {}", args.join(" "), String::from_utf8(out.stderr).unwrap()) } Ok(String::from_utf8(out.stdout)?) } fn check_cmd>(cmd: T) -> bool { Command::new(cmd) .spawn() .is_ok() } fn main() { let html_exists = check_cmd("html-minifier"); let ugjs_exists = check_cmd("uglify-js"); if ! (html_exists || ugjs_exists) { eprintln!("html-minifier or uglify-js are not installed! Trying to install them via npm..."); if ! check_cmd("npm") { eprintln!("npm is not installed! Please install npm and/or html-minifier and uglify-js and build again"); process::exit(1) } let mut cmd = Command::new("npm"); cmd.arg("install") .arg("--global"); if ! html_exists { cmd.arg("html-minifier"); } if ! ugjs_exists { cmd.arg("uglify-js"); } let res = cmd.spawn().unwrap().wait().unwrap(); if res.success() { eprintln!("Successfully installed html-minifier and/or uglify-js"); } else { eprintln!("Couldn't install html-minifier and/or uglify-js! Check the log above for details."); process::exit(1) } } println!("cargo:rerun-if-changed=static/assets"); println!("cargo:rerun-if-changed=templates/source"); let assets = fs::read_dir("static/assets").unwrap(); let assets = assets .map(|x| x.unwrap().path()) .filter(|x| x.extension().is_some()) .collect::>(); let styles = assets .iter() .filter(|x| { extfilter("css".into(), x.extension()) }) .collect::>(); let scripts = assets .iter() .filter(|x| { extfilter("js".into(), x.extension()) }) .collect::>(); styles.iter().for_each(|asset| { let bundled = Minifier::default().minify( String::from_utf8(fs::read(asset).unwrap()).unwrap().as_str(), Level::Zero ).unwrap(); fs::write(asset_path(asset), bundled).unwrap(); }); scripts.iter().for_each(|asset| { Command::new("uglifyjs") .arg(asset) .arg("-o") .arg(asset_path(asset)) .arg("-c") .spawn() .unwrap(); }); // precompile templates let templates = fs::read_dir("templates/source").unwrap(); let templates = templates .map(|x| x.unwrap().path().canonicalize().unwrap()) .filter(|x| extfilter("html".into(), x.extension())) .collect::>(); templates.iter().for_each(|template| { Command::new("html-minifier") .arg(template.canonicalize().unwrap()) .arg("--collapse-whitespace") // .arg("--minify-js") // .arg("--minify-css") // .arg("--keep-closing-slash") .arg("--output") .arg(template_path(template)) .spawn() .unwrap(); }); let commit = system("git", &["rev-parse", "HEAD"]).map_err(|x| x.to_string()); let branch = system("git", &["rev-parse", "--abbrev-ref", "HEAD"]).map_err(|x| x.to_string()); match commit { Err(err) => panic!("Can't get commit: {}", err), Ok(commit) => println!("cargo:rustc-env=COMMIT_HASH={commit}") } match branch { Err(err) => panic!("Can't get commit: {}", err), Ok(branch) => println!("cargo:rustc-env=COMMIT_BRANCH={branch}") } }