use anyhow::{bail, Result};
use std::fs::{self, OpenOptions};
use std::io::Write;
use std::path::Path;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
use crate::loader::discover_migrations;
use crate::templates::{get_template, list_templates};
use crate::version::generate_version;
pub fn run(
project_root: &Path,
migrations_dir: &Path,
name: Option<&str>,
template_name: &str,
description: Option<&str>,
should_list_templates: bool,
) -> Result<()> {
if should_list_templates {
println!("Available templates:");
for template in list_templates() {
println!(" {}", template);
}
return Ok(());
}
let name = match name {
Some(n) => n,
None => bail!("Migration name is required. Usage: migrate create <name>"),
};
let template = match get_template(template_name) {
Some(t) => t,
None => {
bail!(
"Unknown template '{}'. Available: {}",
template_name,
list_templates().collect::<Vec<_>>().join(", ")
);
}
};
let migrations_path = if migrations_dir.is_absolute() {
migrations_dir.to_path_buf()
} else {
project_root.join(migrations_dir)
};
fs::create_dir_all(&migrations_path)?;
let version = generate_version();
let existing = discover_migrations(&migrations_path).unwrap_or_default();
if existing.iter().any(|m| m.version == version) {
bail!(
"A migration with version {} already exists. Wait a few minutes or use a different time slot.",
version
);
}
let filename = format!("{}-{}{}", version, name, template.extension);
let file_path = migrations_path.join(&filename);
if file_path.exists() {
bail!("Migration file already exists: {}", file_path.display());
}
let description_text = description.unwrap_or("TODO: Add description");
let content = template
.content
.replace("{{DESCRIPTION}}", description_text);
let mut file = OpenOptions::new()
.create(true)
.write(true)
.truncate(true)
.open(&file_path)?;
file.write_all(content.as_bytes())?;
#[cfg(unix)]
{
let mut perms = fs::metadata(&file_path)?.permissions();
perms.set_mode(0o755);
fs::set_permissions(&file_path, perms)?;
}
println!("Created migration: {}", file_path.display());
Ok(())
}