use std::env;
use std::fs;
use std::path::PathBuf;
fn main() {
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let plugins_dir = manifest_dir.join("plugins");
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
let out_file = out_dir.join("embedded_catalog.toml");
println!("cargo:rerun-if-changed=plugins");
let index_path = plugins_dir.join("_index.toml");
let index_text = fs::read_to_string(&index_path)
.unwrap_or_else(|e| panic!("could not read {}: {e}", index_path.display()));
let catalog_version = parse_catalog_version(&index_text)
.expect("plugins/_index.toml must declare `catalog_version`");
let plugin_names = parse_plugins_list(&index_text)
.expect("plugins/_index.toml must declare `plugins = [...]`");
let mut buf = String::new();
buf.push_str("# Generated by build.rs from plugins/*.toml. Edit those.\n");
buf.push_str(&format!("catalog_version = {catalog_version}\n\n"));
for name in &plugin_names {
let path = plugins_dir.join(format!("{name}.toml"));
let body = fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("could not read {}: {e}", path.display()));
buf.push_str(&format!("# ---- plugin: {name} ----\n\n"));
buf.push_str(&body);
if !body.ends_with('\n') {
buf.push('\n');
}
buf.push('\n');
}
fs::write(&out_file, buf)
.unwrap_or_else(|e| panic!("could not write {}: {e}", out_file.display()));
}
fn parse_catalog_version(text: &str) -> Option<u32> {
for line in text.lines() {
let trimmed = line.trim();
if trimmed.starts_with('#') {
continue;
}
let rest = trimmed.strip_prefix("catalog_version")?;
let rest = rest.trim_start();
let rest = rest.strip_prefix('=')?.trim_start();
let value = rest.split('#').next()?.trim();
return value.parse::<u32>().ok();
}
None
}
fn parse_plugins_list(text: &str) -> Option<Vec<String>> {
let start = text.find("plugins")?;
let after_key = &text[start..];
let bracket_open = after_key.find('[')?;
let bracket_close = after_key.find(']')?;
if bracket_close <= bracket_open {
return None;
}
let body = &after_key[bracket_open + 1..bracket_close];
let names: Vec<String> = body
.split(',')
.filter_map(|part| {
let trimmed = part.trim().trim_matches('"');
if trimmed.is_empty() {
None
} else {
Some(trimmed.to_string())
}
})
.collect();
if names.is_empty() { None } else { Some(names) }
}