diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-06-23 21:03:35 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-06-23 21:07:27 +0800 |
| commit | 96aa7e23766ffd038a43638ab0b60d04942f0430 (patch) | |
| tree | d123cd1a4b0da5472c897e8b0944f700b8dad161 /dev_tools/src | |
| parent | 270217d5e0e7de1d1cac5b634b1e9c54b197e0ce (diff) | |
Parallelize markdown code block verification
Diffstat (limited to 'dev_tools/src')
| -rw-r--r-- | dev_tools/src/bin/test-all-markdown-code.rs | 100 | ||||
| -rw-r--r-- | dev_tools/src/verify.rs | 4 |
2 files changed, 70 insertions, 34 deletions
diff --git a/dev_tools/src/bin/test-all-markdown-code.rs b/dev_tools/src/bin/test-all-markdown-code.rs index e43053e..31aebdd 100644 --- a/dev_tools/src/bin/test-all-markdown-code.rs +++ b/dev_tools/src/bin/test-all-markdown-code.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::env; +use std::io::Write; use std::path::{Path, PathBuf}; use colored::Colorize; @@ -24,7 +25,8 @@ struct VerifiedPaths { documents_zh_cn: Option<String>, } -fn main() { +#[tokio::main] +async fn main() { #[cfg(windows)] let _ = colored::control::set_virtual_terminal(true); @@ -158,40 +160,76 @@ fn main() { let temp_base = PathBuf::from(".temp/doc-test"); - // Build groups — same hash reuses the same Cargo.toml + // Sort groups by hash for deterministic output order + let mut group_vec: Vec<(String, Vec<(usize, tools::verify::CodeBlock)>)> = + groups.into_iter().collect(); + group_vec.sort_by(|a, b| a.0.cmp(&b.0)); + + // Spawn a blocking task per group — groups run in parallel, blocks within a group are serial + let mut handles = Vec::new(); + for (hash, blocks) in group_vec { + let temp_base = temp_base.clone(); + let handle = tokio::task::spawn_blocking(move || { + let crate_dir = temp_base.join(&hash); + let src_dir = crate_dir.join("src"); + let manifest_path = crate_dir.join("Cargo.toml"); + + // Buffer all output for this group so it prints contiguously + let mut output = String::new(); + + // Generate a single Cargo.toml for the whole group (all blocks share same deps) + let first_block = &blocks[0].1; + let cargo_toml = generate_cargo_toml(first_block, "test-doc", &manifest_path); + + let mut group_results: Vec<(String, usize, bool, String)> = Vec::new(); + for (block_idx, block) in &blocks { + let block_label = + format!("Block {block_idx} ({}:{})", block.source_file, block.line); + + let main_rs = generate_main_rs(block); + let (ok, err) = build_block(&src_dir, &manifest_path, &cargo_toml, &main_rs); + if ok { + output.push_str(&format!( + " Testing {block_label} ... {}\n", + "passed".bold().bright_green() + )); + } else { + output.push_str(&format!( + " Testing {block_label} ... {}\n", + "failed".bold().bright_red() + )); + output.push_str(&format!(" {block_label} FAILED:\n{err}\n")); + } + group_results.push((block.source_file.clone(), block.line, ok, err)); + } + (output, group_results) + }); + handles.push(handle); + } + + // Collect results from all groups let mut results: Vec<(String, usize, bool, String)> = Vec::new(); let mut passed = 0usize; let mut failed = 0usize; - // Sort groups by hash for deterministic output order - let mut group_keys: Vec<&String> = groups.keys().collect(); - group_keys.sort(); - - for hash in group_keys { - let blocks = &groups[hash]; - let crate_dir = temp_base.join(hash); - let src_dir = crate_dir.join("src"); - let manifest_path = crate_dir.join("Cargo.toml"); - - // Generate a single Cargo.toml for the whole group (all blocks share same deps) - let first_block = &blocks[0].1; - let cargo_toml = generate_cargo_toml(first_block, "test-doc", &manifest_path); - - for (block_idx, block) in blocks { - let block_label = format!("Block {block_idx} ({}:{})", block.source_file, block.line); - print!(" Testing {block_label} ... "); - - let main_rs = generate_main_rs(block); - let (ok, err) = build_block(&src_dir, &manifest_path, &cargo_toml, &main_rs); - if ok { - println!("{}", "passed".bold().bright_green()); - passed += 1; - results.push((block.source_file.clone(), block.line, true, String::new())); - } else { - println!("{}", "failed".bold().bright_red()); - failed += 1; - results.push((block.source_file.clone(), block.line, false, err.clone())); - eprintln_cargo_style!(format!(" {block_label} FAILED:\n{err}")); + for handle in handles { + match handle.await { + Ok((output, group_results)) => { + // Print entire group output at once, avoiding interleaving + print!("{output}"); + let _ = std::io::stdout().flush(); + for (file, line, ok, err) in group_results { + if ok { + passed += 1; + } else { + failed += 1; + } + results.push((file, line, ok, err)); + } + } + Err(e) => { + eprintln_cargo_style!("Task panicked: {}", e); + std::process::exit(1); } } } diff --git a/dev_tools/src/verify.rs b/dev_tools/src/verify.rs index 319a38a..06db1b2 100644 --- a/dev_tools/src/verify.rs +++ b/dev_tools/src/verify.rs @@ -1,4 +1,3 @@ -use std::io::Write; use std::path::Path; use crate::println_cargo_style; @@ -293,7 +292,7 @@ pub fn build_block( Err(e) => return (false, format!("spawn: {e}")), }; - // Read stderr while it streams + // Read stderr (buffered, not forwarded — groups print their own output contiguously) use std::io::BufRead; let stderr_handle = child.stderr.take().unwrap(); let reader = std::io::BufReader::new(stderr_handle); @@ -301,7 +300,6 @@ pub fn build_block( for line in reader.lines() { match line { Ok(l) => { - let _ = writeln!(std::io::stderr(), "{l}"); captured.push_str(&l); captured.push('\n'); } |
