1use std::process::Stdio;
4
5use camino::Utf8PathBuf;
6use clap::Parser;
7
8#[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}