From ec9edc294fd5e7e29977fc7b0e6fb953422bc0e2 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Wed, 19 Aug 2026 05:54:00 +0800 Subject: chore: reorganize dev tools into dev/ directory and consolidate configs Move CI, dev tools, and configs from root-level scattered locations into a unified `dev/` directory structure. Update all references across build scripts, documentation, and editor configurations. Also consolidate editor config generation into build.rs for automated synchronization of rust-analyzer settings across VS Code and Zed. --- mingling_ci/src/task/cmd_markdown_compare.rs | 221 --------------------------- 1 file changed, 221 deletions(-) delete mode 100644 mingling_ci/src/task/cmd_markdown_compare.rs (limited to 'mingling_ci/src/task/cmd_markdown_compare.rs') diff --git a/mingling_ci/src/task/cmd_markdown_compare.rs b/mingling_ci/src/task/cmd_markdown_compare.rs deleted file mode 100644 index b014f1e..0000000 --- a/mingling_ci/src/task/cmd_markdown_compare.rs +++ /dev/null @@ -1,221 +0,0 @@ -use std::collections::BTreeSet; -use std::path::{Path, PathBuf}; - -use colored::Colorize; -use just_fmt::snake_case; -use mingling::{ - Grouped, Routable, - macros::{buffer, command, renderer}, - res::ResExitCode, -}; - -use crate::Next; -use crate::markdown::compare::{collect_md_files, compare_signature}; -use crate::reporter::{self, ReportResult}; -use crate::task::cmd_markdown_check::{ErrorMarkdownArgs, ErrorMarkdownConfig, stem_of}; - -const DOCS_DIR: &str = "./docs"; -const LANG_CONFIG: &str = ".config/docs-lang.txt"; - -/// One file-pair outcome of a structure comparison. -struct CompareOutcome { - item: String, - location: String, - ok: bool, - output: String, -} - -#[command(node = "markdown-compare")] -// `#[command]` rewrites an owned first param into the entry type, so the args -// must be passed by value even though the body only reads them. -#[allow(clippy::needless_pass_by_value)] -pub fn markdown_compare(args: Vec) -> Next { - let [ref_arg, trans_arg] = args.as_slice() else { - return ErrorMarkdownArgs("missing and arguments".to_string()) - .to_chain(); - }; - let ref_path = cwd().join(ref_arg); - let trans_path = cwd().join(trans_arg); - - reporter::set_task("Markdown-Compare"); - let outcomes = if ref_path.is_dir() && trans_path.is_dir() { - compare_dirs(&ref_path, &trans_path, "doc") - } else if ref_path.is_file() && trans_path.is_file() { - compare_files(&ref_path, &trans_path, "doc") - } else { - return ErrorMarkdownArgs( - "both arguments must be files or both must be directories".to_string(), - ) - .to_chain(); - }; - let fail_count = export_outcomes(&outcomes); - reporter::flush(); - - ResultMarkdownCompare { fail_count }.to_chain() -} - -#[command(node = "markdown-compare-all")] -pub fn markdown_compare_all() -> Next { - let Some(langs) = lang_config() else { - return ErrorMarkdownConfig.to_chain(); - }; - let Some(reference) = langs.first() else { - return ErrorMarkdownConfig.to_chain(); - }; - let ref_dir = PathBuf::from(DOCS_DIR).join(reference); - if !ref_dir.is_dir() { - return ErrorMarkdownArgs(format!( - "reference docs directory `{}` does not exist", - ref_dir.display() - )) - .to_chain(); - } - - reporter::set_task("Markdown-Compare-All"); - let mut fail_count = 0; - for lang in &langs[1..] { - let lang_dir = PathBuf::from(DOCS_DIR).join(lang); - if !lang_dir.is_dir() { - eprintln!( - " {}: `{}` does not exist", - "ERROR".bright_red(), - lang_dir.display() - ); - fail_count += 1; - continue; - } - let outcomes = compare_dirs(&ref_dir, &lang_dir, &lang_key(lang)); - fail_count += export_outcomes(&outcomes); - } - reporter::flush(); - - ResultMarkdownCompare { fail_count }.to_chain() -} - -/// Compares one file pair (reference vs translation). -fn compare_files(ref_path: &Path, trans_path: &Path, prefix: &str) -> Vec { - let item = format!("{prefix}-{}", snake_case!(&stem_of(ref_path))); - let location = trans_path.to_string_lossy().into_owned(); - match compare_signature(ref_path, trans_path) { - Ok(()) => vec![CompareOutcome { - item, - location, - ok: true, - output: String::new(), - }], - Err(diffs) => vec![CompareOutcome { - item, - location, - ok: false, - output: diffs.join("\n"), - }], - } -} - -/// Compares two directories: every `.md` file in the reference must exist in -/// the translation with the same structural signature; extra files are errors. -fn compare_dirs(ref_dir: &Path, trans_dir: &Path, prefix: &str) -> Vec { - let ref_files = collect_md_files(ref_dir); - let ref_set: BTreeSet = ref_files.iter().cloned().collect(); - let trans_set: BTreeSet = collect_md_files(trans_dir).into_iter().collect(); - - let mut outcomes = Vec::new(); - for file in ref_files { - let item = format!("{prefix}-{}", snake_case!(&stem_of(&file))); - let trans_path = trans_dir.join(&file); - let location = trans_path.to_string_lossy().into_owned(); - if !trans_set.contains(&file) { - outcomes.push(CompareOutcome { - item, - location, - ok: false, - output: "missing in translation".to_string(), - }); - continue; - } - outcomes.push(match compare_signature(&ref_dir.join(&file), &trans_path) { - Ok(()) => CompareOutcome { - item, - location, - ok: true, - output: String::new(), - }, - Err(diffs) => CompareOutcome { - item, - location, - ok: false, - output: diffs.join("\n"), - }, - }); - } - - for file in trans_set.difference(&ref_set) { - let item = format!("{prefix}-{}", snake_case!(&stem_of(file))); - let trans_path = trans_dir.join(file); - outcomes.push(CompareOutcome { - item, - location: trans_path.to_string_lossy().into_owned(), - ok: false, - output: "extra file, not in reference".to_string(), - }); - } - outcomes -} - -/// Exports the outcomes via `reporter`; failures also print to stderr. -fn export_outcomes(outcomes: &[CompareOutcome]) -> usize { - let mut fail_count = 0; - for outcome in outcomes { - if outcome.ok { - reporter::export(&outcome.item, &outcome.location, ReportResult::Ok); - } else { - fail_count += 1; - eprintln!(" {} {}", "failed".bright_red(), outcome.item); - eprintln!(" {}\n{}", outcome.location, outcome.output); - reporter::export( - &outcome.item, - &outcome.location, - ReportResult::Error(outcome.output.clone()), - ); - } - } - fail_count -} - -/// Reads `.config/docs-lang.txt`: the first line is the reference directory -/// (relative to `./docs/`), the rest are translations that must mirror it. -fn lang_config() -> Option> { - let content = std::fs::read_to_string(LANG_CONFIG).ok()?; - Some( - content - .lines() - .map(str::trim) - .filter(|l| !l.is_empty() && !l.starts_with('#')) - .map(|l| l.trim_start_matches("./").to_string()) - .collect(), - ) -} - -/// Turns a lang directory path into a report-item key, e.g. -/// `./_zh_CN/pages/` → `_zh_CN_pages`. -fn lang_key(lang: &str) -> String { - lang.trim_matches('/').replace('/', "_") -} - -fn cwd() -> PathBuf { - std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")) -} - -/// Number of files that failed the structure comparison. -#[derive(Grouped)] -pub struct ResultMarkdownCompare { - pub fail_count: usize, -} - -/// Silently sets a non-zero exit code when any comparison failed. -#[renderer(buffer)] -pub fn render_markdown_compare(r: ResultMarkdownCompare, exit_code: &mut ResExitCode) { - if r.fail_count > 0 { - exit_code.exit_code = 1; - } -} -- cgit