use std::path::Path;
const SHIPPED: [&str; 3] = ["adapters", "base", "editors"];
fn variant(dir: &str) -> String {
let mut c = dir.chars();
match c.next() {
Some(first) => first.to_ascii_uppercase().to_string() + c.as_str(),
None => unreachable!("SHIPPED holds no empty names"),
}
}
fn main() {
let manifest = std::env::var("CARGO_MANIFEST_DIR").expect("cargo sets this");
let out = std::env::var("OUT_DIR").expect("cargo sets this");
let mut variants = String::new();
let mut all = String::new();
let mut dir_arms = String::new();
let mut file_arms = String::new();
for kind in SHIPPED {
let dir = Path::new(&manifest).join(kind);
let name = variant(kind);
println!("cargo:rerun-if-changed={}", dir.display());
let listing = std::fs::read_dir(&dir)
.unwrap_or_else(|e| panic!("omh ships {kind}/, and it is unreadable: {e}"));
let mut files: Vec<_> = listing
.map(|e| {
e.unwrap_or_else(|err| {
panic!("omh ships {kind}/, and an entry is unreadable: {err}")
})
.path()
})
.filter(|p| p.extension().is_some_and(|x| x == "toml"))
.collect();
files.sort();
assert!(
!files.is_empty(),
"{kind}/ holds no .toml — that would build an omh that installs nothing"
);
variants.push_str(&format!(" {name},\n"));
all.push_str(&format!("Shipped::{name}, "));
dir_arms.push_str(&format!(" Shipped::{name} => {kind:?},\n"));
file_arms.push_str(&format!(" Shipped::{name} => &[\n"));
for file in files {
let file_name = file
.file_name()
.expect("a path from read_dir has a final component")
.to_str()
.unwrap_or_else(|| panic!("{}: file names omh ships must be UTF-8", file.display()))
.to_owned();
let path = file.to_str().unwrap_or_else(|| {
panic!(
"{}: the path to a shipped file must be UTF-8",
file.display()
)
});
println!("cargo:rerun-if-changed={path}");
file_arms.push_str(&format!(
" File {{ name: {file_name:?}, contents: include_str!({path:?}) }},\n"
));
}
file_arms.push_str(" ],\n");
}
let count = SHIPPED.len();
let generated = format!(
"// Generated by build.rs. Edit the .toml files, not this.\n\
#[derive(Clone, Copy, Debug, PartialEq, Eq)]\n\
pub enum Shipped {{\n{variants}}}\n\
\n\
/// Every directory omh ships, so nothing can iterate a stale subset.\n\
/// Only the tests walk all three; production names the one it wants.\n\
#[cfg_attr(not(test), allow(dead_code))]\n\
pub const ALL: [Shipped; {count}] = [{all}];\n\
\n\
impl Shipped {{\n\
\x20 /// The directory name, in this repo and under `~/.omh`.\n\
\x20 pub fn dir(self) -> &'static str {{\n\
\x20 match self {{\n{dir_arms}\x20 }}\n\
\x20 }}\n\
\n\
\x20 /// What omh installs for this directory. Never empty: build.rs\n\
\x20 /// refuses to emit an empty one.\n\
\x20 pub fn files(self) -> &'static [File] {{\n\
\x20 match self {{\n{file_arms}\x20 }}\n\
\x20 }}\n\
}}\n"
);
std::fs::write(Path::new(&out).join("bundled.rs"), generated)
.expect("writing the generated table");
}