rustdoc_wrapper/
main.rs

1//! A helper binary for invoking rustdoc
2
3use std::process::Stdio;
4
5use camino::Utf8PathBuf;
6use clap::Parser;
7
8/// Simple program to greet a person
9#[derive(Parser, Debug)]
10#[command(version, about, long_about = None)]
11struct Args {
12    #[arg(long)]
13    json_out: Option<Utf8PathBuf>,
14
15    #[arg(long)]
16    test_out: Option<Utf8PathBuf>,
17
18    #[arg(long)]
19    rustdoc: Utf8PathBuf,
20
21    #[arg(trailing_var_arg = true, allow_hyphen_values = true, hide = true)]
22    rustdoc_args: Vec<String>,
23}
24
25fn json_mode(args: Args) {
26    let mut cmd = std::process::Command::new(args.rustdoc);
27    cmd.args(args.rustdoc_args);
28    let json_out_dir = camino_tempfile::tempdir().expect("unable to create tmp dir");
29    cmd.arg("--out-dir").arg(json_out_dir.path());
30
31    let status = cmd.status().expect("failed to run");
32    if !status.success() {
33        std::process::exit(status.code().unwrap_or(127))
34    }
35
36    let json_out = args.json_out.unwrap();
37    let dir = std::fs::read_dir(json_out_dir.path()).expect("read dir failed");
38    let items: Result<Vec<_>, _> = dir.collect();
39    let items = items.expect("failed to read dir");
40    if items.len() != 1 {
41        panic!("expected exactly 1 file in output dir found: {}", items.len());
42    }
43
44    let filetype = items[0].file_type().expect("failed to read filetype");
45    if !filetype.is_file() {
46        panic!("json output is not file");
47    }
48
49    std::fs::copy(items[0].path(), json_out).expect("failed to copy output");
50}
51
52fn html_mode(args: Args) {
53    let mut cmd = std::process::Command::new(args.rustdoc);
54    cmd.args(args.rustdoc_args);
55    let status = cmd.status().expect("failed to run");
56    if !status.success() {
57        std::process::exit(status.code().unwrap_or(127))
58    }
59}
60
61fn test_mode(args: Args) {
62    let mut cmd = std::process::Command::new(args.rustdoc);
63    cmd.args(args.rustdoc_args);
64    cmd.arg("--output-format=doctest");
65    cmd.stderr(Stdio::inherit());
66    cmd.stdout(Stdio::piped());
67
68    let output = cmd.output().expect("failed to run");
69    if !output.status.success() {
70        std::process::exit(output.status.code().unwrap_or(127))
71    }
72
73    std::fs::write(args.test_out.unwrap(), output.stdout).expect("failed to write doctest output")
74}
75
76fn main() {
77    let args = Args::parse();
78
79    match (args.json_out.is_some(), args.test_out.is_some()) {
80        (true, false) => json_mode(args),
81        (false, true) => test_mode(args),
82        (false, false) => html_mode(args),
83        (true, true) => panic!("cannot specify both --test-out and --json-out"),
84    }
85}