use std::path::{Path, PathBuf}; use anyhow::{Context, anyhow}; fn generate(generate: F) -> anyhow::Result where F: FnOnce() -> anyhow::Result + Send + 'static, { std::thread::Builder::new() .stack_size(256 * 1024 * 1024) .spawn(generate) .context("spawn generator thread")? .join() .map_err(|_| anyhow!("openapi generation panicked (stack overflow?)"))? } fn check_file(path: &Path, json: &str) -> anyhow::Result<()> { let existing = std::fs::read_to_string(path).with_context(|| format!("reading {}", path.display()))?; if existing.trim_end() != json.trim_end() { eprintln!( "{} is out of date; run `cargo run -p openapi` to regenerate", path.display() ); std::process::exit(1); } Ok(()) } fn main() -> anyhow::Result<()> { let web = generate(|| { let doc = webapi::openapi::api_doc(); doc.to_pretty_json().context("serializing web openapi doc") })?; let crate_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let root = crate_dir .ancestors() .nth(2) .ok_or_else(|| anyhow!("workspace root not found above {}", crate_dir.display()))?; let web_path = root.join("openapi.json"); let check = std::env::args().nth(1).as_deref() == Some("--check"); if check { check_file(&web_path, &web)?; println!("openapi.json is up to date"); return Ok(()); } std::fs::write(&web_path, web).with_context(|| format!("writing {}", web_path.display()))?; println!("wrote {}", web_path.display()); Ok(()) }