use std::{ env, fs, path::{Path, PathBuf}, }; fn fnv1a64(parts: &[&[u8]]) -> u64 { let mut hash = 0xcbf29ce484222325u64; for part in parts { for byte in *part { hash ^= u64::from(*byte); hash = hash.wrapping_mul(0x100000001b3); } } hash } fn bundle_manifest(root: &Path, directory: &Path, manifest: &Path, extension: &str) -> String { println!("cargo:rerun-if-changed={}", manifest.display()); let manifest_text = fs::read_to_string(manifest) .unwrap_or_else(|error| panic!("{}: {error}", manifest.display())); let mut bundle = String::new(); for raw in manifest_text.lines() { let name = raw.trim(); if name.is_empty() || name.starts_with('#') { continue; } assert!( name.ends_with(extension) && !name.contains('/') && !name.contains('\\') && !name.contains(".."), "invalid {extension} manifest entry: {name}" ); let path = directory.join(name); assert!( path.starts_with(root), "asset path escaped project root: {}", path.display() ); println!("cargo:rerun-if-changed={}", path.display()); let source = fs::read_to_string(&path).unwrap_or_else(|error| panic!("{}: {error}", path.display())); if !bundle.is_empty() { bundle.push('\n'); } bundle.push_str(&source); if !source.ends_with('\n') { bundle.push('\n'); } } bundle } fn main() { let root = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR")); let out = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR")); let css_dir = root.join("src/web/css"); let js_dir = root.join("src/web/js"); for path in [ root.join("src/web/index.html"), root.join("src/web/icons.svg"), root.join("src/web/i18n/en.json"), root.join("src/web/i18n/pl.json"), ] { println!("cargo:rerun-if-changed={}", path.display()); } let css_bundle = bundle_manifest(&root, &css_dir, &css_dir.join("manifest.txt"), ".css"); let js_bundle = bundle_manifest(&root, &js_dir, &js_dir.join("manifest.txt"), ".js"); let asset_id = fnv1a64(&[css_bundle.as_bytes(), js_bundle.as_bytes()]); println!("cargo:rustc-env=RUSTBOX_ASSET_ID={asset_id:016x}"); fs::write(out.join("rustbox-ui.css"), css_bundle).expect("write RustBox CSS bundle"); fs::write(out.join("rustbox-ui.js"), js_bundle).expect("write RustBox JavaScript bundle"); }