pubhubs/cli/doc.rs
1use std::ffi::OsString;
2
3use anyhow::{Result, ensure};
4
5#[derive(clap::Args, Debug)]
6pub struct DocArgs {
7 /// Arguments forwarded to `cargo doc` (e.g. `--open`, `--document-private-items`, `--no-deps`).
8 #[arg(trailing_var_arg = true, allow_hyphen_values = true)]
9 cargo_args: Vec<OsString>,
10}
11
12impl DocArgs {
13 pub fn run(self, _spec: &mut clap::Command) -> Result<()> {
14 let manifest = env!("CARGO_MANIFEST_DIR");
15 let katex_hdr = format!("{manifest}/docs/assets/rustdoc-include-katex-header.html");
16
17 let mut cmd = std::process::Command::new(env!("CARGO"));
18 cmd.current_dir(manifest)
19 .arg("doc")
20 .args(&self.cargo_args)
21 .env("RUSTDOCFLAGS", format!("--html-in-header {katex_hdr}"));
22
23 // We might be spawned by `cargo run`, which sets some CARGO_... environment variables that
24 // would, by default, be inherited by the `cargo doc` we spawn. They're absent for a plain
25 // top-level `cargo`, so leaking them in makes any build script that tracks one recompile on
26 // every run — e.g. ring tracks CARGO_MANIFEST_DIR, see
27 // https://github.com/rust-lang/cargo/issues/16134. Cargo overwrites them unconditionally, so
28 // dropping them can never clobber a user-set value. We strip only these package-identity
29 // vars, not config-input ones the user may have set on purpose.
30 for (key, _) in std::env::vars_os() {
31 if key
32 .to_str()
33 .is_some_and(|k| k.starts_with("CARGO_PKG_") || k.starts_with("CARGO_MANIFEST_"))
34 {
35 cmd.env_remove(&key);
36 }
37 }
38
39 let status = cmd.status()?;
40 ensure!(status.success(), "cargo doc exited with {status}");
41 Ok(())
42 }
43}