use std::collections::HashMap; use std::fmt::{self, Write}; use std::path::{Path, PathBuf}; use std::{env, fs}; use glob::glob; #[derive(Debug, Default)] struct Level { nested: HashMap, files: Vec, } fn main() { let home = env::var("CARGO_MANIFEST_DIR").unwrap(); let pattern = format!("{home}/../../website/docs/**/*.md*"); let base = format!("{home}/../../website"); let base = Path::new(&base).canonicalize().unwrap(); let dir_pattern = format!("{home}/../../website/docs/**"); for dir in glob(&dir_pattern).unwrap() { println!("cargo:rerun-if-changed={}", dir.unwrap().display()); } let mut level = Level::default(); for entry in glob(&pattern).unwrap() { let path = entry.unwrap(); let path = Path::new(&path).canonicalize().unwrap(); println!("cargo:rerun-if-changed={}", path.display()); let rel = path.strip_prefix(&base).unwrap(); let mut parts = vec![]; for part in rel { parts.push(part.to_str().unwrap()); } level.insert(path.clone(), &parts[..]); } let out = format!("{}/website_tests.rs", env::var("OUT_DIR").unwrap()); fs::write(out, level.to_contents()).unwrap(); } impl Level { fn insert(&mut self, path: PathBuf, rel: &[&str]) { if rel.len() == 1 { self.files.push(path); } else { let nested = self.nested.entry(rel[0].to_string()).or_default(); nested.insert(path, &rel[1..]); } } fn to_contents(&self) -> String { let mut dst = String::new(); self.write_inner(&mut dst, 0).unwrap(); dst } fn write_into(&self, dst: &mut String, name: &str, level: usize) -> fmt::Result { self.write_space(dst, level); let name = name.replace(['-', '.'], "_"); writeln!(dst, "pub mod {name} {{")?; self.write_inner(dst, level + 1)?; self.write_space(dst, level); writeln!(dst, "}}")?; Ok(()) } fn write_inner(&self, dst: &mut String, level: usize) -> fmt::Result { for (name, nested) in &self.nested { nested.write_into(dst, name, level)?; } self.write_space(dst, level); for file in &self.files { let stem = Path::new(file) .file_stem() .unwrap() .to_str() .unwrap() .replace('-', "_"); self.write_space(dst, level); writeln!(dst, "#[doc = include_str!(r\"{}\")]", file.display())?; self.write_space(dst, level); writeln!(dst, "pub fn {stem}_md() {{}}")?; } Ok(()) } fn write_space(&self, dst: &mut String, level: usize) { for _ in 0..level { dst.push_str(" "); } } }