aboutsummaryrefslogtreecommitdiff
path: root/dev_tools
diff options
context:
space:
mode:
Diffstat (limited to 'dev_tools')
-rw-r--r--dev_tools/Cargo.lock25
-rw-r--r--dev_tools/Cargo.toml1
-rw-r--r--dev_tools/src/bin/ci.rs95
-rw-r--r--dev_tools/src/bin/docs-code-box-fix.rs13
-rw-r--r--dev_tools/src/bin/docsify-sidebar-gen.rs8
-rw-r--r--dev_tools/src/bin/refresh-docs.rs30
-rw-r--r--dev_tools/src/lib.rs102
7 files changed, 261 insertions, 13 deletions
diff --git a/dev_tools/Cargo.lock b/dev_tools/Cargo.lock
index 39a1521..7bcc602 100644
--- a/dev_tools/Cargo.lock
+++ b/dev_tools/Cargo.lock
@@ -3,6 +3,15 @@
version = 4
[[package]]
+name = "colored"
+version = "3.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
name = "just_fmt"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -21,6 +30,22 @@ dependencies = [
name = "tools"
version = "0.1.0"
dependencies = [
+ "colored",
"just_fmt",
"just_template",
]
+
+[[package]]
+name = "windows-link"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
+
+[[package]]
+name = "windows-sys"
+version = "0.61.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
+dependencies = [
+ "windows-link",
+]
diff --git a/dev_tools/Cargo.toml b/dev_tools/Cargo.toml
index a28b156..7abb157 100644
--- a/dev_tools/Cargo.toml
+++ b/dev_tools/Cargo.toml
@@ -6,3 +6,4 @@ edition = "2024"
[dependencies]
just_template = "0.1.3"
just_fmt = "0.1.2"
+colored = "3.1.1"
diff --git a/dev_tools/src/bin/ci.rs b/dev_tools/src/bin/ci.rs
new file mode 100644
index 0000000..d5a108e
--- /dev/null
+++ b/dev_tools/src/bin/ci.rs
@@ -0,0 +1,95 @@
+use std::process::exit;
+
+use tools::{cargo_tomls, eprintln_cargo_style, println_cargo_style, run_cmd};
+
+fn main() {
+ #[cfg(windows)]
+ let _ = colored::control::set_virtual_terminal(true);
+ println!("{}", include_str!("../../../docs/res/ci_banner.txt"));
+
+ let needs_commit_temp = !{ run_cmd!("git diff-index --quiet HEAD --").is_ok() };
+
+ if needs_commit_temp {
+ run_cmd!("git add .").unwrap();
+ run_cmd!("git commit -m \"CI Temp\"").unwrap();
+ }
+
+ if ci().is_ok() {
+ println_cargo_style!("Done: All check passed!")
+ }
+
+ let is_worktree_clean = run_cmd!("git diff-index --quiet HEAD --").is_ok();
+ if !is_worktree_clean {
+ eprintln_cargo_style!("Documents needs refresh!");
+ if needs_commit_temp {
+ run_cmd!("git restore .").unwrap();
+ run_cmd!("git reset --soft HEAD~1").unwrap();
+ }
+ exit(1)
+ }
+
+ if needs_commit_temp {
+ run_cmd!("git restore .").unwrap();
+ run_cmd!("git reset --soft HEAD~1").unwrap();
+ }
+}
+
+fn ci() -> Result<(), i32> {
+ build_all()?;
+ clippy_all()?;
+ test_all()?;
+ docs_refresh()?;
+
+ run_cmd!("git add --renormalize .")?;
+
+ Ok(())
+}
+
+fn build_all() -> Result<(), i32> {
+ let cargo_tomls = cargo_tomls();
+ for cargo_toml in cargo_tomls {
+ println_cargo_style!("Build: {}", cargo_toml.to_string_lossy());
+ run_cmd!(
+ "cargo check --manifest-path {}",
+ cargo_toml.to_string_lossy()
+ )?;
+ }
+
+ Ok(())
+}
+
+fn clippy_all() -> Result<(), i32> {
+ let cargo_tomls = cargo_tomls();
+ for cargo_toml in cargo_tomls {
+ println_cargo_style!("Clippy: {}", cargo_toml.to_string_lossy());
+ run_cmd!(
+ "cargo clippy --manifest-path {} -- -D warnings",
+ cargo_toml.to_string_lossy()
+ )?;
+ }
+
+ Ok(())
+}
+
+fn test_all() -> Result<(), i32> {
+ let cargo_tomls = cargo_tomls();
+ for cargo_toml in cargo_tomls {
+ println_cargo_style!("Testing: {}", cargo_toml.to_string_lossy());
+ run_cmd!(
+ "cargo test --manifest-path {}",
+ cargo_toml.to_string_lossy()
+ )?;
+ }
+
+ Ok(())
+}
+
+fn docs_refresh() -> Result<(), i32> {
+ println_cargo_style!("Refresh: document at `./docs/`");
+
+ run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin docs-code-box-fix")?;
+ run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin docsify-sidebar-gen")?;
+ run_cmd!("cargo run --manifest-path dev_tools/Cargo.toml --bin refresh-docs")?;
+
+ Ok(())
+}
diff --git a/dev_tools/src/bin/docs-code-box-fix.rs b/dev_tools/src/bin/docs-code-box-fix.rs
index db97592..21d2cce 100644
--- a/dev_tools/src/bin/docs-code-box-fix.rs
+++ b/dev_tools/src/bin/docs-code-box-fix.rs
@@ -1,6 +1,8 @@
use std::fs;
use std::path::Path;
+use tools::println_cargo_style;
+
/// Docsify code blocks require that blank lines before and after code blocks are not completely empty,
/// but must contain at least one space, otherwise code block rendering will have issues.
///
@@ -9,7 +11,7 @@ use std::path::Path;
const DOCS_DIR: &str = "./docs";
fn main() {
- println!("Fixing code box empty lines in docs/**/*.md ...");
+ println_cargo_style!("Fixing: code box empty lines in docs/**/*.md ...");
let repo_root = find_git_repo().expect("Cannot find git repo root");
let docs_dir = repo_root.join(DOCS_DIR);
@@ -32,15 +34,16 @@ fn main() {
let new_content = fix_code_box_empty_lines(&content);
if new_content != content {
fs::write(path, &new_content).unwrap();
- println!(" Fixed: {}", path.display());
+ println_cargo_style!("Fixed: {}", path.display());
fixed_count += 1;
}
file_count += 1;
});
- println!(
- "Done. Scanned {} files, fixed {} files.",
- file_count, fixed_count
+ println_cargo_style!(
+ "Done: Scanned {} files, fixed {} files.",
+ file_count,
+ fixed_count
);
}
diff --git a/dev_tools/src/bin/docsify-sidebar-gen.rs b/dev_tools/src/bin/docsify-sidebar-gen.rs
index ed9e9f0..e0f9370 100644
--- a/dev_tools/src/bin/docsify-sidebar-gen.rs
+++ b/dev_tools/src/bin/docsify-sidebar-gen.rs
@@ -1,13 +1,15 @@
use std::collections::BTreeMap;
use std::path::Path;
+use tools::println_cargo_style;
+
const PAGES_ROOT: &str = "./docs/pages";
const SIDEBAR_PATH: &str = "./docs/_sidebar.md";
const SIDEBAR_HEAD: &str = "- [Welcome!](README)\n";
fn main() {
- println!("Refreshing _sidebar.md");
+ println_cargo_style!("Refresh: _sidebar.md");
gen_sidebar();
gen_translation_sidebars();
}
@@ -21,7 +23,7 @@ fn gen_sidebar() {
let sidebar_path = repo_root.join(SIDEBAR_PATH);
std::fs::write(&sidebar_path, lines).unwrap();
- println!(" Generated: {}", sidebar_path.display());
+ println_cargo_style!("Generated: {}", sidebar_path.display());
}
/// Generate _sidebar.md inside translation directories
@@ -48,7 +50,7 @@ fn gen_translation_sidebars() {
let sidebar_path = path.join("_sidebar.md");
std::fs::write(&sidebar_path, lines).unwrap();
- println!(" Generated: {}", sidebar_path.display());
+ println_cargo_style!("Generated: {}", sidebar_path.display());
}
}
}
diff --git a/dev_tools/src/bin/refresh-docs.rs b/dev_tools/src/bin/refresh-docs.rs
index 32821ed..ffa80a2 100644
--- a/dev_tools/src/bin/refresh-docs.rs
+++ b/dev_tools/src/bin/refresh-docs.rs
@@ -2,6 +2,7 @@ use std::path::Path;
use just_fmt::snake_case;
use just_template::{Template, tmpl};
+use tools::println_cargo_style;
const EXAMPLE_ROOT: &str = "./examples/";
const OUTPUT_PATH: &str = "./mingling/src/example_docs.rs";
@@ -9,10 +10,7 @@ const OUTPUT_PATH: &str = "./mingling/src/example_docs.rs";
const TEMPLATE_CONTENT: &str = include_str!("../../../mingling/src/example_docs.rs.tmpl");
fn main() {
- {
- println!("Refreshing Examples");
- gen_example_doc_module();
- }
+ gen_example_doc_module();
}
fn gen_example_doc_module() {
@@ -32,6 +30,8 @@ fn gen_example_doc_module() {
}
}
+ examples.sort();
+
for example in examples {
tmpl!(template += {
examples {
@@ -43,7 +43,7 @@ fn gen_example_doc_module() {
)
}
});
- println!(" Refresh: {}", example.name);
+ println_cargo_style!("Refresh: {}", example.name);
}
let template_str = template.to_string();
@@ -63,6 +63,26 @@ struct ExampleContent {
cargo_toml: String,
}
+impl PartialOrd for ExampleContent {
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for ExampleContent {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.name.cmp(&other.name)
+ }
+}
+
+impl PartialEq for ExampleContent {
+ fn eq(&self, other: &Self) -> bool {
+ self.name == other.name
+ }
+}
+
+impl Eq for ExampleContent {}
+
impl ExampleContent {
pub fn read(name: &str) -> Self {
let repo = find_git_repo().unwrap();
diff --git a/dev_tools/src/lib.rs b/dev_tools/src/lib.rs
index 8b13789..1b5dd0f 100644
--- a/dev_tools/src/lib.rs
+++ b/dev_tools/src/lib.rs
@@ -1 +1,103 @@
+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)
+ };
+}
+
+#[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)
+ };
+}
+
+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 {
+ ("".to_string(), s.trim().to_string())
+ };
+
+ if prefix.len() > 12 {
+ panic!(
+ "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());
+}
+
+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)
+ }
+}
+
+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() {
+ dirs.push(path);
+ } else if path.file_name().and_then(|n| n.to_str()) == Some("Cargo.toml") {
+ cargo_tomls.push(path);
+ }
+ }
+ }
+ }
+ cargo_tomls
+}