use std::fs::{self, File};
use std::io::Write;
use std::path::{Path, PathBuf};
fn main() {
let root = Path::new("src");
for migration_path in find_migrations_dirs(root) {
let mut files = Vec::new();
visit_dirs(&migration_path, &mut files).expect("Failed to read migrations directory");
files.sort();
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();
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..]; 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(())
}