f81d6f09af
- Previously, there were two ways of generating manual pages. We used to use the upstream clap_mangen crate, but decided to develop our own custom formatter. However, we didn't quite switch to it, keeping the old mechanism in place and adding our new solution to sq, activated by a hidden environment variable. - This patch drops the upstream formatter, and uses the custom formatter during build time. First, our custom code can be tweaked easily to suit our needs, and switching back to the upstream solution is easy enough should it better suit our needs. Second, generating manual pages at build time should help cross-building environments.
128 lines
3.4 KiB
Rust
128 lines
3.4 KiB
Rust
use std::env;
|
|
use std::fs;
|
|
use std::io::Write;
|
|
use std::path::PathBuf;
|
|
use clap::ValueEnum;
|
|
use clap_complete::Shell;
|
|
use anyhow::{Context, Result};
|
|
|
|
pub mod cli {
|
|
#![allow(unused_macros)]
|
|
include!("src/macros.rs");
|
|
include!("src/cli/mod.rs");
|
|
}
|
|
|
|
pub mod man {
|
|
include!("src/man.rs");
|
|
}
|
|
|
|
fn main() {
|
|
println!("cargo:rerun-if-changed=build.rs");
|
|
|
|
// Generate subplot tests.
|
|
#[cfg(feature = "subplot")]
|
|
subplot_build::codegen("sq.subplot")
|
|
.expect("failed to generate code with Subplot");
|
|
|
|
let mut sq = cli::build();
|
|
generate_sq_usage_md(&sq).unwrap();
|
|
generate_shell_completions(&mut sq).unwrap();
|
|
generate_man_pages(&sq).unwrap();
|
|
}
|
|
|
|
/// Generates shell completions.
|
|
fn generate_shell_completions(sq: &mut clap::Command) -> Result<()> {
|
|
let outdir: PathBuf =
|
|
env::var_os("OUT_DIR").expect("OUT_DIR not set").into();
|
|
assert!(outdir.is_dir());
|
|
let path = outdir.join("shell-completions");
|
|
fs::create_dir_all(&path)?;
|
|
|
|
for shell in Shell::value_variants() {
|
|
clap_complete::generate_to(*shell, sq, "sq", &path)?;
|
|
};
|
|
|
|
println!("cargo:warning=shell completions written to {}", path.display());
|
|
Ok(())
|
|
}
|
|
|
|
/// Dump help output of all commands and subcommands, for inclusion in
|
|
/// the top-level documentation.
|
|
fn generate_sq_usage_md(cmd: &clap::Command) -> Result<()> {
|
|
let mut cmd = cmd.clone().term_width(80);
|
|
cmd.build();
|
|
let outdir: PathBuf =
|
|
env::var_os("OUT_DIR").expect("OUT_DIR not set").into();
|
|
assert!(outdir.is_dir());
|
|
let path = outdir.join("sq-usage.md");
|
|
|
|
let mut sink = fs::File::create(&path)
|
|
.with_context(|| format!("trying to create {}", path.display()))?;
|
|
|
|
dump_help_inner(&mut sink, &mut cmd, "##")
|
|
}
|
|
|
|
fn dump_help_inner(
|
|
sink: &mut dyn Write,
|
|
cmd: &mut clap::Command,
|
|
heading: &str,
|
|
) -> Result<()> {
|
|
writeln!(sink)?;
|
|
|
|
let mut buffer = Vec::new();
|
|
let _ = cmd.write_long_help(&mut buffer);
|
|
let help = std::str::from_utf8(buffer.as_slice())?;
|
|
|
|
let mut verbatim = false;
|
|
for line in help.trim_end().split('\n').skip(1) {
|
|
if ! verbatim && line.starts_with("Usage:") {
|
|
writeln!(sink, "```text")?;
|
|
verbatim = true;
|
|
}
|
|
|
|
if line.is_empty() {
|
|
writeln!(sink)?;
|
|
} else {
|
|
writeln!(sink, "{}", line.trim_end())?;
|
|
}
|
|
}
|
|
if verbatim {
|
|
writeln!(sink, "```")?;
|
|
}
|
|
|
|
// Recurse.
|
|
for subcommand in cmd
|
|
.get_subcommands_mut()
|
|
.filter(|sc| sc.get_name() != "help")
|
|
{
|
|
writeln!(sink)?;
|
|
let heading_name = subcommand
|
|
// cmd.build() in dump_help makes sure every subcommand has a display_name
|
|
.get_display_name()
|
|
.unwrap()
|
|
.replace('-', " ");
|
|
writeln!(sink, "{} Subcommand {}", heading, heading_name)?;
|
|
|
|
dump_help_inner(sink, subcommand, &format!("{}#", heading))?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Generates man pages.
|
|
fn generate_man_pages(sq: &clap::Command) -> Result<()> {
|
|
let outdir: PathBuf =
|
|
env::var_os("OUT_DIR").expect("OUT_DIR not set").into();
|
|
assert!(outdir.is_dir());
|
|
let path = outdir.join("man-pages");
|
|
fs::create_dir_all(&path)?;
|
|
|
|
for man in man::manpages(sq) {
|
|
std::fs::write(path.join(man.filename()), man.troff_source())?;
|
|
}
|
|
|
|
println!("cargo:warning=man pages written to {}", path.display());
|
|
|
|
Ok(())
|
|
}
|