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 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(); // 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"); writeln!(out_file, "// @generated").unwrap(); writeln!(out_file, "// Auto-generated by build.rs").unwrap(); writeln!(out_file, "pub static MIGRATIONS: &[(&str, &str)] = &[").unwrap(); for path in &files { let name = path.file_name().unwrap().to_string_lossy(); let rel_path = &path.to_str().unwrap().replace("\\", "/")[skip_path..]; // for Windows writeln!( out_file, " (\"{name}\", include_str!(r#\".{rel_path}\"#))," ) .unwrap(); } writeln!(out_file, "];").unwrap(); println!("cargo:rerun-if-changed={}", migration_path.display()); } } fn find_migrations_dirs(root: &Path) -> Vec { let mut found = Vec::new(); find_migrations_dirs_rec(root, &mut found); found } fn find_migrations_dirs_rec(dir: &Path, found: &mut Vec) { 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) -> 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(()) }