Просмотр исходного кода

xtask: remove assumptions from docs command

This slightly changes the site layout: crate documentation is now flat
rather than being nested under "user" and  "bpf".

- Run `cargo clean --doc` before generating docs to ensure hermiticity.
- Generate header.html into a temporary directory.
- Remove "site" on each run to ensure hermiticity.
- Invoke cargo only once.
- Avoid editing sources.
Tamir Duberstein 1 год назад
Родитель
Сommit
b86d42d1b0
4 измененных файлов с 76 добавлено и 86 удалено
  1. 0 1
      .gitignore
  2. 0 2
      bpf/.cargo/config.toml
  3. 1 0
      xtask/Cargo.toml
  4. 75 83
      xtask/src/docs/mod.rs

+ 0 - 1
.gitignore

@@ -3,5 +3,4 @@ target/
 .vscode/
 !.vscode/settings.json
 site/
-header.html
 .idea/

+ 0 - 2
bpf/.cargo/config.toml

@@ -5,8 +5,6 @@
 # NB: this file gets loaded only if you run cargo from this directory, it's
 # ignored if you run from the workspace root. See
 # https://doc.rust-lang.org/cargo/reference/config.html#hierarchical-structure
-#
-# NB-2: cargo xtask docs currently relies on this file existing.
 [build]
 target = "bpfel-unknown-none"
 

+ 1 - 0
xtask/Cargo.toml

@@ -13,3 +13,4 @@ indoc = "2.0"
 proc-macro2 = "1"
 quote = "1"
 syn = "2"
+tempfile = "3"

+ 75 - 83
xtask/src/docs/mod.rs

@@ -1,12 +1,7 @@
 use anyhow::{anyhow, Context as _, Result};
-use std::{
-    path::{Path, PathBuf},
-    process::Command,
-};
-
-use std::{fs, io, io::Write};
-
-use indoc::indoc;
+use cargo_metadata::{Metadata, MetadataCommand};
+use indoc::{indoc, writedoc};
+use std::{ffi::OsString, fs, io::Write as _, process::Command};
 
 pub fn exec(cmd: &mut Command) -> Result<()> {
     let status = cmd
@@ -22,95 +17,92 @@ pub fn exec(cmd: &mut Command) -> Result<()> {
 }
 
 pub fn docs() -> Result<()> {
-    let current_dir = PathBuf::from(".");
-    let header_path = current_dir.join("header.html");
-    let mut header = fs::File::create(&header_path).expect("can't create header.html");
-    header
-        .write_all(r#"<meta name="robots" content="noindex">"#.as_bytes())
-        .expect("can't write header.html contents");
-    header.flush().expect("couldn't flush contents");
-    let abs_header_path = fs::canonicalize(&header_path).unwrap();
+    const PACKAGE_TO_DESCRIPTION: &[(&str, &str)] =
+        &[("aya", "User-space"), ("aya-bpf", "Kernel-space")];
+
+    let Metadata {
+        workspace_root,
+        target_directory,
+        ..
+    } = MetadataCommand::new().exec().context("cargo metadata")?;
+
+    exec(
+        Command::new("cargo")
+            .current_dir(&workspace_root)
+            .args(["clean", "--doc"]),
+    )?;
+
+    let tmp = tempfile::tempdir().context("create tempdir")?;
+    let header = tmp.path().join("header.html");
+    fs::write(&header, r#"<meta name="robots" content="noindex">"#).context("write header.html")?;
+
+    let mut rustdocflags = OsString::new();
+    rustdocflags.push("--cfg docsrs --html-in-header ");
+    rustdocflags.push(header);
+    rustdocflags.push(" -D warnings");
 
-    build_docs(&current_dir.join("aya"), &abs_header_path)?;
-    build_docs(&current_dir.join("bpf/aya-bpf"), &abs_header_path)?;
-    copy_dir_all("./target/doc".as_ref(), "./site/user".as_ref())?;
-    copy_dir_all(
-        "./target/bpfel-unknown-none/doc".as_ref(),
-        "./site/bpf".as_ref(),
+    exec(
+        Command::new("cargo")
+            .current_dir(&workspace_root)
+            .env("RUSTDOCFLAGS", rustdocflags)
+            .args(["+nightly", "doc", "--no-deps", "--all-features"])
+            .args(
+                PACKAGE_TO_DESCRIPTION
+                    .iter()
+                    .flat_map(|(package, _)| ["--package", package]),
+            ),
     )?;
 
-    let mut robots = fs::File::create("site/robots.txt").expect("can't create robots.txt");
-    robots
-        .write_all(
-            indoc! {r#"
+    let site = workspace_root.join("site");
+    match fs::remove_dir_all(&site) {
+        Ok(()) => {}
+        Err(err) => {
+            if err.kind() != std::io::ErrorKind::NotFound {
+                return Err(err).context(format!("remove {site:?}"));
+            }
+        }
+    }
+    let doc = target_directory.join("doc");
+    fs::rename(&doc, &site).with_context(|| format!("rename {doc:?} to {site:?}"))?;
+
+    exec(Command::new("sh").current_dir(&site).args([
+        "-c",
+        "grep -FRl crabby.svg | xargs sed -i s/crabby.svg/crabby_dev.svg/g",
+    ]))?;
+
+    fs::write(
+        site.join("robots.txt"),
+        indoc! {r#"
     User-Agent:*
     Disallow: /
-    "#}
-            .as_bytes(),
-        )
-        .expect("can't write robots.txt");
+    "#},
+    )
+    .context("can't write robots.txt")?;
 
-    let mut index = fs::File::create("site/index.html").expect("can't create index.html");
-    index
-        .write_all(
-            indoc! {r#"
+    let mut index = fs::File::create(site.join("index.html"))
+        .with_context(|| format!("create {site:?}/index.html"))?;
+    writedoc! {&mut index, r#"
         <html>
             <meta name="robots" content="noindex">
             <body>
               <ul>
-                <li><a href="user/aya/index.html">Aya User-space Development Documentation</a></li>
-                <li><a href="bpf/aya_bpf/index.html">Aya Kernel-space Development Documentation</a></li>
+    "#}
+    .context("write to index.html")?;
+
+    for (package, description) in PACKAGE_TO_DESCRIPTION {
+        let package = package.replace('-', "_");
+        writedoc! {&mut index, r#"
+            <li><a href="{package}/index.html">Aya {description} Development Documentation</a></li>
+        "#}
+        .context("write to string")?;
+    }
+
+    writedoc! {&mut index, r#"
               </ul>
             </body>
         </html>
     "#}
-            .as_bytes(),
-        )
-        .expect("can't write index.html");
-    Ok(())
-}
-
-fn build_docs(working_dir: &Path, abs_header_path: &Path) -> Result<()> {
-    exec(Command::new("sed").current_dir(working_dir).args([
-        "-i.bak",
-        "s/crabby.svg/crabby_dev.svg/",
-        "src/lib.rs",
-    ]))?;
+    .context("write to index.html")?;
 
-    exec(
-        Command::new("cargo")
-            .current_dir(working_dir)
-            .env(
-                "RUSTDOCFLAGS",
-                format!(
-                    "--cfg docsrs --html-in-header {} -D warnings",
-                    abs_header_path.to_str().unwrap()
-                ),
-            )
-            .args(["+nightly", "doc", "--no-deps", "--all-features"]),
-    )?;
-
-    fs::rename(
-        working_dir.join("src/lib.rs.bak"),
-        working_dir.join("src/lib.rs"),
-    )
-    .context("Failed to rename lib.rs.bak to lib.rs")
-}
-
-fn copy_dir_all(src: &Path, dst: &Path) -> io::Result<()> {
-    fs::create_dir_all(dst)?;
-    for entry in fs::read_dir(src)? {
-        let entry = entry?;
-        let ty = entry.file_type()?;
-        let src = entry.path();
-        let src = src.as_path();
-        let dst = dst.join(entry.file_name());
-        let dst = dst.as_path();
-        if ty.is_dir() {
-            copy_dir_all(src, dst)?;
-        } else if !dst.exists() {
-            fs::copy(src, dst)?;
-        }
-    }
     Ok(())
 }