use crate::error::CliError;
use clap::CommandFactory;
use std::fs;
use std::path::PathBuf;
use crate::Cli;
pub fn run(out: PathBuf) -> Result<u8, CliError> {
fs::create_dir_all(&out).map_err(|e| CliError::BadArg(format!("mkdir {out:?}: {e}")))?;
clap_mangen::generate_to(Cli::command(), &out)
.map_err(|e| CliError::BadArg(format!("gen-man write to {out:?}: {e}")))?;
Ok(0)
}
#[cfg(test)]
mod tests {
use super::*;
use clap::Command;
use std::collections::BTreeSet;
fn expected_pages(cmd: &Command, prefix: &str, acc: &mut BTreeSet<String>) {
let stem = if prefix.is_empty() {
cmd.get_name().to_string()
} else {
format!("{prefix}-{}", cmd.get_name())
};
acc.insert(format!("{stem}.1"));
for sub in cmd.get_subcommands() {
if sub.is_hide_set() || sub.get_name() == "help" {
continue;
}
expected_pages(sub, &stem, acc);
}
}
#[test]
fn gen_man_exact_page_set_walk() {
let dir = tempfile::tempdir().unwrap();
run(dir.path().to_path_buf()).unwrap();
let produced: BTreeSet<String> = std::fs::read_dir(dir.path())
.unwrap()
.map(|e| e.unwrap().file_name().into_string().unwrap())
.filter(|n| n.ends_with(".1"))
.collect();
let root = Cli::command();
let mut expected = BTreeSet::new();
expected_pages(&root, "", &mut expected);
assert_eq!(
produced, expected,
"produced man-page set must exactly equal the walked unbuilt tree"
);
assert!(produced.contains("md.1"), "root md.1 missing: {produced:?}");
assert!(
produced.contains("md-gen-man.1"),
"md-gen-man.1 missing: {produced:?}"
);
assert!(!produced.is_empty(), "produced set is empty");
}
#[test]
fn gen_man_negative_canary_no_help_pages() {
let dir = tempfile::tempdir().unwrap();
run(dir.path().to_path_buf()).unwrap();
for entry in std::fs::read_dir(dir.path()).unwrap() {
let name = entry.unwrap().file_name().into_string().unwrap();
assert!(
!(name == "md-help.1" || name.contains("-help-") || name.ends_with("-help.1")),
"spurious help shadow page produced (accidental pre-build?): {name}"
);
}
}
#[test]
fn gen_man_root_page_has_th_header_and_distinct_filenames() {
let dir = tempfile::tempdir().unwrap();
run(dir.path().to_path_buf()).unwrap();
let root = std::fs::read_to_string(dir.path().join("md.1")).unwrap();
assert!(
root.contains(".TH"),
"root md.1 missing roff .TH header:\n{}",
&root[..root.len().min(200)]
);
let raw: Vec<String> = std::fs::read_dir(dir.path())
.unwrap()
.map(|e| e.unwrap().file_name().into_string().unwrap())
.filter(|n| n.ends_with(".1"))
.collect();
let distinct: BTreeSet<&String> = raw.iter().collect();
assert_eq!(raw.len(), distinct.len(), "duplicate page filenames");
for n in &raw {
let bytes = std::fs::read(dir.path().join(n)).unwrap();
assert!(!bytes.is_empty(), "page {n} is empty");
}
}
}