diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-07-17 11:32:37 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-07-17 11:33:33 +0800 |
| commit | f518904f236f417dcec2cbef10d9c778a017d31e (patch) | |
| tree | debeccdc722486787891e7ac4861579d77facc54 | |
| parent | 11e287e931f7fcda65708846a1cb9bc1cc05de13 (diff) | |
feat: add deploy-api-docs tool for building crate docs with docs.rs
features
| -rw-r--r-- | .gitignore | 7 | ||||
| -rw-r--r-- | .run/src/bin/deploy-api-docs.rs | 132 |
2 files changed, 137 insertions, 2 deletions
@@ -1,7 +1,10 @@ .temp -# Temp file for dev_tools/scripts/windows-folder-hide.ps1 -dev_tools/scripts/last_check +# Temp file for .run/src/bin/windows-folder-hide.ps1 +.run/src/bin/last_check + +# Temp file for .run/src/bin/deploy-api-docs.rs +docs/api-docs/ # Drafts __*.md diff --git a/.run/src/bin/deploy-api-docs.rs b/.run/src/bin/deploy-api-docs.rs new file mode 100644 index 0000000..ea52886 --- /dev/null +++ b/.run/src/bin/deploy-api-docs.rs @@ -0,0 +1,132 @@ +use std::path::Path; + +use tools::{println_cargo_style, run_cmd}; + +const DOCS_RS_MANIFEST: &str = "mingling/Cargo.toml"; +const OUTPUT_DIR: &str = "docs/api-docs"; + +fn main() { + let repo_root = find_git_repo().expect("Failed to find git repository root"); + + let manifest_path = repo_root.join(DOCS_RS_MANIFEST); + if !manifest_path.exists() { + eprintln!("Error: Manifest not found at {}", manifest_path.display()); + std::process::exit(1); + } + + // Read and parse [package.metadata.docs.rs] + let manifest_content = + std::fs::read_to_string(&manifest_path).expect("Failed to read Cargo.toml"); + let cargo_toml: toml::Value = manifest_content + .parse() + .expect("Failed to parse Cargo.toml"); + + let doc_features = cargo_toml + .get("package") + .and_then(|p| p.get("metadata")) + .and_then(|m| m.get("docs")) + .and_then(|d| d.get("rs")) + .and_then(|rs| rs.get("features")) + .and_then(|f| f.as_array()) + .unwrap_or_else(|| { + eprintln!("Error: [package.metadata.docs.rs] or its 'features' key not found in mingling/Cargo.toml"); + std::process::exit(1); + }); + + let features: Vec<&str> = doc_features.iter().filter_map(|v| v.as_str()).collect(); + + if features.is_empty() { + eprintln!("Error: No features defined in [package.metadata.docs.rs]"); + std::process::exit(1); + } + + let features_arg = features.join(","); + + // Ensure output directory exists + let output_path = repo_root.join(OUTPUT_DIR); + std::fs::create_dir_all(&output_path).expect("Failed to create output directory"); + + // Build cargo doc command + let cmd = format!( + "cargo doc --no-deps --features \"{}\" -p mingling --target-dir \"{}\" --color always", + features_arg, + output_path.join("target").to_string_lossy() + ); + + println_cargo_style!("Features: {}", features_arg); + println_cargo_style!("Output: {}", output_path.display()); + + // Run cargo doc, then copy generated docs to output directory + println_cargo_style!("Building: docs (cargo doc --no-deps)"); + run_cmd!(&cmd).unwrap_or_else(|code| { + eprintln!("Error: cargo doc failed with exit code {}", code); + std::process::exit(code); + }); + + // Copy generated docs from target/doc to OUTPUT_DIR (top level) + let doc_source = output_path.join("target").join("doc"); + let doc_dest = &output_path; + + if doc_source.exists() { + println_cargo_style!("Copying: docs to output directory"); + // Remove old docs in destination (except target/) + if let Ok(entries) = std::fs::read_dir(doc_dest) { + for entry in entries.flatten() { + let path = entry.path(); + if path.file_name().and_then(|n| n.to_str()) == Some("target") { + continue; + } + if path.is_dir() { + std::fs::remove_dir_all(&path).ok(); + } else { + std::fs::remove_file(&path).ok(); + } + } + } + copy_dir_recursively(&doc_source, doc_dest).expect("Failed to copy documentation"); + } + + // Clean up the intermediate target directory to save space + std::fs::remove_dir_all(output_path.join("target")).ok(); + + println_cargo_style!("Done: API docs deployed to {}", output_path.display()); +} + +fn copy_dir_recursively(src: &Path, dst: &Path) -> std::io::Result<()> { + if !dst.exists() { + std::fs::create_dir_all(dst)?; + } + + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let file_type = entry.file_type()?; + let src_path = entry.path(); + let file_name = src_path.file_name().expect("Failed to get file name"); + let dst_path = dst.join(file_name); + + if file_type.is_dir() { + copy_dir_recursively(&src_path, &dst_path)?; + } else { + std::fs::copy(&src_path, &dst_path)?; + } + } + + Ok(()) +} + +fn find_git_repo() -> Option<std::path::PathBuf> { + let mut current_dir = std::env::current_dir().ok()?; + + loop { + let git_dir = current_dir.join(".git"); + if git_dir.exists() && git_dir.is_dir() { + return Some(current_dir); + } + + if !current_dir.pop() { + break; + } + } + + None +} |
