aboutsummaryrefslogtreecommitdiff
path: root/dev_tools/src/lib.rs
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-07-10 16:54:57 +0800
committer魏曹先生 <1992414357@qq.com>2026-07-10 16:54:57 +0800
commit5d258482fb84d58c966a7ccc1b467708278d28ad (patch)
tree1a0c9d2e245d43ff7bc11d9088cf88a5264d293f /dev_tools/src/lib.rs
parenta8c8d50b6c59b103da7fd4bbb5e7ca3ff7b2f49a (diff)
refactor(devtools): rename dev_tools to .run and replace run-tools
scripts Replace the old run-tools.ps1/run-tools.sh scripts with a new unified run.ps1/run.sh launcher that supports multiple languages (PowerShell, Rust, Python, Go, C#, Nim, Perl, Ruby, Zig, and arbitrary binaries) from the `.run/src/bin` directory. Move all development tools from `dev_tools/` to `.run/`, update Cargo workspace config and relevant documentation references.
Diffstat (limited to 'dev_tools/src/lib.rs')
-rw-r--r--dev_tools/src/lib.rs331
1 files changed, 0 insertions, 331 deletions
diff --git a/dev_tools/src/lib.rs b/dev_tools/src/lib.rs
deleted file mode 100644
index d38a156..0000000
--- a/dev_tools/src/lib.rs
+++ /dev/null
@@ -1,331 +0,0 @@
-pub mod verify;
-
-use colored::Colorize;
-
-#[macro_export]
-macro_rules! run_cmd {
- ($fmt:literal, $($arg:tt)*) => {
- $crate::run_cmd(format!($fmt, $($arg)*))
- };
- ($cmd:expr) => {
- $crate::run_cmd($cmd)
- };
-}
-
-/// Run a shell command and capture its combined stdout+stderr output.
-/// Returns `Ok(output)` on success, `Err((exit_code, stderr))` on failure.
-#[macro_export]
-macro_rules! run_cmd_and_capture_stderr {
- ($fmt:literal, $($arg:tt)*) => {
- $crate::run_cmd_capture(format!($fmt, $($arg)*))
- };
- ($cmd:expr) => {
- $crate::run_cmd_capture($cmd)
- };
-}
-
-#[macro_export]
-macro_rules! println_cargo_style {
- ($fmt:literal, $($arg:tt)*) => {
- $crate::println_cargo_style(format!($fmt, $($arg)*))
- };
- ($cmd:expr) => {
- $crate::println_cargo_style($cmd)
- };
-}
-
-#[macro_export]
-macro_rules! eprintln_cargo_style {
- ($fmt:literal, $($arg:tt)*) => {
- $crate::eprintln_cargo_style(format!($fmt, $($arg)*))
- };
- ($cmd:expr) => {
- $crate::eprintln_cargo_style($cmd)
- };
-}
-
-#[macro_export]
-macro_rules! wprintln_cargo_style {
- ($fmt:literal, $($arg:tt)*) => {
- $crate::wprintln_cargo_style(format!($fmt, $($arg)*))
- };
- ($cmd:expr) => {
- $crate::wprintln_cargo_style($cmd)
- };
-}
-
-/// Print a message in cargo style format, with bold green prefix.
-///
-/// # Panics
-///
-/// Panics if the prefix (text before the first `:`) exceeds 12 characters.
-pub fn println_cargo_style(str: impl Into<String>) {
- let s = str.into();
- let (prefix, content) = if let Some(pos) = s.find(':') {
- (
- s[..pos].trim().to_string(),
- s[pos + 1..].trim_start().to_string(),
- )
- } else {
- (String::new(), s.trim().to_string())
- };
-
- assert!(
- prefix.len() <= 12,
- "prefix length exceeds 12: '{}' has length {}",
- prefix,
- prefix.len()
- );
-
- let padding = " ".repeat(12 - prefix.len());
-
- println!(
- "{}{} {}",
- padding,
- prefix.bold().bright_green(),
- content.trim()
- );
-}
-
-pub fn eprintln_cargo_style(str: impl Into<String>) {
- println!("{}: {}", "error".bold().bright_red(), str.into());
-}
-
-/// Print a message in cargo style format, with bold yellow prefix (warning style).
-///
-/// # Panics
-///
-/// Panics if the prefix (text before the first `:`) exceeds 12 characters.
-pub fn wprintln_cargo_style(str: impl Into<String>) {
- let s = str.into();
- let (prefix, content) = if let Some(pos) = s.find(':') {
- (
- s[..pos].trim().to_string(),
- s[pos + 1..].trim_start().to_string(),
- )
- } else {
- (String::new(), s.trim().to_string())
- };
-
- assert!(
- prefix.len() <= 12,
- "prefix length exceeds 12: '{}' has length {}",
- prefix,
- prefix.len()
- );
-
- let padding = " ".repeat(12 - prefix.len());
-
- println!(
- "{}{} {}",
- padding,
- prefix.bold().bright_yellow(),
- content.trim()
- );
-}
-
-/// Run a shell command and return its exit status.
-///
-/// # Panics
-///
-/// Panics if the shell command cannot be spawned (e.g. the shell binary is not found).
-///
-/// # Errors
-///
-/// Returns `Err` with the exit code if the command finishes with a non-zero exit code.
-pub fn run_cmd(cmd: impl Into<String>) -> Result<(), i32> {
- let shell = if cfg!(target_os = "windows") {
- "powershell"
- } else {
- "sh"
- };
- let status = std::process::Command::new(shell)
- .arg("-c")
- .arg(cmd.into())
- .current_dir(std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")))
- .status()
- .expect("failed to execute command");
-
- let exit_code = status.code().unwrap_or(1);
- if exit_code == 0 {
- Ok(())
- } else {
- Err(exit_code)
- }
-}
-
-/// Run a shell command and capture its combined stdout+stderr output.
-///
-/// On success returns `Ok(combined_output)`. On failure returns `Err((exit_code, stderr))`.
-/// Stderr falls back to stdout if stderr is empty.
-pub fn run_cmd_capture(cmd: impl Into<String>) -> Result<String, (i32, String)> {
- let shell = if cfg!(target_os = "windows") {
- "powershell"
- } else {
- "sh"
- };
- let output = std::process::Command::new(shell)
- .arg("-c")
- .arg(cmd.into())
- .current_dir(std::env::current_dir().unwrap_or_else(|_| std::path::PathBuf::from(".")))
- .output()
- .expect("failed to execute command");
-
- let exit_code = output.status.code().unwrap_or(1);
- let stderr = String::from_utf8_lossy(&output.stderr).to_string();
- let stdout = String::from_utf8_lossy(&output.stdout).to_string();
- let combined = if stderr.is_empty() { stdout } else { stderr };
-
- if exit_code == 0 {
- Ok(combined)
- } else {
- Err((exit_code, combined))
- }
-}
-
-/// Extract a crate-style name from a `Cargo.toml` path.
-///
-/// Examples:
-/// - `mingling_core/Cargo.toml` → `mingling_core`
-/// - `.` → `(root)`
-pub fn crate_name_from(path: &std::path::Path) -> String {
- path.parent()
- .and_then(|p| p.file_name())
- .and_then(|n| n.to_str())
- .unwrap_or("(root)")
- .to_string()
-}
-
-/// Run a list of `(label_for_errors, crate_name_for_bar, shell_command)` tuples
-/// in parallel with a progress bar.
-///
-/// - Success: silent, the bar tracks progress:
-/// ` Building [============================] 32/32: mingling_core`
-/// - Failure: `pb.println()` prints the error immediately above the bar.
-pub fn run_parallel(phase: &str, tasks: Vec<(String, String, String)>) -> Result<(), i32> {
- let n = tasks.len();
- if n == 0 {
- return Ok(());
- }
-
- // Cargo-style prefix: right-aligned to 12 chars, bold bright cyan
- let padding = " ".repeat(12 - phase.len());
- let styled_prefix = format!("{}{}", padding, phase.bold().bright_cyan());
-
- let pb = indicatif::ProgressBar::new(n as u64);
- pb.set_style(
- indicatif::ProgressStyle::default_bar()
- .template(&format!(
- "{} [{{bar:28}}] {{pos}}/{{len}}: {{msg}}",
- styled_prefix
- ))
- .unwrap()
- .progress_chars("=> "),
- );
- pb.set_position(0);
-
- // Pre-extract labels for error messages
- let labels: Vec<String> = tasks.iter().map(|(l, _, _)| l.clone()).collect();
-
- let (tx, rx) = std::sync::mpsc::channel::<(usize, String, Result<String, (i32, String)>)>();
-
- for (i, (_label, crate_name, cmd)) in tasks.into_iter().enumerate() {
- let tx = tx.clone();
- std::thread::spawn(move || {
- let result = run_cmd_capture(&cmd);
- let _ = tx.send((i, crate_name, result));
- });
- }
- drop(tx);
-
- let mut first_exit_code = 0;
-
- while let Ok((i, crate_name, result)) = rx.recv() {
- pb.inc(1);
- pb.set_message(crate_name);
-
- if let Err((code, output)) = result {
- if first_exit_code == 0 {
- first_exit_code = code;
- }
- pb.println(format!(
- "{}: {} failed (exit code {})",
- "error".bright_red().bold(),
- labels[i],
- code,
- ));
- if !output.is_empty() {
- for line in output.lines() {
- pb.println(format!(" {line}"));
- }
- }
- }
- }
-
- pb.finish_and_clear();
-
- if first_exit_code != 0 {
- Err(first_exit_code)
- } else {
- Ok(())
- }
-}
-
-/// Run a single shell command with a progress bar, capturing its output.
-///
-/// - Success: bar clears silently.
-/// - Failure: error is printed above the bar, then the bar clears.
-pub fn run_cmd_with_progress(phase: &str, label: &str, cmd: String) -> Result<(), i32> {
- let padding = " ".repeat(12 - phase.len());
- let styled_prefix = format!("{}{}", padding, phase.bold().bright_cyan());
-
- let pb = indicatif::ProgressBar::new(1);
- pb.set_style(
- indicatif::ProgressStyle::default_bar()
- .template(&format!(
- "{} [{{bar:28}}] {{pos}}/{{len}}: {{msg}}",
- styled_prefix
- ))
- .unwrap()
- .progress_chars("=> "),
- );
- pb.set_message(label.to_owned());
-
- let result = run_cmd_capture(&cmd);
- pb.inc(1);
- pb.finish_and_clear();
-
- match result {
- Ok(_) => Ok(()),
- Err((code, output)) => {
- eprintln_cargo_style(format!("{} failed (exit code {})", label, code));
- if !output.is_empty() {
- println!("{}", output.trim_end());
- }
- Err(code)
- }
- }
-}
-
-#[must_use]
-pub fn cargo_tomls() -> Vec<std::path::PathBuf> {
- let mut cargo_tomls = Vec::new();
- let mut dirs = vec![std::path::PathBuf::from(".")];
- while let Some(dir) = dirs.pop() {
- if let Ok(entries) = std::fs::read_dir(&dir) {
- for entry in entries.flatten() {
- let path = entry.path();
- if path.is_dir() {
- // Skip the dev_tools directory
- if path.file_name().and_then(|n| n.to_str()) == Some("dev_tools") {
- continue;
- }
- dirs.push(path);
- } else if path.file_name().and_then(|n| n.to_str()) == Some("Cargo.toml") {
- cargo_tomls.push(path);
- }
- }
- }
- }
- cargo_tomls
-}