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
|
use std::path::Path;
use tools::{println_cargo_style, run_cmd};
const OUTPUT_DIR: &str = "docs/api-docs";
fn main() {
let repo_root = find_git_repo().expect("Failed to find git repository root");
// Read features from [package.metadata.docs.rs]
let features = tools::read_features().unwrap_or_else(|e| {
eprintln!("Error: {}", e);
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
}
|