summaryrefslogtreecommitdiffstats
path: root/src/tools/cargo/crates/xtask-build-man/src/main.rs
blob: 2ab3f098aaa474785badd7f60c9fcba64ae55a7c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
//! ```text
//! NAME
//!         build-man
//!
//! SYNOPSIS
//!         build-man
//!
//! DESCRIPTION
//!         Build the man pages for packages `mdman` and `cargo`.
//!         For more, read their doc comments.
//! ```

#![allow(clippy::print_stderr)]

use std::fs;
use std::io;
use std::path::PathBuf;
use std::process;
use std::process::Command;

fn main() -> io::Result<()> {
    build_mdman()?;
    build_cargo()?;
    Ok(())
}

/// Builds the man pages for `mdman`.
fn build_mdman() -> io::Result<()> {
    cwd_to_workspace_root()?;

    let src_paths = &["crates/mdman/doc/mdman.md".into()];
    let dst_path = "crates/mdman/doc/out";
    let outs = [("md", dst_path), ("txt", dst_path), ("man", dst_path)];

    build_man("mdman", src_paths, &outs, &[])
}

/// Builds the man pages for Cargo.
///
/// The source for the man pages are located in src/doc/man/ in markdown format.
/// These also are handlebars templates, see crates/mdman/README.md for details.
///
/// The generated man pages are placed in the src/etc/man/ directory. The pages
/// are also expanded into markdown (after being expanded by handlebars) and
/// saved in the src/doc/src/commands/ directory. These are included in the
/// Cargo book, which is converted to HTML by mdbook.
fn build_cargo() -> io::Result<()> {
    // Find all `src/doc/man/cargo-*.md`
    let src_paths = {
        let mut src_paths = Vec::new();
        for entry in fs::read_dir("src/doc/man")? {
            let entry = entry?;
            let file_name = entry.file_name();
            let file_name = file_name.to_str().unwrap();
            if file_name.starts_with("cargo-") && file_name.ends_with(".md") {
                src_paths.push(entry.path());
            }
        }
        src_paths
    };
    let outs = [
        ("md", "src/doc/src/commands"),
        ("txt", "src/doc/man/generated_txt"),
        ("man", "src/etc/man"),
    ];
    let args = [
        "--url",
        "https://doc.rust-lang.org/cargo/commands/",
        "--man",
        "rustc:1=https://doc.rust-lang.org/rustc/index.html",
        "--man",
        "rustdoc:1=https://doc.rust-lang.org/rustdoc/index.html",
    ];
    build_man("cargo", &src_paths[..], &outs, &args)
}

/// Change to workspace root.
///
/// Assumed this xtask is located in `[WORKSPACE]/crates/xtask-build-man`.
fn cwd_to_workspace_root() -> io::Result<()> {
    let pkg_root = std::env!("CARGO_MANIFEST_DIR");
    let ws_root = format!("{pkg_root}/../..");
    std::env::set_current_dir(ws_root)
}

/// Builds the man pages.
fn build_man(
    pkg_name: &str,
    src_paths: &[PathBuf],
    outs: &[(&str, &str)],
    extra_args: &[&str],
) -> io::Result<()> {
    for (format, dst_path) in outs {
        eprintln!("Start converting `{format}` for package `{pkg_name}`...");
        let mut cmd = Command::new(std::env!("CARGO"));
        cmd.args(["run", "--package", "mdman", "--"])
            .args(["-t", format, "-o", dst_path])
            .args(src_paths)
            .args(extra_args);

        let status = cmd.status()?;
        if !status.success() {
            eprintln!("failed to build the man pages for package `{pkg_name}`");
            eprintln!("failed command: `{cmd:?}`");
            process::exit(status.code().unwrap_or(1));
        }
    }

    Ok(())
}