use std::path::Path;
use anyhow::{anyhow, Context, Result};
use crate::bench::BenchRun;
pub const GENERATED_MARKER: &str = "<!-- nornir:generated -->";
pub mod sections;
pub use sections::{assemble_file, check_file, Ctx, FileReport};
pub mod test_inventory;
pub use test_inventory::{scan as scan_tests, scan_opts as scan_tests_opts, TestInventory};
pub mod layout;
pub use layout::{
check_all as render_check_all, check_doc as render_check_doc, init_repo,
render_all, render_doc, RenderReport, RepoLayout, MANAGED_DOCS,
};
pub mod warehouse;
pub use warehouse::{
list_doc_exports, list_doc_exports_async, record_doc_export, record_doc_export_async,
DocExport, ExportFilter,
};
pub mod search;
pub use search::{
build_docs_index, discover_doc_files, docs_index_dir, restore_docs_index, search_docs,
snapshot_docs_index,
};
#[cfg(feature = "docs-export")]
pub mod export;
#[cfg(feature = "docs-export")]
pub use export::{export as export_bytes, export_repo, DocFormat, ExportMeta};
#[cfg(feature = "docs-export")]
pub mod svg;
#[cfg(feature = "docs-export")]
pub mod release_book;
#[cfg(feature = "docs-export")]
pub use release_book::{BookOptions, build_release_book, build_release_book_markdown};
#[cfg(feature = "docs-export")]
pub mod book;
#[cfg(feature = "docs-export")]
pub use book::{build_book, collect_chapters, resolve_version, Chapter};
pub fn render_readme(repo_name: &str, description: &str, run: &BenchRun) -> String {
let best = best_metric(run);
let mut out = String::new();
out.push_str(&format!("# {repo_name}\n\n"));
out.push_str(description.trim());
out.push_str("\n\n");
out.push_str(&format!(
"**{best:.0} ops/sec · {cores} cores · v{ver}**\n\n",
cores = run.cores,
ver = run.version
));
out.push_str("## Current benchmarks\n\n");
out.push_str("| name | metric | value |\n|------|--------|-------|\n");
for r in &run.results {
for (k, v) in &r.metrics {
if let Some(f) = v.as_f64() {
out.push_str(&format!("| {} | {} | {:.2} |\n", r.name, k, f));
}
}
}
out.push_str("\n");
out.push_str(GENERATED_MARKER);
out.push('\n');
out
}
pub fn write_readme(repo_root: &Path, body: &str) -> Result<()> {
let path = repo_root.join("README.md");
std::fs::write(&path, body).with_context(|| format!("write {}", path.display()))?;
Ok(())
}
pub fn append_changelog(repo_root: &Path, version: &str, date: &str, summary: &str) -> Result<()> {
let path = repo_root.join("CHANGELOG.md");
let prior = std::fs::read_to_string(&path).unwrap_or_default();
let entry = format!("## v{version} — {date}\n\n{}\n\n", summary.trim());
let new = if prior.starts_with("# ") {
let (head, rest) = prior.split_once('\n').unwrap_or((&prior, ""));
format!("{head}\n\n{entry}{rest}")
} else {
format!("# Changelog\n\n{entry}{prior}")
};
std::fs::write(&path, new).with_context(|| format!("write {}", path.display()))?;
Ok(())
}
pub fn assemble_and_check(repo_root: &Path, run: &BenchRun) -> Result<()> {
let readme = repo_root.join("README.md");
let text = std::fs::read_to_string(&readme).unwrap_or_default();
if text.contains(GENERATED_MARKER) {
return Ok(());
}
let needle = format!("v{}", run.version);
if !text.contains(&needle) {
return Err(anyhow!(
"README.md does not mention {needle} — update headline before release"
));
}
Ok(())
}
fn best_metric(run: &BenchRun) -> f64 {
let mut best = 0.0f64;
for r in &run.results {
for (_, v) in &r.metrics {
if let Some(f) = v.as_f64() {
if f > best {
best = f;
}
}
}
}
best
}