mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-19 05:35:18 +01:00
- write generated migration files to OUT_DIR instead of source directory - copy migration SQL files to OUT_DIR for inclusion in build artifacts - use absolute paths from OUT_DIR in include_str! macros - update consumer modules to include from OUT_DIR using concat! macro these changes enable cdk to support nix sandbox builds
163 lines
5.5 KiB
Rust
163 lines
5.5 KiB
Rust
use std::cmp::Ordering;
|
|
use std::env;
|
|
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");
|
|
|
|
// Get the OUT_DIR from Cargo - this is writable
|
|
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR is set by Cargo"));
|
|
|
|
for migration_path in find_migrations_dirs(root) {
|
|
// Step 3: Output file path to OUT_DIR instead of source directory
|
|
let parent = migration_path.parent().unwrap();
|
|
|
|
// Create a unique filename based on the migration path to avoid conflicts
|
|
let migration_name = parent
|
|
.strip_prefix("src")
|
|
.unwrap_or(parent)
|
|
.to_str()
|
|
.unwrap_or("default")
|
|
.replace("/", "_")
|
|
.replace("\\", "_");
|
|
let dest_path = out_dir.join(format!("migrations_{}.rs", migration_name));
|
|
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();
|
|
|
|
// Copy migration file to OUT_DIR
|
|
let relative_path = path.strip_prefix(root).unwrap();
|
|
let dest_migration_file = out_dir.join(relative_path);
|
|
if let Some(parent) = dest_migration_file.parent() {
|
|
fs::create_dir_all(parent)
|
|
.expect("Failed to create migration directory in OUT_DIR");
|
|
}
|
|
fs::copy(path, &dest_migration_file).expect("Failed to copy migration file to OUT_DIR");
|
|
|
|
// Use path relative to OUT_DIR for include_str
|
|
let relative_to_out_dir = relative_path.to_str().unwrap().replace("\\", "/");
|
|
writeln!(
|
|
out_file,
|
|
" (\"{prefix}\", \"{rel_name}\", include_str!(r#\"{}\"#)),",
|
|
relative_to_out_dir
|
|
)
|
|
.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(())
|
|
}
|