use std::env;
use std::fmt::Write as _;
use std::fs;
use std::path::{Path, PathBuf};
use ferroui_build::{Build, TypeSystem, XamlGroup};
fn collect(root: &Path, directory: &Path, found: &mut Vec<(String, PathBuf)>) {
println!("cargo::rerun-if-changed={}", directory.display());
let mut entries: Vec<PathBuf> = fs::read_dir(directory)
.unwrap_or_else(|e| panic!("cannot read {}: {e}", directory.display()))
.map(|entry| entry.expect("directory entry").path())
.collect();
entries.sort();
for path in entries {
let name = path.file_name().and_then(|name| name.to_str()).unwrap_or_default();
if path.is_dir() {
if !name.starts_with('.') {
collect(root, &path, found);
}
continue;
}
if path.extension().is_some_and(|extension| extension == "xaml") {
let relative = path.strip_prefix(root).expect("a path under the crate directory");
let parts: Vec<String> =
relative.components().map(|c| c.as_os_str().to_string_lossy().into_owned()).collect();
found.push((format!("/{}", parts.join("/")), path));
}
}
}
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")).join("assets.rs");
let mut assets = Vec::new();
collect(&root, &root.join("Themes"), &mut assets);
assets.sort();
let mut text = String::from("pub(crate) static ASSETS: &[(&str, &[u8])] = &[\n");
let mut documents: Vec<(String, String)> = Vec::with_capacity(assets.len());
for (asset_path, path) in &assets {
let path = path.canonicalize().unwrap_or_else(|e| panic!("cannot resolve {}: {e}", path.display()));
println!("cargo::rerun-if-changed={}", path.display());
writeln!(text, " ({asset_path:?}, include_bytes!({:?})),", path.display().to_string()).expect("write");
let document = fs::read_to_string(&path).unwrap_or_else(|e| panic!("cannot read {}: {e}", path.display()));
documents.push((asset_path.trim_start_matches('/').to_string(), document));
}
text.push_str("];\n");
let documents: Vec<(&str, &str)> = documents.iter().map(|(name, text)| (name.as_str(), text.as_str())).collect();
Build::from_env()
.type_system(TypeSystem::Model)
.compile_group(XamlGroup::new("compiled_xaml").documents(&documents))
.run();
if fs::read_to_string(&out).ok().as_deref() != Some(text.as_str()) {
fs::write(&out, text).unwrap_or_else(|e| panic!("cannot write {}: {e}", out.display()));
}
generate_windows_ink_bindings(&root);
}
fn generate_windows_ink_bindings(root: &Path) {
let idl_path = root.join("windows_ink.idl");
println!("cargo::rerun-if-changed={}", idl_path.display());
let source = fs::read_to_string(&idl_path).unwrap_or_else(|e| panic!("{}: {e}", idl_path.display()));
let parsed = microcom_codegen::parse(&source).unwrap_or_else(|e| panic!("{}:{e}", idl_path.display()));
let bindings = microcom_codegen::rust::generate(&parsed, &Default::default())
.unwrap_or_else(|e| panic!("{}: {e}", idl_path.display()));
let generated = PathBuf::from(env::var_os("OUT_DIR").expect("OUT_DIR")).join("windows_ink.rs");
if fs::read_to_string(&generated).is_ok_and(|existing| existing == bindings) {
return;
}
fs::write(&generated, bindings).unwrap_or_else(|e| panic!("{}: {e}", generated.display()));
}