| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 | use std::cmp::Ordering;use std::fs::{self, File};use std::io::Write;use std::path::{Path, PathBuf};fn main() {    // Step 1: Find `migrations/` folder recursively    let root = Path::new("src");    for migration_path in find_migrations_dirs(root) {        // Step 3: Output file path (e.g., `src/db/migrations.rs`)        let parent = migration_path.parent().unwrap();        let skip_path = parent.to_str().unwrap_or_default().len();        let dest_path = parent.join("migrations.rs");        let mut out_file = File::create(&dest_path).expect("Failed to create migrations.rs");        let skip_name = migration_path.to_str().unwrap_or_default().len();        // Step 2: Collect all files inside the migrations dir        let mut files = Vec::new();        visit_dirs(&migration_path, &mut files).expect("Failed to read migrations directory");        files.sort_by(|path_a, path_b| {            let parts_a = path_a.to_str().unwrap().replace("\\", "/")[skip_name + 1..]                .split("/")                .map(|x| x.to_owned())                .collect::<Vec<_>>();            let parts_b = path_b.to_str().unwrap().replace("\\", "/")[skip_name + 1..]                .split("/")                .map(|x| x.to_owned())                .collect::<Vec<_>>();            let prefix_a = if parts_a.len() == 2 {                parts_a.first().map(|x| x.to_owned()).unwrap_or_default()            } else {                "".to_owned()            };            let prefix_b = if parts_a.len() == 2 {                parts_b.first().map(|x| x.to_owned()).unwrap_or_default()            } else {                "".to_owned()            };            let prefix_cmp = prefix_a.cmp(&prefix_b);            if prefix_cmp != Ordering::Equal {                return prefix_cmp;            }            let path_a = path_a.file_name().unwrap().to_str().unwrap();            let path_b = path_b.file_name().unwrap().to_str().unwrap();            let prefix_a = path_a                .split("_")                .next()                .and_then(|prefix| prefix.parse::<usize>().ok())                .unwrap_or_default();            let prefix_b = path_b                .split("_")                .next()                .and_then(|prefix| prefix.parse::<usize>().ok())                .unwrap_or_default();            if prefix_a != 0 && prefix_b != 0 {                prefix_a.cmp(&prefix_b)            } else {                path_a.cmp(path_b)            }        });        writeln!(out_file, "/// @generated").unwrap();        writeln!(out_file, "/// Auto-generated by build.rs").unwrap();        writeln!(            out_file,            "pub static MIGRATIONS: &[(&str, &str, &str)] = &["        )        .unwrap();        for path in &files {            let parts = path.to_str().unwrap().replace("\\", "/")[skip_name + 1..]                .split("/")                .map(|x| x.to_owned())                .collect::<Vec<_>>();            let prefix = if parts.len() == 2 {                parts.first().map(|x| x.to_owned()).unwrap_or_default()            } else {                "".to_owned()            };            let rel_name = &path.file_name().unwrap().to_str().unwrap();            let rel_path = &path.to_str().unwrap().replace("\\", "/")[skip_path..]; // for Windows            writeln!(                out_file,                "    (\"{prefix}\", \"{rel_name}\", include_str!(r#\".{rel_path}\"#)),"            )            .unwrap();            println!("cargo:rerun-if-changed={}", path.display());        }        writeln!(out_file, "];").unwrap();        println!("cargo:rerun-if-changed={}", migration_path.display());    }}fn find_migrations_dirs(root: &Path) -> Vec<PathBuf> {    let mut found = Vec::new();    find_migrations_dirs_rec(root, &mut found);    found}fn find_migrations_dirs_rec(dir: &Path, found: &mut Vec<PathBuf>) {    if let Ok(entries) = fs::read_dir(dir) {        for entry in entries.flatten() {            let path = entry.path();            if path.is_dir() {                if path.file_name().unwrap_or_default() == "migrations" {                    found.push(path.clone());                }                find_migrations_dirs_rec(&path, found);            }        }    }}fn visit_dirs(dir: &Path, files: &mut Vec<PathBuf>) -> std::io::Result<()> {    for entry in fs::read_dir(dir)? {        let entry = entry?;        let path = entry.path();        if path.is_dir() {            visit_dirs(&path, files)?;        } else if path.is_file() {            files.push(path);        }    }    Ok(())}
 |